зеркало из https://github.com/microsoft/git.git
gc: do not repack promisor packfiles
Teach gc to stop traversal at promisor objects, and to leave promisor packfiles alone. This has the effect of only repacking non-promisor packfiles, and preserves the distinction between promisor packfiles and non-promisor packfiles. Signed-off-by: Jonathan Tan <jonathantanmy@google.com> Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Родитель
df11e19648
Коммит
0c16cd499d
|
@ -255,6 +255,17 @@ a missing object is encountered. This is the default action.
|
|||
The form '--missing=allow-any' will allow object traversal to continue
|
||||
if a missing object is encountered. Missing objects will silently be
|
||||
omitted from the results.
|
||||
+
|
||||
The form '--missing=allow-promisor' is like 'allow-any', but will only
|
||||
allow object traversal to continue for EXPECTED promisor missing objects.
|
||||
Unexpected missing object will raise an error.
|
||||
|
||||
--exclude-promisor-objects::
|
||||
Omit objects that are known to be in the promisor remote. (This
|
||||
option has the purpose of operating only on locally created objects,
|
||||
so that when we repack, we still maintain a distinction between
|
||||
locally created objects [without .promisor] and objects from the
|
||||
promisor remote [with .promisor].) This is used with partial clone.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
|
|
|
@ -458,6 +458,9 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
|
|||
argv_array_push(&prune, prune_expire);
|
||||
if (quiet)
|
||||
argv_array_push(&prune, "--no-progress");
|
||||
if (repository_format_partial_clone)
|
||||
argv_array_push(&prune,
|
||||
"--exclude-promisor-objects");
|
||||
if (run_command_v_opt(prune.argv, RUN_GIT_CMD))
|
||||
return error(FAILED_RUN, prune.argv[0]);
|
||||
}
|
||||
|
|
|
@ -75,6 +75,8 @@ static int use_bitmap_index = -1;
|
|||
static int write_bitmap_index;
|
||||
static uint16_t write_bitmap_options;
|
||||
|
||||
static int exclude_promisor_objects;
|
||||
|
||||
static unsigned long delta_cache_size = 0;
|
||||
static unsigned long max_delta_cache_size = 256 * 1024 * 1024;
|
||||
static unsigned long cache_max_small_delta_size = 1000;
|
||||
|
@ -86,6 +88,7 @@ static struct list_objects_filter_options filter_options;
|
|||
enum missing_action {
|
||||
MA_ERROR = 0, /* fail if any missing objects are encountered */
|
||||
MA_ALLOW_ANY, /* silently allow ALL missing objects */
|
||||
MA_ALLOW_PROMISOR, /* silently allow all missing PROMISOR objects */
|
||||
};
|
||||
static enum missing_action arg_missing_action;
|
||||
static show_object_fn fn_show_object;
|
||||
|
@ -2577,6 +2580,20 @@ static void show_object__ma_allow_any(struct object *obj, const char *name, void
|
|||
show_object(obj, name, data);
|
||||
}
|
||||
|
||||
static void show_object__ma_allow_promisor(struct object *obj, const char *name, void *data)
|
||||
{
|
||||
assert(arg_missing_action == MA_ALLOW_PROMISOR);
|
||||
|
||||
/*
|
||||
* Quietly ignore EXPECTED missing objects. This avoids problems with
|
||||
* staging them now and getting an odd error later.
|
||||
*/
|
||||
if (!has_object_file(&obj->oid) && is_promisor_object(&obj->oid))
|
||||
return;
|
||||
|
||||
show_object(obj, name, data);
|
||||
}
|
||||
|
||||
static int option_parse_missing_action(const struct option *opt,
|
||||
const char *arg, int unset)
|
||||
{
|
||||
|
@ -2591,10 +2608,18 @@ static int option_parse_missing_action(const struct option *opt,
|
|||
|
||||
if (!strcmp(arg, "allow-any")) {
|
||||
arg_missing_action = MA_ALLOW_ANY;
|
||||
fetch_if_missing = 0;
|
||||
fn_show_object = show_object__ma_allow_any;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(arg, "allow-promisor")) {
|
||||
arg_missing_action = MA_ALLOW_PROMISOR;
|
||||
fetch_if_missing = 0;
|
||||
fn_show_object = show_object__ma_allow_promisor;
|
||||
return 0;
|
||||
}
|
||||
|
||||
die(_("invalid value for --missing"));
|
||||
return 0;
|
||||
}
|
||||
|
@ -3008,6 +3033,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
|
|||
{ OPTION_CALLBACK, 0, "missing", NULL, N_("action"),
|
||||
N_("handling for missing objects"), PARSE_OPT_NONEG,
|
||||
option_parse_missing_action },
|
||||
OPT_BOOL(0, "exclude-promisor-objects", &exclude_promisor_objects,
|
||||
N_("do not pack objects in promisor packfiles")),
|
||||
OPT_END(),
|
||||
};
|
||||
|
||||
|
@ -3053,6 +3080,12 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
|
|||
argv_array_push(&rp, "--unpacked");
|
||||
}
|
||||
|
||||
if (exclude_promisor_objects) {
|
||||
use_internal_rev_list = 1;
|
||||
fetch_if_missing = 0;
|
||||
argv_array_push(&rp, "--exclude-promisor-objects");
|
||||
}
|
||||
|
||||
if (!reuse_object)
|
||||
reuse_delta = 0;
|
||||
if (pack_compression_level == -1)
|
||||
|
|
|
@ -101,12 +101,15 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
|
|||
{
|
||||
struct rev_info revs;
|
||||
struct progress *progress = NULL;
|
||||
int exclude_promisor_objects = 0;
|
||||
const struct option options[] = {
|
||||
OPT__DRY_RUN(&show_only, N_("do not remove, show only")),
|
||||
OPT__VERBOSE(&verbose, N_("report pruned objects")),
|
||||
OPT_BOOL(0, "progress", &show_progress, N_("show progress")),
|
||||
OPT_EXPIRY_DATE(0, "expire", &expire,
|
||||
N_("expire objects older than <time>")),
|
||||
OPT_BOOL(0, "exclude-promisor-objects", &exclude_promisor_objects,
|
||||
N_("limit traversal to objects outside promisor packfiles")),
|
||||
OPT_END()
|
||||
};
|
||||
char *s;
|
||||
|
@ -139,6 +142,10 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
|
|||
show_progress = isatty(2);
|
||||
if (show_progress)
|
||||
progress = start_delayed_progress(_("Checking connectivity"), 0);
|
||||
if (exclude_promisor_objects) {
|
||||
fetch_if_missing = 0;
|
||||
revs.exclude_promisor_objects = 1;
|
||||
}
|
||||
|
||||
mark_reachable_objects(&revs, 1, expire, progress);
|
||||
stop_progress(&progress);
|
||||
|
|
|
@ -83,7 +83,8 @@ static void remove_pack_on_signal(int signo)
|
|||
|
||||
/*
|
||||
* Adds all packs hex strings to the fname list, which do not
|
||||
* have a corresponding .keep file.
|
||||
* have a corresponding .keep or .promisor file. These packs are not to
|
||||
* be kept if we are going to pack everything into one file.
|
||||
*/
|
||||
static void get_non_kept_pack_filenames(struct string_list *fname_list)
|
||||
{
|
||||
|
@ -101,7 +102,8 @@ static void get_non_kept_pack_filenames(struct string_list *fname_list)
|
|||
|
||||
fname = xmemdupz(e->d_name, len);
|
||||
|
||||
if (!file_exists(mkpath("%s/%s.keep", packdir, fname)))
|
||||
if (!file_exists(mkpath("%s/%s.keep", packdir, fname)) &&
|
||||
!file_exists(mkpath("%s/%s.promisor", packdir, fname)))
|
||||
string_list_append_nodup(fname_list, fname);
|
||||
else
|
||||
free(fname);
|
||||
|
@ -232,6 +234,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
|
|||
argv_array_push(&cmd.args, "--all");
|
||||
argv_array_push(&cmd.args, "--reflog");
|
||||
argv_array_push(&cmd.args, "--indexed-objects");
|
||||
if (repository_format_partial_clone)
|
||||
argv_array_push(&cmd.args, "--exclude-promisor-objects");
|
||||
if (window)
|
||||
argv_array_pushf(&cmd.args, "--window=%s", window);
|
||||
if (window_memory)
|
||||
|
|
|
@ -10,14 +10,16 @@ delete_object () {
|
|||
|
||||
pack_as_from_promisor () {
|
||||
HASH=$(git -C repo pack-objects .git/objects/pack/pack) &&
|
||||
>repo/.git/objects/pack/pack-$HASH.promisor
|
||||
>repo/.git/objects/pack/pack-$HASH.promisor &&
|
||||
echo $HASH
|
||||
}
|
||||
|
||||
promise_and_delete () {
|
||||
HASH=$(git -C repo rev-parse "$1") &&
|
||||
git -C repo tag -a -m message my_annotated_tag "$HASH" &&
|
||||
git -C repo rev-parse my_annotated_tag | pack_as_from_promisor &&
|
||||
git -C repo tag -d my_annotated_tag &&
|
||||
# tag -d prints a message to stdout, so redirect it
|
||||
git -C repo tag -d my_annotated_tag >/dev/null &&
|
||||
delete_object repo "$HASH"
|
||||
}
|
||||
|
||||
|
@ -261,6 +263,54 @@ test_expect_success 'rev-list accepts missing and promised objects on command li
|
|||
git -C repo rev-list --exclude-promisor-objects --objects "$COMMIT" "$TREE" "$BLOB"
|
||||
'
|
||||
|
||||
test_expect_success 'gc does not repack promisor objects' '
|
||||
rm -rf repo &&
|
||||
test_create_repo repo &&
|
||||
test_commit -C repo my_commit &&
|
||||
|
||||
TREE_HASH=$(git -C repo rev-parse HEAD^{tree}) &&
|
||||
HASH=$(printf "$TREE_HASH\n" | pack_as_from_promisor) &&
|
||||
|
||||
git -C repo config core.repositoryformatversion 1 &&
|
||||
git -C repo config extensions.partialclone "arbitrary string" &&
|
||||
git -C repo gc &&
|
||||
|
||||
# Ensure that the promisor packfile still exists, and remove it
|
||||
test -e repo/.git/objects/pack/pack-$HASH.pack &&
|
||||
rm repo/.git/objects/pack/pack-$HASH.* &&
|
||||
|
||||
# Ensure that the single other pack contains the commit, but not the tree
|
||||
ls repo/.git/objects/pack/pack-*.pack >packlist &&
|
||||
test_line_count = 1 packlist &&
|
||||
git verify-pack repo/.git/objects/pack/pack-*.pack -v >out &&
|
||||
grep "$(git -C repo rev-parse HEAD)" out &&
|
||||
! grep "$TREE_HASH" out
|
||||
'
|
||||
|
||||
test_expect_success 'gc stops traversal when a missing but promised object is reached' '
|
||||
rm -rf repo &&
|
||||
test_create_repo repo &&
|
||||
test_commit -C repo my_commit &&
|
||||
|
||||
TREE_HASH=$(git -C repo rev-parse HEAD^{tree}) &&
|
||||
HASH=$(promise_and_delete $TREE_HASH) &&
|
||||
|
||||
git -C repo config core.repositoryformatversion 1 &&
|
||||
git -C repo config extensions.partialclone "arbitrary string" &&
|
||||
git -C repo gc &&
|
||||
|
||||
# Ensure that the promisor packfile still exists, and remove it
|
||||
test -e repo/.git/objects/pack/pack-$HASH.pack &&
|
||||
rm repo/.git/objects/pack/pack-$HASH.* &&
|
||||
|
||||
# Ensure that the single other pack contains the commit, but not the tree
|
||||
ls repo/.git/objects/pack/pack-*.pack >packlist &&
|
||||
test_line_count = 1 packlist &&
|
||||
git verify-pack repo/.git/objects/pack/pack-*.pack -v >out &&
|
||||
grep "$(git -C repo rev-parse HEAD)" out &&
|
||||
! grep "$TREE_HASH" out
|
||||
'
|
||||
|
||||
LIB_HTTPD_PORT=12345 # default port, 410, cannot be used as non-root
|
||||
. "$TEST_DIRECTORY"/lib-httpd.sh
|
||||
start_httpd
|
||||
|
|
Загрузка…
Ссылка в новой задаче