Skip to content

Commit 0c16cd4

Browse files
jonathantanmygitster
authored andcommitted
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 <[email protected]> Signed-off-by: Jeff Hostetler <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent df11e19 commit 0c16cd4

File tree

6 files changed

+114
-6
lines changed

6 files changed

+114
-6
lines changed

Documentation/git-pack-objects.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,17 @@ a missing object is encountered. This is the default action.
255255
The form '--missing=allow-any' will allow object traversal to continue
256256
if a missing object is encountered. Missing objects will silently be
257257
omitted from the results.
258+
+
259+
The form '--missing=allow-promisor' is like 'allow-any', but will only
260+
allow object traversal to continue for EXPECTED promisor missing objects.
261+
Unexpected missing object will raise an error.
262+
263+
--exclude-promisor-objects::
264+
Omit objects that are known to be in the promisor remote. (This
265+
option has the purpose of operating only on locally created objects,
266+
so that when we repack, we still maintain a distinction between
267+
locally created objects [without .promisor] and objects from the
268+
promisor remote [with .promisor].) This is used with partial clone.
258269

259270
SEE ALSO
260271
--------

builtin/gc.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,9 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
458458
argv_array_push(&prune, prune_expire);
459459
if (quiet)
460460
argv_array_push(&prune, "--no-progress");
461+
if (repository_format_partial_clone)
462+
argv_array_push(&prune,
463+
"--exclude-promisor-objects");
461464
if (run_command_v_opt(prune.argv, RUN_GIT_CMD))
462465
return error(FAILED_RUN, prune.argv[0]);
463466
}

builtin/pack-objects.c

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ static int use_bitmap_index = -1;
7575
static int write_bitmap_index;
7676
static uint16_t write_bitmap_options;
7777

78+
static int exclude_promisor_objects;
79+
7880
static unsigned long delta_cache_size = 0;
7981
static unsigned long max_delta_cache_size = 256 * 1024 * 1024;
8082
static unsigned long cache_max_small_delta_size = 1000;
@@ -84,8 +86,9 @@ static unsigned long window_memory_limit = 0;
8486
static struct list_objects_filter_options filter_options;
8587

8688
enum missing_action {
87-
MA_ERROR = 0, /* fail if any missing objects are encountered */
88-
MA_ALLOW_ANY, /* silently allow ALL missing objects */
89+
MA_ERROR = 0, /* fail if any missing objects are encountered */
90+
MA_ALLOW_ANY, /* silently allow ALL missing objects */
91+
MA_ALLOW_PROMISOR, /* silently allow all missing PROMISOR objects */
8992
};
9093
static enum missing_action arg_missing_action;
9194
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
25772580
show_object(obj, name, data);
25782581
}
25792582

2583+
static void show_object__ma_allow_promisor(struct object *obj, const char *name, void *data)
2584+
{
2585+
assert(arg_missing_action == MA_ALLOW_PROMISOR);
2586+
2587+
/*
2588+
* Quietly ignore EXPECTED missing objects. This avoids problems with
2589+
* staging them now and getting an odd error later.
2590+
*/
2591+
if (!has_object_file(&obj->oid) && is_promisor_object(&obj->oid))
2592+
return;
2593+
2594+
show_object(obj, name, data);
2595+
}
2596+
25802597
static int option_parse_missing_action(const struct option *opt,
25812598
const char *arg, int unset)
25822599
{
@@ -2591,10 +2608,18 @@ static int option_parse_missing_action(const struct option *opt,
25912608

25922609
if (!strcmp(arg, "allow-any")) {
25932610
arg_missing_action = MA_ALLOW_ANY;
2611+
fetch_if_missing = 0;
25942612
fn_show_object = show_object__ma_allow_any;
25952613
return 0;
25962614
}
25972615

2616+
if (!strcmp(arg, "allow-promisor")) {
2617+
arg_missing_action = MA_ALLOW_PROMISOR;
2618+
fetch_if_missing = 0;
2619+
fn_show_object = show_object__ma_allow_promisor;
2620+
return 0;
2621+
}
2622+
25982623
die(_("invalid value for --missing"));
25992624
return 0;
26002625
}
@@ -3008,6 +3033,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
30083033
{ OPTION_CALLBACK, 0, "missing", NULL, N_("action"),
30093034
N_("handling for missing objects"), PARSE_OPT_NONEG,
30103035
option_parse_missing_action },
3036+
OPT_BOOL(0, "exclude-promisor-objects", &exclude_promisor_objects,
3037+
N_("do not pack objects in promisor packfiles")),
30113038
OPT_END(),
30123039
};
30133040

@@ -3053,6 +3080,12 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
30533080
argv_array_push(&rp, "--unpacked");
30543081
}
30553082

3083+
if (exclude_promisor_objects) {
3084+
use_internal_rev_list = 1;
3085+
fetch_if_missing = 0;
3086+
argv_array_push(&rp, "--exclude-promisor-objects");
3087+
}
3088+
30563089
if (!reuse_object)
30573090
reuse_delta = 0;
30583091
if (pack_compression_level == -1)

builtin/prune.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,15 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
101101
{
102102
struct rev_info revs;
103103
struct progress *progress = NULL;
104+
int exclude_promisor_objects = 0;
104105
const struct option options[] = {
105106
OPT__DRY_RUN(&show_only, N_("do not remove, show only")),
106107
OPT__VERBOSE(&verbose, N_("report pruned objects")),
107108
OPT_BOOL(0, "progress", &show_progress, N_("show progress")),
108109
OPT_EXPIRY_DATE(0, "expire", &expire,
109110
N_("expire objects older than <time>")),
111+
OPT_BOOL(0, "exclude-promisor-objects", &exclude_promisor_objects,
112+
N_("limit traversal to objects outside promisor packfiles")),
110113
OPT_END()
111114
};
112115
char *s;
@@ -139,6 +142,10 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
139142
show_progress = isatty(2);
140143
if (show_progress)
141144
progress = start_delayed_progress(_("Checking connectivity"), 0);
145+
if (exclude_promisor_objects) {
146+
fetch_if_missing = 0;
147+
revs.exclude_promisor_objects = 1;
148+
}
142149

143150
mark_reachable_objects(&revs, 1, expire, progress);
144151
stop_progress(&progress);

builtin/repack.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,8 @@ static void remove_pack_on_signal(int signo)
8383

8484
/*
8585
* Adds all packs hex strings to the fname list, which do not
86-
* have a corresponding .keep file.
86+
* have a corresponding .keep or .promisor file. These packs are not to
87+
* be kept if we are going to pack everything into one file.
8788
*/
8889
static void get_non_kept_pack_filenames(struct string_list *fname_list)
8990
{
@@ -101,7 +102,8 @@ static void get_non_kept_pack_filenames(struct string_list *fname_list)
101102

102103
fname = xmemdupz(e->d_name, len);
103104

104-
if (!file_exists(mkpath("%s/%s.keep", packdir, fname)))
105+
if (!file_exists(mkpath("%s/%s.keep", packdir, fname)) &&
106+
!file_exists(mkpath("%s/%s.promisor", packdir, fname)))
105107
string_list_append_nodup(fname_list, fname);
106108
else
107109
free(fname);
@@ -232,6 +234,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
232234
argv_array_push(&cmd.args, "--all");
233235
argv_array_push(&cmd.args, "--reflog");
234236
argv_array_push(&cmd.args, "--indexed-objects");
237+
if (repository_format_partial_clone)
238+
argv_array_push(&cmd.args, "--exclude-promisor-objects");
235239
if (window)
236240
argv_array_pushf(&cmd.args, "--window=%s", window);
237241
if (window_memory)

t/t0410-partial-clone.sh

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,16 @@ delete_object () {
1010

1111
pack_as_from_promisor () {
1212
HASH=$(git -C repo pack-objects .git/objects/pack/pack) &&
13-
>repo/.git/objects/pack/pack-$HASH.promisor
13+
>repo/.git/objects/pack/pack-$HASH.promisor &&
14+
echo $HASH
1415
}
1516

1617
promise_and_delete () {
1718
HASH=$(git -C repo rev-parse "$1") &&
1819
git -C repo tag -a -m message my_annotated_tag "$HASH" &&
1920
git -C repo rev-parse my_annotated_tag | pack_as_from_promisor &&
20-
git -C repo tag -d my_annotated_tag &&
21+
# tag -d prints a message to stdout, so redirect it
22+
git -C repo tag -d my_annotated_tag >/dev/null &&
2123
delete_object repo "$HASH"
2224
}
2325

@@ -261,6 +263,54 @@ test_expect_success 'rev-list accepts missing and promised objects on command li
261263
git -C repo rev-list --exclude-promisor-objects --objects "$COMMIT" "$TREE" "$BLOB"
262264
'
263265

266+
test_expect_success 'gc does not repack promisor objects' '
267+
rm -rf repo &&
268+
test_create_repo repo &&
269+
test_commit -C repo my_commit &&
270+
271+
TREE_HASH=$(git -C repo rev-parse HEAD^{tree}) &&
272+
HASH=$(printf "$TREE_HASH\n" | pack_as_from_promisor) &&
273+
274+
git -C repo config core.repositoryformatversion 1 &&
275+
git -C repo config extensions.partialclone "arbitrary string" &&
276+
git -C repo gc &&
277+
278+
# Ensure that the promisor packfile still exists, and remove it
279+
test -e repo/.git/objects/pack/pack-$HASH.pack &&
280+
rm repo/.git/objects/pack/pack-$HASH.* &&
281+
282+
# Ensure that the single other pack contains the commit, but not the tree
283+
ls repo/.git/objects/pack/pack-*.pack >packlist &&
284+
test_line_count = 1 packlist &&
285+
git verify-pack repo/.git/objects/pack/pack-*.pack -v >out &&
286+
grep "$(git -C repo rev-parse HEAD)" out &&
287+
! grep "$TREE_HASH" out
288+
'
289+
290+
test_expect_success 'gc stops traversal when a missing but promised object is reached' '
291+
rm -rf repo &&
292+
test_create_repo repo &&
293+
test_commit -C repo my_commit &&
294+
295+
TREE_HASH=$(git -C repo rev-parse HEAD^{tree}) &&
296+
HASH=$(promise_and_delete $TREE_HASH) &&
297+
298+
git -C repo config core.repositoryformatversion 1 &&
299+
git -C repo config extensions.partialclone "arbitrary string" &&
300+
git -C repo gc &&
301+
302+
# Ensure that the promisor packfile still exists, and remove it
303+
test -e repo/.git/objects/pack/pack-$HASH.pack &&
304+
rm repo/.git/objects/pack/pack-$HASH.* &&
305+
306+
# Ensure that the single other pack contains the commit, but not the tree
307+
ls repo/.git/objects/pack/pack-*.pack >packlist &&
308+
test_line_count = 1 packlist &&
309+
git verify-pack repo/.git/objects/pack/pack-*.pack -v >out &&
310+
grep "$(git -C repo rev-parse HEAD)" out &&
311+
! grep "$TREE_HASH" out
312+
'
313+
264314
LIB_HTTPD_PORT=12345 # default port, 410, cannot be used as non-root
265315
. "$TEST_DIRECTORY"/lib-httpd.sh
266316
start_httpd

0 commit comments

Comments
 (0)