]> git.ipfire.org Git - thirdparty/git.git/commitdiff
builtin/pack-objects.c: respect 'pack.preferBitmapTips'
authorTaylor Blau <me@ttaylorr.com>
Thu, 1 Apr 2021 01:32:14 +0000 (21:32 -0400)
committerJunio C Hamano <gitster@pobox.com>
Thu, 1 Apr 2021 06:14:03 +0000 (23:14 -0700)
When writing a new pack with a bitmap, it is sometimes convenient to
indicate some reference prefixes which should receive priority when
selecting which commits to receive bitmaps.

A truly motivated caller could accomplish this by setting
'pack.islandCore', (since all commits in the core island are similarly
marked as preferred) but this requires callers to opt into using delta
islands, which they may or may not want to do.

Introduce a new multi-valued configuration, 'pack.preferBitmapTips' to
allow callers to specify a list of reference prefixes. All references
which have a prefix contained in 'pack.preferBitmapTips' will mark their
tips as "preferred" in the same way as commits are marked as preferred
for selection by 'pack.islandCore'.

The choice of the verb "prefer" is intentional: marking the NEEDS_BITMAP
flag on an object does *not* guarantee that that object will receive a
bitmap. It merely guarantees that that commit will receive a bitmap over
any *other* commit in the same window by bitmap_writer_select_commits().

The test this patch adds reflects this quirk, too. It only tests that
a commit (which didn't receive bitmaps by default) is selected for
bitmaps after changing the value of 'pack.preferBitmapTips' to include
it. Other commits may lose their bitmaps as a byproduct of how the
selection process works (bitmap_writer_select_commits() ignores the
remainder of a window after seeing a commit with the NEEDS_BITMAP flag).

This configuration will aide in selecting important references for
multi-pack bitmaps, since they do not respect the same pack.islandCore
configuration. (They could, but doing so may be confusing, since it is
packs--not bitmaps--which are influenced by the delta-islands
configuration).

In a fork network repository (one which lists all forks of a given
repository as remotes), for example, it is useful to set
pack.preferBitmapTips to 'refs/remotes/<root>/heads' and
'refs/remotes/<root>/tags', where '<root>' is an opaque identifier
referring to the repository which is at the base of the fork chain.

Suggested-by: Jeff King <peff@peff.net>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/config/pack.txt
builtin/pack-objects.c
pack-bitmap.c
pack-bitmap.h
t/t5310-pack-bitmaps.sh

index 3da4ea98e2d4b11d0ff3534efd71ceddb93d9ea8..c0844d8d8e921fe297103e78b025923d54486f36 100644 (file)
@@ -122,6 +122,21 @@ pack.useSparse::
        commits contain certain types of direct renames. Default is
        `true`.
 
+pack.preferBitmapTips::
+       When selecting which commits will receive bitmaps, prefer a
+       commit at the tip of any reference that is a suffix of any value
+       of this configuration over any other commits in the "selection
+       window".
++
+Note that setting this configuration to `refs/foo` does not mean that
+the commits at the tips of `refs/foo/bar` and `refs/foo/baz` will
+necessarily be selected. This is because commits are selected for
+bitmaps from within a series of windows of variable length.
++
+If a commit at the tip of any reference which is a suffix of any value
+of this configuration is seen in a window, it is immediately given
+preference over any other commit in that window.
+
 pack.writeBitmaps (deprecated)::
        This is a deprecated synonym for `repack.writeBitmaps`.
 
index 525c2d85529f41bc56fb3495f9f7e9dec9557c81..a1e33d7507249741faaa46cf018b64c2fab82f46 100644 (file)
@@ -3547,6 +3547,37 @@ static void record_recent_commit(struct commit *commit, void *data)
        oid_array_append(&recent_objects, &commit->object.oid);
 }
 
+static int mark_bitmap_preferred_tip(const char *refname,
+                                    const struct object_id *oid, int flags,
+                                    void *_data)
+{
+       struct object_id peeled;
+       struct object *object;
+
+       if (!peel_iterated_oid(oid, &peeled))
+               oid = &peeled;
+
+       object = parse_object_or_die(oid, refname);
+       if (object->type == OBJ_COMMIT)
+               object->flags |= NEEDS_BITMAP;
+
+       return 0;
+}
+
+static void mark_bitmap_preferred_tips(void)
+{
+       struct string_list_item *item;
+       const struct string_list *preferred_tips;
+
+       preferred_tips = bitmap_preferred_tips(the_repository);
+       if (!preferred_tips)
+               return;
+
+       for_each_string_list_item(item, preferred_tips) {
+               for_each_ref_in(item->string, mark_bitmap_preferred_tip, NULL);
+       }
+}
+
 static void get_object_list(int ac, const char **av)
 {
        struct rev_info revs;
@@ -3601,6 +3632,9 @@ static void get_object_list(int ac, const char **av)
        if (use_delta_islands)
                load_delta_islands(the_repository, progress);
 
+       if (write_bitmap_index)
+               mark_bitmap_preferred_tips();
+
        if (prepare_revision_walk(&revs))
                die(_("revision walk setup failed"));
        mark_edges_uninteresting(&revs, show_edge, sparse);
index 7554510b140d4b4b366d4c4ea121a9e87d3451a2..bfe2943a9b9d6f5d82b56a2814449373eef374d5 100644 (file)
@@ -13,6 +13,7 @@
 #include "repository.h"
 #include "object-store.h"
 #include "list-objects-filter-options.h"
+#include "config.h"
 
 /*
  * An entry on the bitmap index, representing the bitmap for a given
@@ -1529,3 +1530,8 @@ off_t get_disk_usage_from_bitmap(struct bitmap_index *bitmap_git,
 
        return total;
 }
+
+const struct string_list *bitmap_preferred_tips(struct repository *r)
+{
+       return repo_config_get_value_multi(r, "pack.preferbitmaptips");
+}
index c3cdd80756ca401a8ee687a9d21a6f2137bcfb67..78f2b3ff792ecca6fd316cdeffffdcf174c79598 100644 (file)
@@ -5,6 +5,7 @@
 #include "khash.h"
 #include "pack.h"
 #include "pack-objects.h"
+#include "string-list.h"
 
 struct commit;
 struct repository;
@@ -91,4 +92,6 @@ void bitmap_writer_finish(struct pack_idx_entry **index,
                          const char *filename,
                          uint16_t options);
 
+const struct string_list *bitmap_preferred_tips(struct repository *r);
+
 #endif
index 40b9f632441446d5042100d2797e9dd80b17f643..f53efc8229b39a09303b0c31c09c30a247ae624e 100755 (executable)
@@ -554,4 +554,42 @@ test_expect_success 'fetch with bitmaps can reuse old base' '
        )
 '
 
+test_expect_success 'pack.preferBitmapTips' '
+       git init repo &&
+       test_when_finished "rm -fr repo" &&
+       (
+               cd repo &&
+
+               # create enough commits that not all are receive bitmap
+               # coverage even if they are all at the tip of some reference.
+               test_commit_bulk --message="%s" 103 &&
+
+               git rev-list HEAD >commits.raw &&
+               sort <commits.raw >commits &&
+
+               git log --format="create refs/tags/%s %H" HEAD >refs &&
+               git update-ref --stdin <refs &&
+
+               git repack -adb &&
+               test-tool bitmap list-commits | sort >bitmaps &&
+
+               # remember which commits did not receive bitmaps
+               comm -13 bitmaps commits >before &&
+               test_file_not_empty before &&
+
+               # mark the commits which did not receive bitmaps as preferred,
+               # and generate the bitmap again
+               perl -pe "s{^}{create refs/tags/include/$. }" <before |
+                       git update-ref --stdin &&
+               git -c pack.preferBitmapTips=refs/tags/include repack -adb &&
+
+               # finally, check that the commit(s) without bitmap coverage
+               # are not the same ones as before
+               test-tool bitmap list-commits | sort >bitmaps &&
+               comm -13 bitmaps commits >after &&
+
+               ! test_cmp before after
+       )
+'
+
 test_done