Merge branch 'ps/pack-refs-auto' into jt/reftable-geometric-compaction
* ps/pack-refs-auto: builtin/gc: pack refs when using `git maintenance run --auto` builtin/gc: forward git-gc(1)'s `--auto` flag when packing refs t6500: extract objects with "17" prefix builtin/gc: move `struct maintenance_run_opts` builtin/pack-refs: introduce new "--auto" flag builtin/pack-refs: release allocated memory refs/reftable: expose auto compaction via new flag refs: remove `PACK_REFS_ALL` flag refs: move `struct pack_refs_opts` to where it's used t/helper: drop pack-refs wrapper refs/reftable: print errors on compaction failure reftable/stack: gracefully handle failed auto-compaction due to locks reftable/stack: use error codes when locking fails during compaction reftable/error: discern locked/outdated errors reftable/stack: fix error handling in `reftable_stack_init_addition()`maint
commit
7424fb7797
|
@ -8,7 +8,7 @@ git-pack-refs - Pack heads and tags for efficient repository access
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
[verse]
|
[verse]
|
||||||
'git pack-refs' [--all] [--no-prune] [--include <pattern>] [--exclude <pattern>]
|
'git pack-refs' [--all] [--no-prune] [--auto] [--include <pattern>] [--exclude <pattern>]
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
|
@ -60,6 +60,19 @@ with many branches of historical interests.
|
||||||
The command usually removes loose refs under `$GIT_DIR/refs`
|
The command usually removes loose refs under `$GIT_DIR/refs`
|
||||||
hierarchy after packing them. This option tells it not to.
|
hierarchy after packing them. This option tells it not to.
|
||||||
|
|
||||||
|
--auto::
|
||||||
|
|
||||||
|
Pack refs as needed depending on the current state of the ref database. The
|
||||||
|
behavior depends on the ref format used by the repository and may change in the
|
||||||
|
future.
|
||||||
|
+
|
||||||
|
- "files": No special handling for `--auto` has been implemented.
|
||||||
|
+
|
||||||
|
- "reftable": Tables are compacted such that they form a geometric
|
||||||
|
sequence. For two tables N and N+1, where N+1 is newer, this
|
||||||
|
maintains the property that N is at least twice as big as N+1. Only
|
||||||
|
tables that violate this property are compacted.
|
||||||
|
|
||||||
--include <pattern>::
|
--include <pattern>::
|
||||||
|
|
||||||
Pack refs based on a `glob(7)` pattern. Repetitions of this option
|
Pack refs based on a `glob(7)` pattern. Repetitions of this option
|
||||||
|
|
86
builtin/gc.c
86
builtin/gc.c
|
@ -180,13 +180,51 @@ static void gc_config(void)
|
||||||
git_config(git_default_config, NULL);
|
git_config(git_default_config, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct maintenance_run_opts;
|
enum schedule_priority {
|
||||||
|
SCHEDULE_NONE = 0,
|
||||||
|
SCHEDULE_WEEKLY = 1,
|
||||||
|
SCHEDULE_DAILY = 2,
|
||||||
|
SCHEDULE_HOURLY = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
static enum schedule_priority parse_schedule(const char *value)
|
||||||
|
{
|
||||||
|
if (!value)
|
||||||
|
return SCHEDULE_NONE;
|
||||||
|
if (!strcasecmp(value, "hourly"))
|
||||||
|
return SCHEDULE_HOURLY;
|
||||||
|
if (!strcasecmp(value, "daily"))
|
||||||
|
return SCHEDULE_DAILY;
|
||||||
|
if (!strcasecmp(value, "weekly"))
|
||||||
|
return SCHEDULE_WEEKLY;
|
||||||
|
return SCHEDULE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct maintenance_run_opts {
|
||||||
|
int auto_flag;
|
||||||
|
int quiet;
|
||||||
|
enum schedule_priority schedule;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int pack_refs_condition(void)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* The auto-repacking logic for refs is handled by the ref backends and
|
||||||
|
* exposed via `git pack-refs --auto`. We thus always return truish
|
||||||
|
* here and let the backend decide for us.
|
||||||
|
*/
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int maintenance_task_pack_refs(MAYBE_UNUSED struct maintenance_run_opts *opts)
|
static int maintenance_task_pack_refs(MAYBE_UNUSED struct maintenance_run_opts *opts)
|
||||||
{
|
{
|
||||||
struct child_process cmd = CHILD_PROCESS_INIT;
|
struct child_process cmd = CHILD_PROCESS_INIT;
|
||||||
|
|
||||||
cmd.git_cmd = 1;
|
cmd.git_cmd = 1;
|
||||||
strvec_pushl(&cmd.args, "pack-refs", "--all", "--prune", NULL);
|
strvec_pushl(&cmd.args, "pack-refs", "--all", "--prune", NULL);
|
||||||
|
if (opts->auto_flag)
|
||||||
|
strvec_push(&cmd.args, "--auto");
|
||||||
|
|
||||||
return run_command(&cmd);
|
return run_command(&cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -547,7 +585,7 @@ done:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gc_before_repack(void)
|
static void gc_before_repack(struct maintenance_run_opts *opts)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* We may be called twice, as both the pre- and
|
* We may be called twice, as both the pre- and
|
||||||
|
@ -558,7 +596,7 @@ static void gc_before_repack(void)
|
||||||
if (done++)
|
if (done++)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (pack_refs && maintenance_task_pack_refs(NULL))
|
if (pack_refs && maintenance_task_pack_refs(opts))
|
||||||
die(FAILED_RUN, "pack-refs");
|
die(FAILED_RUN, "pack-refs");
|
||||||
|
|
||||||
if (prune_reflogs) {
|
if (prune_reflogs) {
|
||||||
|
@ -574,7 +612,6 @@ static void gc_before_repack(void)
|
||||||
int cmd_gc(int argc, const char **argv, const char *prefix)
|
int cmd_gc(int argc, const char **argv, const char *prefix)
|
||||||
{
|
{
|
||||||
int aggressive = 0;
|
int aggressive = 0;
|
||||||
int auto_gc = 0;
|
|
||||||
int quiet = 0;
|
int quiet = 0;
|
||||||
int force = 0;
|
int force = 0;
|
||||||
const char *name;
|
const char *name;
|
||||||
|
@ -583,6 +620,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
|
||||||
int keep_largest_pack = -1;
|
int keep_largest_pack = -1;
|
||||||
timestamp_t dummy;
|
timestamp_t dummy;
|
||||||
struct child_process rerere_cmd = CHILD_PROCESS_INIT;
|
struct child_process rerere_cmd = CHILD_PROCESS_INIT;
|
||||||
|
struct maintenance_run_opts opts = {0};
|
||||||
|
|
||||||
struct option builtin_gc_options[] = {
|
struct option builtin_gc_options[] = {
|
||||||
OPT__QUIET(&quiet, N_("suppress progress reporting")),
|
OPT__QUIET(&quiet, N_("suppress progress reporting")),
|
||||||
|
@ -593,7 +631,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
|
||||||
OPT_MAGNITUDE(0, "max-cruft-size", &max_cruft_size,
|
OPT_MAGNITUDE(0, "max-cruft-size", &max_cruft_size,
|
||||||
N_("with --cruft, limit the size of new cruft packs")),
|
N_("with --cruft, limit the size of new cruft packs")),
|
||||||
OPT_BOOL(0, "aggressive", &aggressive, N_("be more thorough (increased runtime)")),
|
OPT_BOOL(0, "aggressive", &aggressive, N_("be more thorough (increased runtime)")),
|
||||||
OPT_BOOL_F(0, "auto", &auto_gc, N_("enable auto-gc mode"),
|
OPT_BOOL_F(0, "auto", &opts.auto_flag, N_("enable auto-gc mode"),
|
||||||
PARSE_OPT_NOCOMPLETE),
|
PARSE_OPT_NOCOMPLETE),
|
||||||
OPT_BOOL_F(0, "force", &force,
|
OPT_BOOL_F(0, "force", &force,
|
||||||
N_("force running gc even if there may be another gc running"),
|
N_("force running gc even if there may be another gc running"),
|
||||||
|
@ -638,7 +676,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
|
||||||
if (quiet)
|
if (quiet)
|
||||||
strvec_push(&repack, "-q");
|
strvec_push(&repack, "-q");
|
||||||
|
|
||||||
if (auto_gc) {
|
if (opts.auto_flag) {
|
||||||
/*
|
/*
|
||||||
* Auto-gc should be least intrusive as possible.
|
* Auto-gc should be least intrusive as possible.
|
||||||
*/
|
*/
|
||||||
|
@ -663,7 +701,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
|
||||||
|
|
||||||
if (lock_repo_for_gc(force, &pid))
|
if (lock_repo_for_gc(force, &pid))
|
||||||
return 0;
|
return 0;
|
||||||
gc_before_repack(); /* dies on failure */
|
gc_before_repack(&opts); /* dies on failure */
|
||||||
delete_tempfile(&pidfile);
|
delete_tempfile(&pidfile);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -688,7 +726,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
|
||||||
|
|
||||||
name = lock_repo_for_gc(force, &pid);
|
name = lock_repo_for_gc(force, &pid);
|
||||||
if (name) {
|
if (name) {
|
||||||
if (auto_gc)
|
if (opts.auto_flag)
|
||||||
return 0; /* be quiet on --auto */
|
return 0; /* be quiet on --auto */
|
||||||
die(_("gc is already running on machine '%s' pid %"PRIuMAX" (use --force if not)"),
|
die(_("gc is already running on machine '%s' pid %"PRIuMAX" (use --force if not)"),
|
||||||
name, (uintmax_t)pid);
|
name, (uintmax_t)pid);
|
||||||
|
@ -703,7 +741,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
|
||||||
atexit(process_log_file_at_exit);
|
atexit(process_log_file_at_exit);
|
||||||
}
|
}
|
||||||
|
|
||||||
gc_before_repack();
|
gc_before_repack(&opts);
|
||||||
|
|
||||||
if (!repository_format_precious_objects) {
|
if (!repository_format_precious_objects) {
|
||||||
struct child_process repack_cmd = CHILD_PROCESS_INIT;
|
struct child_process repack_cmd = CHILD_PROCESS_INIT;
|
||||||
|
@ -758,7 +796,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
|
||||||
!quiet && !daemonized ? COMMIT_GRAPH_WRITE_PROGRESS : 0,
|
!quiet && !daemonized ? COMMIT_GRAPH_WRITE_PROGRESS : 0,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
if (auto_gc && too_many_loose_objects())
|
if (opts.auto_flag && too_many_loose_objects())
|
||||||
warning(_("There are too many unreachable loose objects; "
|
warning(_("There are too many unreachable loose objects; "
|
||||||
"run 'git prune' to remove them."));
|
"run 'git prune' to remove them."));
|
||||||
|
|
||||||
|
@ -773,26 +811,6 @@ static const char *const builtin_maintenance_run_usage[] = {
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
enum schedule_priority {
|
|
||||||
SCHEDULE_NONE = 0,
|
|
||||||
SCHEDULE_WEEKLY = 1,
|
|
||||||
SCHEDULE_DAILY = 2,
|
|
||||||
SCHEDULE_HOURLY = 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
static enum schedule_priority parse_schedule(const char *value)
|
|
||||||
{
|
|
||||||
if (!value)
|
|
||||||
return SCHEDULE_NONE;
|
|
||||||
if (!strcasecmp(value, "hourly"))
|
|
||||||
return SCHEDULE_HOURLY;
|
|
||||||
if (!strcasecmp(value, "daily"))
|
|
||||||
return SCHEDULE_DAILY;
|
|
||||||
if (!strcasecmp(value, "weekly"))
|
|
||||||
return SCHEDULE_WEEKLY;
|
|
||||||
return SCHEDULE_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int maintenance_opt_schedule(const struct option *opt, const char *arg,
|
static int maintenance_opt_schedule(const struct option *opt, const char *arg,
|
||||||
int unset)
|
int unset)
|
||||||
{
|
{
|
||||||
|
@ -809,12 +827,6 @@ static int maintenance_opt_schedule(const struct option *opt, const char *arg,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct maintenance_run_opts {
|
|
||||||
int auto_flag;
|
|
||||||
int quiet;
|
|
||||||
enum schedule_priority schedule;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Remember to update object flag allocation in object.h */
|
/* Remember to update object flag allocation in object.h */
|
||||||
#define SEEN (1u<<0)
|
#define SEEN (1u<<0)
|
||||||
|
|
||||||
|
@ -1296,7 +1308,7 @@ static struct maintenance_task tasks[] = {
|
||||||
[TASK_PACK_REFS] = {
|
[TASK_PACK_REFS] = {
|
||||||
"pack-refs",
|
"pack-refs",
|
||||||
maintenance_task_pack_refs,
|
maintenance_task_pack_refs,
|
||||||
NULL,
|
pack_refs_condition,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -7,24 +7,28 @@
|
||||||
#include "revision.h"
|
#include "revision.h"
|
||||||
|
|
||||||
static char const * const pack_refs_usage[] = {
|
static char const * const pack_refs_usage[] = {
|
||||||
N_("git pack-refs [--all] [--no-prune] [--include <pattern>] [--exclude <pattern>]"),
|
N_("git pack-refs [--all] [--no-prune] [--auto] [--include <pattern>] [--exclude <pattern>]"),
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
int cmd_pack_refs(int argc, const char **argv, const char *prefix)
|
int cmd_pack_refs(int argc, const char **argv, const char *prefix)
|
||||||
{
|
{
|
||||||
unsigned int flags = PACK_REFS_PRUNE;
|
struct ref_exclusions excludes = REF_EXCLUSIONS_INIT;
|
||||||
static struct ref_exclusions excludes = REF_EXCLUSIONS_INIT;
|
struct string_list included_refs = STRING_LIST_INIT_NODUP;
|
||||||
static struct string_list included_refs = STRING_LIST_INIT_NODUP;
|
struct pack_refs_opts pack_refs_opts = {
|
||||||
struct pack_refs_opts pack_refs_opts = { .exclusions = &excludes,
|
.exclusions = &excludes,
|
||||||
.includes = &included_refs,
|
.includes = &included_refs,
|
||||||
.flags = flags };
|
.flags = PACK_REFS_PRUNE,
|
||||||
static struct string_list option_excluded_refs = STRING_LIST_INIT_NODUP;
|
};
|
||||||
|
struct string_list option_excluded_refs = STRING_LIST_INIT_NODUP;
|
||||||
struct string_list_item *item;
|
struct string_list_item *item;
|
||||||
|
int pack_all = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
struct option opts[] = {
|
struct option opts[] = {
|
||||||
OPT_BIT(0, "all", &pack_refs_opts.flags, N_("pack everything"), PACK_REFS_ALL),
|
OPT_BOOL(0, "all", &pack_all, N_("pack everything")),
|
||||||
OPT_BIT(0, "prune", &pack_refs_opts.flags, N_("prune loose refs (default)"), PACK_REFS_PRUNE),
|
OPT_BIT(0, "prune", &pack_refs_opts.flags, N_("prune loose refs (default)"), PACK_REFS_PRUNE),
|
||||||
|
OPT_BIT(0, "auto", &pack_refs_opts.flags, N_("auto-pack refs as needed"), PACK_REFS_AUTO),
|
||||||
OPT_STRING_LIST(0, "include", pack_refs_opts.includes, N_("pattern"),
|
OPT_STRING_LIST(0, "include", pack_refs_opts.includes, N_("pattern"),
|
||||||
N_("references to include")),
|
N_("references to include")),
|
||||||
OPT_STRING_LIST(0, "exclude", &option_excluded_refs, N_("pattern"),
|
OPT_STRING_LIST(0, "exclude", &option_excluded_refs, N_("pattern"),
|
||||||
|
@ -38,11 +42,16 @@ int cmd_pack_refs(int argc, const char **argv, const char *prefix)
|
||||||
for_each_string_list_item(item, &option_excluded_refs)
|
for_each_string_list_item(item, &option_excluded_refs)
|
||||||
add_ref_exclusion(pack_refs_opts.exclusions, item->string);
|
add_ref_exclusion(pack_refs_opts.exclusions, item->string);
|
||||||
|
|
||||||
if (pack_refs_opts.flags & PACK_REFS_ALL)
|
if (pack_all)
|
||||||
string_list_append(pack_refs_opts.includes, "*");
|
string_list_append(pack_refs_opts.includes, "*");
|
||||||
|
|
||||||
if (!pack_refs_opts.includes->nr)
|
if (!pack_refs_opts.includes->nr)
|
||||||
string_list_append(pack_refs_opts.includes, "refs/tags/*");
|
string_list_append(pack_refs_opts.includes, "refs/tags/*");
|
||||||
|
|
||||||
return refs_pack_refs(get_main_ref_store(the_repository), &pack_refs_opts);
|
ret = refs_pack_refs(get_main_ref_store(the_repository), &pack_refs_opts);
|
||||||
|
|
||||||
|
clear_ref_exclusions(&excludes);
|
||||||
|
string_list_clear(&included_refs, 0);
|
||||||
|
string_list_clear(&option_excluded_refs, 0);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
20
refs.h
20
refs.h
|
@ -66,12 +66,6 @@ const char *ref_storage_format_to_name(unsigned int ref_storage_format);
|
||||||
#define RESOLVE_REF_NO_RECURSE 0x02
|
#define RESOLVE_REF_NO_RECURSE 0x02
|
||||||
#define RESOLVE_REF_ALLOW_BAD_NAME 0x04
|
#define RESOLVE_REF_ALLOW_BAD_NAME 0x04
|
||||||
|
|
||||||
struct pack_refs_opts {
|
|
||||||
unsigned int flags;
|
|
||||||
struct ref_exclusions *exclusions;
|
|
||||||
struct string_list *includes;
|
|
||||||
};
|
|
||||||
|
|
||||||
const char *refs_resolve_ref_unsafe(struct ref_store *refs,
|
const char *refs_resolve_ref_unsafe(struct ref_store *refs,
|
||||||
const char *refname,
|
const char *refname,
|
||||||
int resolve_flags,
|
int resolve_flags,
|
||||||
|
@ -428,10 +422,18 @@ void warn_dangling_symrefs(FILE *fp, const char *msg_fmt,
|
||||||
/*
|
/*
|
||||||
* Flags for controlling behaviour of pack_refs()
|
* Flags for controlling behaviour of pack_refs()
|
||||||
* PACK_REFS_PRUNE: Prune loose refs after packing
|
* PACK_REFS_PRUNE: Prune loose refs after packing
|
||||||
* PACK_REFS_ALL: Pack _all_ refs, not just tags and already packed refs
|
* PACK_REFS_AUTO: Pack refs on a best effort basis. The heuristics and end
|
||||||
|
* result are decided by the ref backend. Backends may ignore
|
||||||
|
* this flag and fall back to a normal repack.
|
||||||
*/
|
*/
|
||||||
#define PACK_REFS_PRUNE 0x0001
|
#define PACK_REFS_PRUNE (1 << 0)
|
||||||
#define PACK_REFS_ALL 0x0002
|
#define PACK_REFS_AUTO (1 << 1)
|
||||||
|
|
||||||
|
struct pack_refs_opts {
|
||||||
|
unsigned int flags;
|
||||||
|
struct ref_exclusions *exclusions;
|
||||||
|
struct string_list *includes;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Write a packed-refs file for the current repository.
|
* Write a packed-refs file for the current repository.
|
||||||
|
|
|
@ -1203,9 +1203,16 @@ static int reftable_be_pack_refs(struct ref_store *ref_store,
|
||||||
if (!stack)
|
if (!stack)
|
||||||
stack = refs->main_stack;
|
stack = refs->main_stack;
|
||||||
|
|
||||||
ret = reftable_stack_compact_all(stack, NULL);
|
if (opts->flags & PACK_REFS_AUTO)
|
||||||
if (ret)
|
ret = reftable_stack_auto_compact(stack);
|
||||||
|
else
|
||||||
|
ret = reftable_stack_compact_all(stack, NULL);
|
||||||
|
if (ret < 0) {
|
||||||
|
ret = error(_("unable to compact stack: %s"),
|
||||||
|
reftable_error_str(ret));
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
ret = reftable_stack_clean(stack);
|
ret = reftable_stack_clean(stack);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
|
@ -22,7 +22,7 @@ const char *reftable_error_str(int err)
|
||||||
case REFTABLE_NOT_EXIST_ERROR:
|
case REFTABLE_NOT_EXIST_ERROR:
|
||||||
return "file does not exist";
|
return "file does not exist";
|
||||||
case REFTABLE_LOCK_ERROR:
|
case REFTABLE_LOCK_ERROR:
|
||||||
return "data is outdated";
|
return "data is locked";
|
||||||
case REFTABLE_API_ERROR:
|
case REFTABLE_API_ERROR:
|
||||||
return "misuse of the reftable API";
|
return "misuse of the reftable API";
|
||||||
case REFTABLE_ZLIB_ERROR:
|
case REFTABLE_ZLIB_ERROR:
|
||||||
|
@ -35,6 +35,8 @@ const char *reftable_error_str(int err)
|
||||||
return "invalid refname";
|
return "invalid refname";
|
||||||
case REFTABLE_ENTRY_TOO_BIG_ERROR:
|
case REFTABLE_ENTRY_TOO_BIG_ERROR:
|
||||||
return "entry too large";
|
return "entry too large";
|
||||||
|
case REFTABLE_OUTDATED_ERROR:
|
||||||
|
return "data concurrently modified";
|
||||||
case -1:
|
case -1:
|
||||||
return "general error";
|
return "general error";
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -25,7 +25,7 @@ enum reftable_error {
|
||||||
*/
|
*/
|
||||||
REFTABLE_NOT_EXIST_ERROR = -4,
|
REFTABLE_NOT_EXIST_ERROR = -4,
|
||||||
|
|
||||||
/* Trying to write out-of-date data. */
|
/* Trying to access locked data. */
|
||||||
REFTABLE_LOCK_ERROR = -5,
|
REFTABLE_LOCK_ERROR = -5,
|
||||||
|
|
||||||
/* Misuse of the API:
|
/* Misuse of the API:
|
||||||
|
@ -57,6 +57,9 @@ enum reftable_error {
|
||||||
/* Entry does not fit. This can happen when writing outsize reflog
|
/* Entry does not fit. This can happen when writing outsize reflog
|
||||||
messages. */
|
messages. */
|
||||||
REFTABLE_ENTRY_TOO_BIG_ERROR = -11,
|
REFTABLE_ENTRY_TOO_BIG_ERROR = -11,
|
||||||
|
|
||||||
|
/* Trying to write out-of-date data. */
|
||||||
|
REFTABLE_OUTDATED_ERROR = -12,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* convert the numeric error code to a string. The string should not be
|
/* convert the numeric error code to a string. The string should not be
|
||||||
|
|
|
@ -529,9 +529,9 @@ int reftable_stack_add(struct reftable_stack *st,
|
||||||
{
|
{
|
||||||
int err = stack_try_add(st, write, arg);
|
int err = stack_try_add(st, write, arg);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
if (err == REFTABLE_LOCK_ERROR) {
|
if (err == REFTABLE_OUTDATED_ERROR) {
|
||||||
/* Ignore error return, we want to propagate
|
/* Ignore error return, we want to propagate
|
||||||
REFTABLE_LOCK_ERROR.
|
REFTABLE_OUTDATED_ERROR.
|
||||||
*/
|
*/
|
||||||
reftable_stack_reload(st);
|
reftable_stack_reload(st);
|
||||||
}
|
}
|
||||||
|
@ -590,9 +590,8 @@ static int reftable_stack_init_addition(struct reftable_addition *add,
|
||||||
err = stack_uptodate(st);
|
err = stack_uptodate(st);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
if (err > 0) {
|
||||||
if (err > 1) {
|
err = REFTABLE_OUTDATED_ERROR;
|
||||||
err = REFTABLE_LOCK_ERROR;
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -681,8 +680,19 @@ int reftable_addition_commit(struct reftable_addition *add)
|
||||||
if (err)
|
if (err)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if (!add->stack->disable_auto_compact)
|
if (!add->stack->disable_auto_compact) {
|
||||||
|
/*
|
||||||
|
* Auto-compact the stack to keep the number of tables in
|
||||||
|
* control. It is possible that a concurrent writer is already
|
||||||
|
* trying to compact parts of the stack, which would lead to a
|
||||||
|
* `REFTABLE_LOCK_ERROR` because parts of the stack are locked
|
||||||
|
* already. This is a benign error though, so we ignore it.
|
||||||
|
*/
|
||||||
err = reftable_stack_auto_compact(add->stack);
|
err = reftable_stack_auto_compact(add->stack);
|
||||||
|
if (err < 0 && err != REFTABLE_LOCK_ERROR)
|
||||||
|
goto done;
|
||||||
|
err = 0;
|
||||||
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
reftable_addition_close(add);
|
reftable_addition_close(add);
|
||||||
|
@ -713,10 +723,6 @@ static int stack_try_add(struct reftable_stack *st,
|
||||||
int err = reftable_stack_init_addition(&add, st);
|
int err = reftable_stack_init_addition(&add, st);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (err > 0) {
|
|
||||||
err = REFTABLE_LOCK_ERROR;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = reftable_addition_add(&add, write_table, arg);
|
err = reftable_addition_add(&add, write_table, arg);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
|
@ -978,7 +984,15 @@ done:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* < 0: error. 0 == OK, > 0 attempt failed; could retry. */
|
/*
|
||||||
|
* Compact all tables in the range `[first, last)` into a single new table.
|
||||||
|
*
|
||||||
|
* This function returns `0` on success or a code `< 0` on failure. When the
|
||||||
|
* stack or any of the tables in the specified range are already locked then
|
||||||
|
* this function returns `REFTABLE_LOCK_ERROR`. This is a benign error that
|
||||||
|
* callers can either ignore, or they may choose to retry compaction after some
|
||||||
|
* amount of time.
|
||||||
|
*/
|
||||||
static int stack_compact_range(struct reftable_stack *st,
|
static int stack_compact_range(struct reftable_stack *st,
|
||||||
size_t first, size_t last,
|
size_t first, size_t last,
|
||||||
struct reftable_log_expiry_config *expiry)
|
struct reftable_log_expiry_config *expiry)
|
||||||
|
@ -1008,7 +1022,7 @@ static int stack_compact_range(struct reftable_stack *st,
|
||||||
LOCK_NO_DEREF);
|
LOCK_NO_DEREF);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
if (errno == EEXIST)
|
if (errno == EEXIST)
|
||||||
err = 1;
|
err = REFTABLE_LOCK_ERROR;
|
||||||
else
|
else
|
||||||
err = REFTABLE_IO_ERROR;
|
err = REFTABLE_IO_ERROR;
|
||||||
goto done;
|
goto done;
|
||||||
|
@ -1030,7 +1044,7 @@ static int stack_compact_range(struct reftable_stack *st,
|
||||||
table_name.buf, LOCK_NO_DEREF);
|
table_name.buf, LOCK_NO_DEREF);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
if (errno == EEXIST)
|
if (errno == EEXIST)
|
||||||
err = 1;
|
err = REFTABLE_LOCK_ERROR;
|
||||||
else
|
else
|
||||||
err = REFTABLE_IO_ERROR;
|
err = REFTABLE_IO_ERROR;
|
||||||
goto done;
|
goto done;
|
||||||
|
@ -1080,7 +1094,7 @@ static int stack_compact_range(struct reftable_stack *st,
|
||||||
LOCK_NO_DEREF);
|
LOCK_NO_DEREF);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
if (errno == EEXIST)
|
if (errno == EEXIST)
|
||||||
err = 1;
|
err = REFTABLE_LOCK_ERROR;
|
||||||
else
|
else
|
||||||
err = REFTABLE_IO_ERROR;
|
err = REFTABLE_IO_ERROR;
|
||||||
goto done;
|
goto done;
|
||||||
|
@ -1192,7 +1206,7 @@ static int stack_compact_range_stats(struct reftable_stack *st,
|
||||||
struct reftable_log_expiry_config *config)
|
struct reftable_log_expiry_config *config)
|
||||||
{
|
{
|
||||||
int err = stack_compact_range(st, first, last, config);
|
int err = stack_compact_range(st, first, last, config);
|
||||||
if (err > 0)
|
if (err == REFTABLE_LOCK_ERROR)
|
||||||
st->stats.failures++;
|
st->stats.failures++;
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -232,7 +232,7 @@ static void test_reftable_stack_uptodate(void)
|
||||||
EXPECT_ERR(err);
|
EXPECT_ERR(err);
|
||||||
|
|
||||||
err = reftable_stack_add(st2, &write_test_ref, &ref2);
|
err = reftable_stack_add(st2, &write_test_ref, &ref2);
|
||||||
EXPECT(err == REFTABLE_LOCK_ERROR);
|
EXPECT(err == REFTABLE_OUTDATED_ERROR);
|
||||||
|
|
||||||
err = reftable_stack_reload(st2);
|
err = reftable_stack_reload(st2);
|
||||||
EXPECT_ERR(err);
|
EXPECT_ERR(err);
|
||||||
|
@ -343,6 +343,49 @@ static void test_reftable_stack_transaction_api_performs_auto_compaction(void)
|
||||||
clear_dir(dir);
|
clear_dir(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_reftable_stack_auto_compaction_fails_gracefully(void)
|
||||||
|
{
|
||||||
|
struct reftable_ref_record ref = {
|
||||||
|
.refname = "refs/heads/master",
|
||||||
|
.update_index = 1,
|
||||||
|
.value_type = REFTABLE_REF_VAL1,
|
||||||
|
.value.val1 = {0x01},
|
||||||
|
};
|
||||||
|
struct reftable_write_options cfg = {0};
|
||||||
|
struct reftable_stack *st;
|
||||||
|
struct strbuf table_path = STRBUF_INIT;
|
||||||
|
char *dir = get_tmp_dir(__LINE__);
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = reftable_new_stack(&st, dir, cfg);
|
||||||
|
EXPECT_ERR(err);
|
||||||
|
|
||||||
|
err = reftable_stack_add(st, write_test_ref, &ref);
|
||||||
|
EXPECT_ERR(err);
|
||||||
|
EXPECT(st->merged->stack_len == 1);
|
||||||
|
EXPECT(st->stats.attempts == 0);
|
||||||
|
EXPECT(st->stats.failures == 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lock the newly written table such that it cannot be compacted.
|
||||||
|
* Adding a new table to the stack should not be impacted by this, even
|
||||||
|
* though auto-compaction will now fail.
|
||||||
|
*/
|
||||||
|
strbuf_addf(&table_path, "%s/%s.lock", dir, st->readers[0]->name);
|
||||||
|
write_file_buf(table_path.buf, "", 0);
|
||||||
|
|
||||||
|
ref.update_index = 2;
|
||||||
|
err = reftable_stack_add(st, write_test_ref, &ref);
|
||||||
|
EXPECT_ERR(err);
|
||||||
|
EXPECT(st->merged->stack_len == 2);
|
||||||
|
EXPECT(st->stats.attempts == 1);
|
||||||
|
EXPECT(st->stats.failures == 1);
|
||||||
|
|
||||||
|
reftable_stack_destroy(st);
|
||||||
|
strbuf_release(&table_path);
|
||||||
|
clear_dir(dir);
|
||||||
|
}
|
||||||
|
|
||||||
static void test_reftable_stack_validate_refname(void)
|
static void test_reftable_stack_validate_refname(void)
|
||||||
{
|
{
|
||||||
struct reftable_write_options cfg = { 0 };
|
struct reftable_write_options cfg = { 0 };
|
||||||
|
@ -1085,6 +1128,7 @@ int stack_test_main(int argc, const char *argv[])
|
||||||
RUN_TEST(test_reftable_stack_tombstone);
|
RUN_TEST(test_reftable_stack_tombstone);
|
||||||
RUN_TEST(test_reftable_stack_transaction_api);
|
RUN_TEST(test_reftable_stack_transaction_api);
|
||||||
RUN_TEST(test_reftable_stack_transaction_api_performs_auto_compaction);
|
RUN_TEST(test_reftable_stack_transaction_api_performs_auto_compaction);
|
||||||
|
RUN_TEST(test_reftable_stack_auto_compaction_fails_gracefully);
|
||||||
RUN_TEST(test_reftable_stack_update_index_check);
|
RUN_TEST(test_reftable_stack_update_index_check);
|
||||||
RUN_TEST(test_reftable_stack_uptodate);
|
RUN_TEST(test_reftable_stack_uptodate);
|
||||||
RUN_TEST(test_reftable_stack_validate_refname);
|
RUN_TEST(test_reftable_stack_validate_refname);
|
||||||
|
|
|
@ -112,25 +112,6 @@ static const char **get_store(const char **argv, struct ref_store **refs)
|
||||||
return argv + 1;
|
return argv + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct flag_definition pack_flags[] = { FLAG_DEF(PACK_REFS_PRUNE),
|
|
||||||
FLAG_DEF(PACK_REFS_ALL),
|
|
||||||
{ NULL, 0 } };
|
|
||||||
|
|
||||||
static int cmd_pack_refs(struct ref_store *refs, const char **argv)
|
|
||||||
{
|
|
||||||
unsigned int flags = arg_flags(*argv++, "flags", pack_flags);
|
|
||||||
static struct ref_exclusions exclusions = REF_EXCLUSIONS_INIT;
|
|
||||||
static struct string_list included_refs = STRING_LIST_INIT_NODUP;
|
|
||||||
struct pack_refs_opts pack_opts = { .flags = flags,
|
|
||||||
.exclusions = &exclusions,
|
|
||||||
.includes = &included_refs };
|
|
||||||
|
|
||||||
if (pack_opts.flags & PACK_REFS_ALL)
|
|
||||||
string_list_append(pack_opts.includes, "*");
|
|
||||||
|
|
||||||
return refs_pack_refs(refs, &pack_opts);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cmd_create_symref(struct ref_store *refs, const char **argv)
|
static int cmd_create_symref(struct ref_store *refs, const char **argv)
|
||||||
{
|
{
|
||||||
const char *refname = notnull(*argv++, "refname");
|
const char *refname = notnull(*argv++, "refname");
|
||||||
|
@ -326,7 +307,6 @@ struct command {
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct command commands[] = {
|
static struct command commands[] = {
|
||||||
{ "pack-refs", cmd_pack_refs },
|
|
||||||
{ "create-symref", cmd_create_symref },
|
{ "create-symref", cmd_create_symref },
|
||||||
{ "delete-refs", cmd_delete_refs },
|
{ "delete-refs", cmd_delete_refs },
|
||||||
{ "rename-ref", cmd_rename_ref },
|
{ "rename-ref", cmd_rename_ref },
|
||||||
|
|
|
@ -15,3 +15,15 @@ empty_blob sha256:473a0f4c3be8a93681a267e3b1e9a7dcda1185436fe141f7749120a3037218
|
||||||
|
|
||||||
empty_tree sha1:4b825dc642cb6eb9a060e54bf8d69288fbee4904
|
empty_tree sha1:4b825dc642cb6eb9a060e54bf8d69288fbee4904
|
||||||
empty_tree sha256:6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321
|
empty_tree sha256:6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321
|
||||||
|
|
||||||
|
blob17_1 sha1:263
|
||||||
|
blob17_1 sha256:34
|
||||||
|
|
||||||
|
blob17_2 sha1:410
|
||||||
|
blob17_2 sha256:174
|
||||||
|
|
||||||
|
blob17_3 sha1:523
|
||||||
|
blob17_3 sha256:313
|
||||||
|
|
||||||
|
blob17_4 sha1:790
|
||||||
|
blob17_4 sha256:481
|
||||||
|
|
|
@ -32,11 +32,16 @@ test_expect_success 'prepare a trivial repository' '
|
||||||
HEAD=$(git rev-parse --verify HEAD)
|
HEAD=$(git rev-parse --verify HEAD)
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'pack_refs(PACK_REFS_ALL | PACK_REFS_PRUNE)' '
|
test_expect_success 'pack-refs --prune --all' '
|
||||||
N=`find .git/refs -type f | wc -l` &&
|
test_path_is_missing .git/packed-refs &&
|
||||||
|
git pack-refs --no-prune --all &&
|
||||||
|
test_path_is_file .git/packed-refs &&
|
||||||
|
N=$(find .git/refs -type f | wc -l) &&
|
||||||
test "$N" != 0 &&
|
test "$N" != 0 &&
|
||||||
test-tool ref-store main pack-refs PACK_REFS_PRUNE,PACK_REFS_ALL &&
|
|
||||||
N=`find .git/refs -type f` &&
|
git pack-refs --prune --all &&
|
||||||
|
test_path_is_file .git/packed-refs &&
|
||||||
|
N=$(find .git/refs -type f) &&
|
||||||
test -z "$N"
|
test -z "$N"
|
||||||
'
|
'
|
||||||
|
|
||||||
|
@ -159,6 +164,13 @@ test_expect_success 'test --exclude takes precedence over --include' '
|
||||||
git pack-refs --include "refs/heads/pack*" --exclude "refs/heads/pack*" &&
|
git pack-refs --include "refs/heads/pack*" --exclude "refs/heads/pack*" &&
|
||||||
test -f .git/refs/heads/dont_pack5'
|
test -f .git/refs/heads/dont_pack5'
|
||||||
|
|
||||||
|
test_expect_success '--auto packs and prunes refs as usual' '
|
||||||
|
git branch auto &&
|
||||||
|
test_path_is_file .git/refs/heads/auto &&
|
||||||
|
git pack-refs --auto --all &&
|
||||||
|
test_path_is_missing .git/refs/heads/auto
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success 'see if up-to-date packed refs are preserved' '
|
test_expect_success 'see if up-to-date packed refs are preserved' '
|
||||||
git branch q &&
|
git branch q &&
|
||||||
git pack-refs --all --prune &&
|
git pack-refs --all --prune &&
|
||||||
|
@ -358,4 +370,14 @@ test_expect_success 'pack-refs does not drop broken refs during deletion' '
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'maintenance --auto unconditionally packs loose refs' '
|
||||||
|
git update-ref refs/heads/something HEAD &&
|
||||||
|
test_path_is_file .git/refs/heads/something &&
|
||||||
|
git rev-parse refs/heads/something >expect &&
|
||||||
|
git maintenance run --task=pack-refs --auto &&
|
||||||
|
test_path_is_missing .git/refs/heads/something &&
|
||||||
|
git rev-parse refs/heads/something >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
|
|
@ -340,6 +340,26 @@ test_expect_success 'ref transaction: empty transaction in empty repo' '
|
||||||
EOF
|
EOF
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'ref transaction: fails gracefully when auto compaction fails' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
(
|
||||||
|
cd repo &&
|
||||||
|
|
||||||
|
test_commit A &&
|
||||||
|
for i in $(test_seq 10)
|
||||||
|
do
|
||||||
|
git branch branch-$i &&
|
||||||
|
for table in .git/reftable/*.ref
|
||||||
|
do
|
||||||
|
touch "$table.lock" || exit 1
|
||||||
|
done ||
|
||||||
|
exit 1
|
||||||
|
done &&
|
||||||
|
test_line_count = 13 .git/reftable/tables.list
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success 'pack-refs: compacts tables' '
|
test_expect_success 'pack-refs: compacts tables' '
|
||||||
test_when_finished "rm -rf repo" &&
|
test_when_finished "rm -rf repo" &&
|
||||||
git init repo &&
|
git init repo &&
|
||||||
|
@ -355,6 +375,65 @@ test_expect_success 'pack-refs: compacts tables' '
|
||||||
test_line_count = 1 repo/.git/reftable/tables.list
|
test_line_count = 1 repo/.git/reftable/tables.list
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'pack-refs: compaction raises locking errors' '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
test_commit -C repo A &&
|
||||||
|
touch repo/.git/reftable/tables.list.lock &&
|
||||||
|
cat >expect <<-EOF &&
|
||||||
|
error: unable to compact stack: data is locked
|
||||||
|
EOF
|
||||||
|
test_must_fail git -C repo pack-refs 2>err &&
|
||||||
|
test_cmp expect err
|
||||||
|
'
|
||||||
|
|
||||||
|
for command in pack-refs gc "maintenance run --task=pack-refs"
|
||||||
|
do
|
||||||
|
test_expect_success "$command: auto compaction" '
|
||||||
|
test_when_finished "rm -rf repo" &&
|
||||||
|
git init repo &&
|
||||||
|
(
|
||||||
|
cd repo &&
|
||||||
|
|
||||||
|
test_commit A &&
|
||||||
|
|
||||||
|
# We need a bit of setup to ensure that git-gc(1) actually
|
||||||
|
# triggers, and that it does not write anything to the refdb.
|
||||||
|
git config gc.auto 1 &&
|
||||||
|
git config gc.autoDetach 0 &&
|
||||||
|
git config gc.reflogExpire never &&
|
||||||
|
git config gc.reflogExpireUnreachable never &&
|
||||||
|
test_oid blob17_1 | git hash-object -w --stdin &&
|
||||||
|
|
||||||
|
# The tables should have been auto-compacted, and thus auto
|
||||||
|
# compaction should not have to do anything.
|
||||||
|
ls -1 .git/reftable >tables-expect &&
|
||||||
|
test_line_count = 4 tables-expect &&
|
||||||
|
git $command --auto &&
|
||||||
|
ls -1 .git/reftable >tables-actual &&
|
||||||
|
test_cmp tables-expect tables-actual &&
|
||||||
|
|
||||||
|
test_oid blob17_2 | git hash-object -w --stdin &&
|
||||||
|
|
||||||
|
# Lock all tables write some refs. Auto-compaction will be
|
||||||
|
# unable to compact tables and thus fails gracefully, leaving
|
||||||
|
# the stack in a sub-optimal state.
|
||||||
|
ls .git/reftable/*.ref |
|
||||||
|
while read table
|
||||||
|
do
|
||||||
|
touch "$table.lock" || exit 1
|
||||||
|
done &&
|
||||||
|
git branch B &&
|
||||||
|
git branch C &&
|
||||||
|
rm .git/reftable/*.lock &&
|
||||||
|
test_line_count = 5 .git/reftable/tables.list &&
|
||||||
|
|
||||||
|
git $command --auto &&
|
||||||
|
test_line_count = 1 .git/reftable/tables.list
|
||||||
|
)
|
||||||
|
'
|
||||||
|
done
|
||||||
|
|
||||||
test_expect_success 'pack-refs: prunes stale tables' '
|
test_expect_success 'pack-refs: prunes stale tables' '
|
||||||
test_when_finished "rm -rf repo" &&
|
test_when_finished "rm -rf repo" &&
|
||||||
git init repo &&
|
git init repo &&
|
||||||
|
|
|
@ -11,23 +11,7 @@ test_expect_success 'setup' '
|
||||||
# behavior, make sure we always pack everything to one pack by
|
# behavior, make sure we always pack everything to one pack by
|
||||||
# default
|
# default
|
||||||
git config gc.bigPackThreshold 2g &&
|
git config gc.bigPackThreshold 2g &&
|
||||||
|
test_oid_init
|
||||||
# These are simply values which, when hashed as a blob with a newline,
|
|
||||||
# produce a hash where the first byte is 0x17 in their respective
|
|
||||||
# algorithms.
|
|
||||||
test_oid_cache <<-EOF
|
|
||||||
obj1 sha1:263
|
|
||||||
obj1 sha256:34
|
|
||||||
|
|
||||||
obj2 sha1:410
|
|
||||||
obj2 sha256:174
|
|
||||||
|
|
||||||
obj3 sha1:523
|
|
||||||
obj3 sha256:313
|
|
||||||
|
|
||||||
obj4 sha1:790
|
|
||||||
obj4 sha256:481
|
|
||||||
EOF
|
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'gc empty repository' '
|
test_expect_success 'gc empty repository' '
|
||||||
|
@ -114,8 +98,8 @@ test_expect_success 'pre-auto-gc hook can stop auto gc' '
|
||||||
# We need to create two object whose sha1s start with 17
|
# We need to create two object whose sha1s start with 17
|
||||||
# since this is what git gc counts. As it happens, these
|
# since this is what git gc counts. As it happens, these
|
||||||
# two blobs will do so.
|
# two blobs will do so.
|
||||||
test_commit "$(test_oid obj1)" &&
|
test_commit "$(test_oid blob17_1)" &&
|
||||||
test_commit "$(test_oid obj2)" &&
|
test_commit "$(test_oid blob17_2)" &&
|
||||||
|
|
||||||
git gc --auto >../out.actual 2>../err.actual
|
git gc --auto >../out.actual 2>../err.actual
|
||||||
) &&
|
) &&
|
||||||
|
@ -146,13 +130,13 @@ test_expect_success 'auto gc with too many loose objects does not attempt to cre
|
||||||
# We need to create two object whose sha1s start with 17
|
# We need to create two object whose sha1s start with 17
|
||||||
# since this is what git gc counts. As it happens, these
|
# since this is what git gc counts. As it happens, these
|
||||||
# two blobs will do so.
|
# two blobs will do so.
|
||||||
test_commit "$(test_oid obj1)" &&
|
test_commit "$(test_oid blob17_1)" &&
|
||||||
test_commit "$(test_oid obj2)" &&
|
test_commit "$(test_oid blob17_2)" &&
|
||||||
# Our first gc will create a pack; our second will create a second pack
|
# Our first gc will create a pack; our second will create a second pack
|
||||||
git gc --auto &&
|
git gc --auto &&
|
||||||
ls .git/objects/pack/pack-*.pack | sort >existing_packs &&
|
ls .git/objects/pack/pack-*.pack | sort >existing_packs &&
|
||||||
test_commit "$(test_oid obj3)" &&
|
test_commit "$(test_oid blob17_3)" &&
|
||||||
test_commit "$(test_oid obj4)" &&
|
test_commit "$(test_oid blob17_4)" &&
|
||||||
|
|
||||||
git gc --auto 2>err &&
|
git gc --auto 2>err &&
|
||||||
test_grep ! "^warning:" err &&
|
test_grep ! "^warning:" err &&
|
||||||
|
|
Loading…
Reference in New Issue