diff --git a/Documentation/git-multi-pack-index.txt b/Documentation/git-multi-pack-index.txt
index 009c989ef8..27f83932e4 100644
--- a/Documentation/git-multi-pack-index.txt
+++ b/Documentation/git-multi-pack-index.txt
@@ -49,6 +49,21 @@ write::
--stdin-packs::
Write a multi-pack index containing only the set of
line-delimited pack index basenames provided over stdin.
+
+ --refs-snapshot=<path>::
+ With `--bitmap`, optionally specify a file which
+ contains a "refs snapshot" taken prior to repacking.
++
+A reference snapshot is composed of line-delimited OIDs corresponding to
+the reference tips, usually taken by `git repack` prior to generating a
+new pack. A line may optionally start with a `+` character to indicate
+that the reference which corresponds to that OID is "preferred" (see
+linkgit:git-config[1]'s `pack.preferBitmapTips`.)
++
+The file given at `<path>` is expected to be readable, and can contain
+duplicates. (If a given OID is given more than once, it is marked as
+preferred if at least one instance of it begins with the special `+`
+marker).
--
verify::
diff --git a/builtin/multi-pack-index.c b/builtin/multi-pack-index.c
index 77488b6b7b..65a242f5cf 100644
--- a/builtin/multi-pack-index.c
+++ b/builtin/multi-pack-index.c
@@ -7,7 +7,8 @@
#include "object-store.h"
#define BUILTIN_MIDX_WRITE_USAGE \
- N_("git multi-pack-index [<options>] write [--preferred-pack=<pack>]")
+ N_("git multi-pack-index [<options>] write [--preferred-pack=<pack>]" \
+ "[--refs-snapshot=<path>]")
#define BUILTIN_MIDX_VERIFY_USAGE \
N_("git multi-pack-index [<options>] verify")@@ -45,6 +46,7 @@ static char const * const builtin_multi_pack_index_usage[] = {
static struct opts_multi_pack_index {
const char *object_dir;
const char *preferred_pack;
+ const char *refs_snapshot;
unsigned long batch_size;
unsigned flags;
int stdin_packs;@@ -82,6 +84,8 @@ static int cmd_multi_pack_index_write(int argc, const char **argv)
MIDX_WRITE_BITMAP | MIDX_WRITE_REV_INDEX),
OPT_BOOL(0, "stdin-packs", &opts.stdin_packs,
N_("write multi-pack index containing only given indexes")),
+ OPT_FILENAME(0, "refs-snapshot", &opts.refs_snapshot,
+ N_("refs snapshot for selecting bitmap commits")),
OPT_END(),
};
@@ -105,7 +109,8 @@ static int cmd_multi_pack_index_write(int argc, const char **argv)
read_packs_from_stdin(&packs);
ret = write_midx_file_only(opts.object_dir, &packs,
- opts.preferred_pack, opts.flags);
+ opts.preferred_pack,
+ opts.refs_snapshot, opts.flags);
string_list_clear(&packs, 0);
@@ -113,7 +118,7 @@ static int cmd_multi_pack_index_write(int argc, const char **argv)
}
return write_midx_file(opts.object_dir, opts.preferred_pack,
- opts.flags);
+ opts.refs_snapshot, opts.flags);
}
static int cmd_multi_pack_index_verify(int argc, const char **argv)
diff --git a/builtin/repack.c b/builtin/repack.c
index 82ab668272..27158a897b 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -733,7 +733,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
unsigned flags = 0;
if (git_env_bool(GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP, 0))
flags |= MIDX_WRITE_BITMAP | MIDX_WRITE_REV_INDEX;
- write_midx_file(get_object_directory(), NULL, flags);
+ write_midx_file(get_object_directory(), NULL, NULL, flags);
}
string_list_clear(&names, 0);
diff --git a/midx.c b/midx.c
index 29d1d107b3..46ded7a4cf 100644
--- a/midx.c
+++ b/midx.c
@@ -970,7 +970,42 @@ static void bitmap_show_commit(struct commit *commit, void *_data)
data->commits[data->commits_nr++] = commit;
}
+static int read_refs_snapshot(const char *refs_snapshot,
+ struct rev_info *revs)
+{
+ struct strbuf buf = STRBUF_INIT;
+ struct object_id oid;
+ FILE *f = xfopen(refs_snapshot, "r");
+
+ while (strbuf_getline(&buf, f) != EOF) {
+ struct object *object;
+ int preferred = 0;
+ char *hex = buf.buf;
+ const char *end = NULL;
+
+ if (buf.len && *buf.buf == '+') {
+ preferred = 1;
+ hex = &buf.buf[1];
+ }
+
+ if (parse_oid_hex(hex, &oid, &end) < 0)
+ die(_("could not parse line: %s"), buf.buf);
+ if (*end)
+ die(_("malformed line: %s"), buf.buf);
+
+ object = parse_object_or_die(&oid, NULL);
+ if (preferred)
+ object->flags |= NEEDS_BITMAP;
+
+ add_pending_object(revs, object, "");
+ }
+
+ fclose(f);
+ return 0;
+}
+
static struct commit **find_commits_for_midx_bitmap(uint32_t *indexed_commits_nr_p,
+ const char *refs_snapshot,
struct write_midx_context *ctx)
{
struct rev_info revs;@@ -979,8 +1014,12 @@ static struct commit **find_commits_for_midx_bitmap(uint32_t *indexed_commits_nr
cb.ctx = ctx;
repo_init_revisions(the_repository, &revs, NULL);
- setup_revisions(0, NULL, &revs, NULL);
- for_each_ref(add_ref_to_pending, &revs);
+ if (refs_snapshot) {
+ read_refs_snapshot(refs_snapshot, &revs);
+ } else {
+ setup_revisions(0, NULL, &revs, NULL);
+ for_each_ref(add_ref_to_pending, &revs);
+ }
/*
* Skipping promisor objects here is intentional, since it only excludes@@ -1009,6 +1048,7 @@ static struct commit **find_commits_for_midx_bitmap(uint32_t *indexed_commits_nr
static int write_midx_bitmap(char *midx_name, unsigned char *midx_hash,
struct write_midx_context *ctx,
+ const char *refs_snapshot,
unsigned flags)
{
struct packing_data pdata;@@ -1020,7 +1060,7 @@ static int write_midx_bitmap(char *midx_name, unsigned char *midx_hash,
prepare_midx_packing_data(&pdata, ctx);
- commits = find_commits_for_midx_bitmap(&commits_nr, ctx);
+ commits = find_commits_for_midx_bitmap(&commits_nr, refs_snapshot, ctx);
/*
* Build the MIDX-order index based on pdata.objects (which is already
@@ -1068,6 +1108,7 @@ static int write_midx_internal(const char *object_dir,
struct string_list *packs_to_include,
struct string_list *packs_to_drop,
const char *preferred_pack_name,
+ const char *refs_snapshot,
unsigned flags)
{
char *midx_name;@@ -1361,7 +1402,8 @@ static int write_midx_internal(const char *object_dir,
if (flags & MIDX_WRITE_REV_INDEX)
write_midx_reverse_index(midx_name, midx_hash, &ctx);
if (flags & MIDX_WRITE_BITMAP) {
- if (write_midx_bitmap(midx_name, midx_hash, &ctx, flags) < 0) {
+ if (write_midx_bitmap(midx_name, midx_hash, &ctx,
+ refs_snapshot, flags) < 0) {
error(_("could not write multi-pack bitmap"));
result = 1;
goto cleanup;@@ -1396,19 +1438,21 @@ static int write_midx_internal(const char *object_dir,
int write_midx_file(const char *object_dir,
const char *preferred_pack_name,
+ const char *refs_snapshot,
unsigned flags)
{
return write_midx_internal(object_dir, NULL, NULL, preferred_pack_name,
- flags);
+ refs_snapshot, flags);
}
int write_midx_file_only(const char *object_dir,
struct string_list *packs_to_include,
const char *preferred_pack_name,
+ const char *refs_snapshot,
unsigned flags)
{
return write_midx_internal(object_dir, packs_to_include, NULL,
- preferred_pack_name, flags);
+ preferred_pack_name, refs_snapshot, flags);
}
struct clear_midx_data {@@ -1688,7 +1732,7 @@ int expire_midx_packs(struct repository *r, const char *object_dir, unsigned fla
free(count);
if (packs_to_drop.nr) {
- result = write_midx_internal(object_dir, NULL, &packs_to_drop, NULL, flags);
+ result = write_midx_internal(object_dir, NULL, &packs_to_drop, NULL, NULL, flags);
m = NULL;
}
@@ -1879,7 +1923,7 @@ int midx_repack(struct repository *r, const char *object_dir, size_t batch_size,
goto cleanup;
}
- result = write_midx_internal(object_dir, NULL, NULL, NULL, flags);
+ result = write_midx_internal(object_dir, NULL, NULL, NULL, NULL, flags);
m = NULL;
cleanup:
diff --git a/midx.h b/midx.h
index aefa371c90..dc37b94ea1 100644
--- a/midx.h
+++ b/midx.h
@@ -62,8 +62,8 @@ int fill_midx_entry(struct repository *r, const struct object_id *oid, struct pa
int midx_contains_pack(struct multi_pack_index *m, const char *idx_or_pack_name);
int prepare_multi_pack_index_one(struct repository *r, const char *object_dir, int local);
-int write_midx_file(const char *object_dir, const char *preferred_pack_name, unsigned flags);
-int write_midx_file_only(const char *object_dir, struct string_list *packs_to_include, const char *preferred_pack_name, unsigned flags);
+int write_midx_file(const char *object_dir, const char *preferred_pack_name, const char *refs_snapshot, unsigned flags);
+int write_midx_file_only(const char *object_dir, struct string_list *packs_to_include, const char *preferred_pack_name, const char *refs_snapshot, unsigned flags);
void clear_midx_file(struct repository *r);
int verify_midx_file(struct repository *r, const char *object_dir, unsigned flags);
int expire_midx_packs(struct repository *r, const char *object_dir, unsigned flags);
diff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh
index 4ad7c2c969..069dab3e17 100755
--- a/t/t5326-multi-pack-bitmaps.sh
+++ b/t/t5326-multi-pack-bitmaps.sh
@@ -283,4 +283,86 @@ test_expect_success 'pack.preferBitmapTips' '
)
'
+test_expect_success 'writing a bitmap with --refs-snapshot' '
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+
+ test_commit one &&
+ test_commit two &&
+
+ git rev-parse one >snapshot &&
+
+ git repack -ad &&
+
+ # First, write a MIDX which see both refs/tags/one and
+ # refs/tags/two (causing both of those commits to receive
+ # bitmaps).
+ git multi-pack-index write --bitmap &&
+
+ test_path_is_file $midx &&
+ test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
+
+ test-tool bitmap list-commits | sort >bitmaps &&
+ grep "$(git rev-parse one)" bitmaps &&
+ grep "$(git rev-parse two)" bitmaps &&
+
+ rm -fr $midx-$(midx_checksum $objdir).bitmap &&
+ rm -fr $midx-$(midx_checksum $objdir).rev &&
+ rm -fr $midx &&
+
+ # Then again, but with a refs snapshot which only sees
+ # refs/tags/one.
+ git multi-pack-index write --bitmap --refs-snapshot=snapshot &&
+
+ test_path_is_file $midx &&
+ test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
+
+ test-tool bitmap list-commits | sort >bitmaps &&
+ grep "$(git rev-parse one)" bitmaps &&
+ ! grep "$(git rev-parse two)" bitmaps
+ )
+'
+
+test_expect_success 'write a bitmap with --refs-snapshot (preferred tips)' '
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+
+ test_commit_bulk --message="%s" 103 &&
+
+ git log --format="%H" >commits.raw &&
+ sort <commits.raw >commits &&
+
+ git log --format="create refs/tags/%s %H" HEAD >refs &&
+ git update-ref --stdin <refs &&
+
+ git multi-pack-index write --bitmap &&
+ test_path_is_file $midx &&
+ test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
+
+ test-tool bitmap list-commits | sort >bitmaps &&
+ comm -13 bitmaps commits >before &&
+ test_line_count = 1 before &&
+
+ (
+ grep -vf before commits.raw &&
+ # mark missing commits as preferred
+ sed "s/^/+/" before
+ ) >snapshot &&
+
+ rm -fr $midx-$(midx_checksum $objdir).bitmap &&
+ rm -fr $midx-$(midx_checksum $objdir).rev &&
+ rm -fr $midx &&
+
+ git multi-pack-index write --bitmap --refs-snapshot=snapshot &&
+ test-tool bitmap list-commits | sort >bitmaps &&
+ comm -13 bitmaps commits >after &&
+
+ ! test_cmp before after
+ )
+'
+
test_done
--
2.33.0.96.g73915697e6