diff --git a/builtin/repack.c b/builtin/repack.c index 094c2f8ea4..78b23d7a9a 100644 --- a/builtin/repack.c +++ b/builtin/repack.c @@ -233,6 +233,13 @@ static void repack_promisor_objects(const struct pack_objects_args *args, /* * pack-objects creates the .pack and .idx files, but not the * .promisor file. Create the .promisor file, which is empty. + * + * NEEDSWORK: fetch-pack sometimes generates non-empty + * .promisor files containing the ref names and associated + * hashes at the point of generation of the corresponding + * packfile, but this would not preserve their contents. Maybe + * concatenate the contents of all .promisor files instead of + * just creating a new empty file. */ promisor_name = mkpathdup("%s-%s.promisor", packtmp, line.buf); diff --git a/fetch-pack.c b/fetch-pack.c index 947da545de..b9e63b52ff 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -754,8 +754,33 @@ static int sideband_demux(int in, int out, void *data) return ret; } +static void write_promisor_file(const char *keep_name, + struct ref **sought, int nr_sought) +{ + struct strbuf promisor_name = STRBUF_INIT; + int suffix_stripped; + FILE *output; + int i; + + strbuf_addstr(&promisor_name, keep_name); + suffix_stripped = strbuf_strip_suffix(&promisor_name, ".keep"); + if (!suffix_stripped) + BUG("name of pack lockfile should end with .keep (was '%s')", + keep_name); + strbuf_addstr(&promisor_name, ".promisor"); + + output = xfopen(promisor_name.buf, "w"); + for (i = 0; i < nr_sought; i++) + fprintf(output, "%s %s\n", oid_to_hex(&sought[i]->old_oid), + sought[i]->name); + fclose(output); + + strbuf_release(&promisor_name); +} + static int get_pack(struct fetch_pack_args *args, - int xd[2], char **pack_lockfile) + int xd[2], char **pack_lockfile, + struct ref **sought, int nr_sought) { struct async demux; int do_keep = args->keep_pack; @@ -817,7 +842,13 @@ static int get_pack(struct fetch_pack_args *args, } if (args->check_self_contained_and_connected) argv_array_push(&cmd.args, "--check-self-contained-and-connected"); - if (args->from_promisor) + /* + * If we're obtaining the filename of a lockfile, we'll use + * that filename to write a .promisor file with more + * information below. If not, we need index-pack to do it for + * us. + */ + if (!(do_keep && pack_lockfile) && args->from_promisor) argv_array_push(&cmd.args, "--promisor"); } else { @@ -871,6 +902,14 @@ static int get_pack(struct fetch_pack_args *args, die(_("%s failed"), cmd_name); if (use_sideband && finish_async(&demux)) die(_("error in sideband demultiplexer")); + + /* + * Now that index-pack has succeeded, write the promisor file using the + * obtained .keep filename if necessary + */ + if (do_keep && pack_lockfile && args->from_promisor) + write_promisor_file(*pack_lockfile, sought, nr_sought); + return 0; } @@ -1006,7 +1045,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args, alternate_shallow_file = setup_temporary_shallow(si->shallow); else alternate_shallow_file = NULL; - if (get_pack(args, fd, pack_lockfile)) + if (get_pack(args, fd, pack_lockfile, sought, nr_sought)) die(_("git fetch-pack: fetch failed.")); all_done: @@ -1453,7 +1492,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args, /* get the pack */ process_section_header(&reader, "packfile", 0); - if (get_pack(args, fd, pack_lockfile)) + if (get_pack(args, fd, pack_lockfile, sought, nr_sought)) die(_("git fetch-pack: fetch failed.")); state = FETCH_DONE; diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh index 79f7b65f8c..eaa33a852b 100755 --- a/t/t5616-partial-clone.sh +++ b/t/t5616-partial-clone.sh @@ -46,6 +46,14 @@ test_expect_success 'do partial clone 1' ' test "$(git -C pc1 config --local remote.origin.partialclonefilter)" = "blob:none" ' +test_expect_success 'verify that .promisor file contains refs fetched' ' + ls pc1/.git/objects/pack/pack-*.promisor >promisorlist && + test_line_count = 1 promisorlist && + git -C srv.bare rev-list HEAD >headhash && + grep "$(cat headhash) HEAD" $(cat promisorlist) && + grep "$(cat headhash) refs/heads/master" $(cat promisorlist) +' + # checkout master to force dynamic object fetch of blobs at HEAD. test_expect_success 'verify checkout with dynamic object fetch' ' git -C pc1 rev-list --quiet --objects --missing=print HEAD >observed &&