Imported Upstream version 2.27.0
[platform/upstream/git.git] / builtin / pack-objects.c
index 41d7fc5..c5b433a 100644 (file)
@@ -26,7 +26,7 @@
 #include "pack-bitmap.h"
 #include "delta-islands.h"
 #include "reachable.h"
-#include "sha1-array.h"
+#include "oid-array.h"
 #include "argv-array.h"
 #include "list.h"
 #include "packfile.h"
@@ -34,6 +34,7 @@
 #include "dir.h"
 #include "midx.h"
 #include "trace2.h"
+#include "shallow.h"
 
 #define IN_PACK(obj) oe_in_pack(&to_pack, obj)
 #define SIZE(obj) oe_size(&to_pack, obj)
@@ -92,11 +93,16 @@ static struct progress *progress_state;
 
 static struct packed_git *reuse_packfile;
 static uint32_t reuse_packfile_objects;
-static off_t reuse_packfile_offset;
+static struct bitmap *reuse_packfile_bitmap;
 
 static int use_bitmap_index_default = 1;
 static int use_bitmap_index = -1;
-static int write_bitmap_index;
+static int allow_pack_reuse = 1;
+static enum {
+       WRITE_BITMAP_FALSE = 0,
+       WRITE_BITMAP_QUIET,
+       WRITE_BITMAP_TRUE,
+} write_bitmap_index;
 static uint16_t write_bitmap_options = BITMAP_OPT_HASH_CACHE;
 
 static int exclude_promisor_objects;
@@ -159,7 +165,7 @@ static void *get_delta(struct object_entry *entry)
        delta_buf = diff_delta(base_buf, base_size,
                               buf, size, &delta_size, 0);
        /*
-        * We succesfully computed this delta once but dropped it for
+        * We successfully computed this delta once but dropped it for
         * memory reasons. Something is very wrong if this time we
         * recompute and create a different delta.
         */
@@ -299,7 +305,8 @@ static unsigned long write_no_reuse_object(struct hashfile *f, struct object_ent
        if (!usable_delta) {
                if (oe_type(entry) == OBJ_BLOB &&
                    oe_size_greater_than(&to_pack, entry, big_file_threshold) &&
-                   (st = open_istream(&entry->idx.oid, &type, &size, NULL)) != NULL)
+                   (st = open_istream(the_repository, &entry->idx.oid, &type,
+                                      &size, NULL)) != NULL)
                        buf = NULL;
                else {
                        buf = read_object_file(&entry->idx.oid, &type, &size);
@@ -606,12 +613,12 @@ static int mark_tagged(const char *path, const struct object_id *oid, int flag,
                       void *cb_data)
 {
        struct object_id peeled;
-       struct object_entry *entry = packlist_find(&to_pack, oid->hash, NULL);
+       struct object_entry *entry = packlist_find(&to_pack, oid);
 
        if (entry)
                entry->tagged = 1;
        if (!peel_ref(path, &peeled)) {
-               entry = packlist_find(&to_pack, peeled.hash, NULL);
+               entry = packlist_find(&to_pack, &peeled);
                if (entry)
                        entry->tagged = 1;
        }
@@ -780,57 +787,186 @@ static struct object_entry **compute_write_order(void)
        return wo;
 }
 
-static off_t write_reused_pack(struct hashfile *f)
+
+/*
+ * A reused set of objects. All objects in a chunk have the same
+ * relative position in the original packfile and the generated
+ * packfile.
+ */
+
+static struct reused_chunk {
+       /* The offset of the first object of this chunk in the original
+        * packfile. */
+       off_t original;
+       /* The offset of the first object of this chunk in the generated
+        * packfile minus "original". */
+       off_t difference;
+} *reused_chunks;
+static int reused_chunks_nr;
+static int reused_chunks_alloc;
+
+static void record_reused_object(off_t where, off_t offset)
+{
+       if (reused_chunks_nr && reused_chunks[reused_chunks_nr-1].difference == offset)
+               return;
+
+       ALLOC_GROW(reused_chunks, reused_chunks_nr + 1,
+                  reused_chunks_alloc);
+       reused_chunks[reused_chunks_nr].original = where;
+       reused_chunks[reused_chunks_nr].difference = offset;
+       reused_chunks_nr++;
+}
+
+/*
+ * Binary search to find the chunk that "where" is in. Note
+ * that we're not looking for an exact match, just the first
+ * chunk that contains it (which implicitly ends at the start
+ * of the next chunk.
+ */
+static off_t find_reused_offset(off_t where)
+{
+       int lo = 0, hi = reused_chunks_nr;
+       while (lo < hi) {
+               int mi = lo + ((hi - lo) / 2);
+               if (where == reused_chunks[mi].original)
+                       return reused_chunks[mi].difference;
+               if (where < reused_chunks[mi].original)
+                       hi = mi;
+               else
+                       lo = mi + 1;
+       }
+
+       /*
+        * The first chunk starts at zero, so we can't have gone below
+        * there.
+        */
+       assert(lo);
+       return reused_chunks[lo-1].difference;
+}
+
+static void write_reused_pack_one(size_t pos, struct hashfile *out,
+                                 struct pack_window **w_curs)
 {
-       unsigned char buffer[8192];
-       off_t to_write, total;
-       int fd;
+       off_t offset, next, cur;
+       enum object_type type;
+       unsigned long size;
 
-       if (!is_pack_valid(reuse_packfile))
-               die(_("packfile is invalid: %s"), reuse_packfile->pack_name);
+       offset = reuse_packfile->revindex[pos].offset;
+       next = reuse_packfile->revindex[pos + 1].offset;
 
-       fd = git_open(reuse_packfile->pack_name);
-       if (fd < 0)
-               die_errno(_("unable to open packfile for reuse: %s"),
-                         reuse_packfile->pack_name);
+       record_reused_object(offset, offset - hashfile_total(out));
 
-       if (lseek(fd, sizeof(struct pack_header), SEEK_SET) == -1)
-               die_errno(_("unable to seek in reused packfile"));
+       cur = offset;
+       type = unpack_object_header(reuse_packfile, w_curs, &cur, &size);
+       assert(type >= 0);
 
-       if (reuse_packfile_offset < 0)
-               reuse_packfile_offset = reuse_packfile->pack_size - the_hash_algo->rawsz;
+       if (type == OBJ_OFS_DELTA) {
+               off_t base_offset;
+               off_t fixup;
 
-       total = to_write = reuse_packfile_offset - sizeof(struct pack_header);
+               unsigned char header[MAX_PACK_OBJECT_HEADER];
+               unsigned len;
 
-       while (to_write) {
-               int read_pack = xread(fd, buffer, sizeof(buffer));
+               base_offset = get_delta_base(reuse_packfile, w_curs, &cur, type, offset);
+               assert(base_offset != 0);
 
-               if (read_pack <= 0)
-                       die_errno(_("unable to read from reused packfile"));
+               /* Convert to REF_DELTA if we must... */
+               if (!allow_ofs_delta) {
+                       int base_pos = find_revindex_position(reuse_packfile, base_offset);
+                       struct object_id base_oid;
 
-               if (read_pack > to_write)
-                       read_pack = to_write;
+                       nth_packed_object_id(&base_oid, reuse_packfile,
+                                            reuse_packfile->revindex[base_pos].nr);
 
-               hashwrite(f, buffer, read_pack);
-               to_write -= read_pack;
+                       len = encode_in_pack_object_header(header, sizeof(header),
+                                                          OBJ_REF_DELTA, size);
+                       hashwrite(out, header, len);
+                       hashwrite(out, base_oid.hash, the_hash_algo->rawsz);
+                       copy_pack_data(out, reuse_packfile, w_curs, cur, next - cur);
+                       return;
+               }
+
+               /* Otherwise see if we need to rewrite the offset... */
+               fixup = find_reused_offset(offset) -
+                       find_reused_offset(base_offset);
+               if (fixup) {
+                       unsigned char ofs_header[10];
+                       unsigned i, ofs_len;
+                       off_t ofs = offset - base_offset - fixup;
+
+                       len = encode_in_pack_object_header(header, sizeof(header),
+                                                          OBJ_OFS_DELTA, size);
+
+                       i = sizeof(ofs_header) - 1;
+                       ofs_header[i] = ofs & 127;
+                       while (ofs >>= 7)
+                               ofs_header[--i] = 128 | (--ofs & 127);
+
+                       ofs_len = sizeof(ofs_header) - i;
+
+                       hashwrite(out, header, len);
+                       hashwrite(out, ofs_header + sizeof(ofs_header) - ofs_len, ofs_len);
+                       copy_pack_data(out, reuse_packfile, w_curs, cur, next - cur);
+                       return;
+               }
+
+               /* ...otherwise we have no fixup, and can write it verbatim */
+       }
+
+       copy_pack_data(out, reuse_packfile, w_curs, offset, next - offset);
+}
+
+static size_t write_reused_pack_verbatim(struct hashfile *out,
+                                        struct pack_window **w_curs)
+{
+       size_t pos = 0;
+
+       while (pos < reuse_packfile_bitmap->word_alloc &&
+                       reuse_packfile_bitmap->words[pos] == (eword_t)~0)
+               pos++;
+
+       if (pos) {
+               off_t to_write;
+
+               written = (pos * BITS_IN_EWORD);
+               to_write = reuse_packfile->revindex[written].offset
+                       - sizeof(struct pack_header);
+
+               /* We're recording one chunk, not one object. */
+               record_reused_object(sizeof(struct pack_header), 0);
+               hashflush(out);
+               copy_pack_data(out, reuse_packfile, w_curs,
+                       sizeof(struct pack_header), to_write);
 
-               /*
-                * We don't know the actual number of objects written,
-                * only how many bytes written, how many bytes total, and
-                * how many objects total. So we can fake it by pretending all
-                * objects we are writing are the same size. This gives us a
-                * smooth progress meter, and at the end it matches the true
-                * answer.
-                */
-               written = reuse_packfile_objects *
-                               (((double)(total - to_write)) / total);
                display_progress(progress_state, written);
        }
+       return pos;
+}
+
+static void write_reused_pack(struct hashfile *f)
+{
+       size_t i = 0;
+       uint32_t offset;
+       struct pack_window *w_curs = NULL;
+
+       if (allow_ofs_delta)
+               i = write_reused_pack_verbatim(f, &w_curs);
+
+       for (; i < reuse_packfile_bitmap->word_alloc; ++i) {
+               eword_t word = reuse_packfile_bitmap->words[i];
+               size_t pos = (i * BITS_IN_EWORD);
+
+               for (offset = 0; offset < BITS_IN_EWORD; ++offset) {
+                       if ((word >> offset) == 0)
+                               break;
+
+                       offset += ewah_bit_ctz64(word >> offset);
+                       write_reused_pack_one(pos + offset, f, &w_curs);
+                       display_progress(progress_state, ++written);
+               }
+       }
 
-       close(fd);
-       written = reuse_packfile_objects;
-       display_progress(progress_state, written);
-       return reuse_packfile_offset - sizeof(struct pack_header);
+       unuse_pack(&w_curs);
 }
 
 static const char no_split_warning[] = N_(
@@ -863,11 +999,9 @@ static void write_pack_file(void)
                offset = write_pack_header(f, nr_remaining);
 
                if (reuse_packfile) {
-                       off_t packfile_size;
                        assert(pack_to_stdout);
-
-                       packfile_size = write_reused_pack(f);
-                       offset += packfile_size;
+                       write_reused_pack(f);
+                       offset = hashfile_total(f);
                }
 
                nr_written = 0;
@@ -892,7 +1026,8 @@ static void write_pack_file(void)
                                                 nr_written, oid.hash, offset);
                        close(fd);
                        if (write_bitmap_index) {
-                               warning(_(no_split_warning));
+                               if (write_bitmap_index != WRITE_BITMAP_QUIET)
+                                       warning(_(no_split_warning));
                                write_bitmap_index = 0;
                        }
                }
@@ -991,12 +1126,15 @@ static int no_try_delta(const char *path)
  * few lines later when we want to add the new entry.
  */
 static int have_duplicate_entry(const struct object_id *oid,
-                               int exclude,
-                               uint32_t *index_pos)
+                               int exclude)
 {
        struct object_entry *entry;
 
-       entry = packlist_find(&to_pack, oid->hash, index_pos);
+       if (reuse_packfile_bitmap &&
+           bitmap_walk_contains(bitmap_git, reuse_packfile_bitmap, oid))
+               return 1;
+
+       entry = packlist_find(&to_pack, oid);
        if (!entry)
                return 0;
 
@@ -1136,13 +1274,12 @@ static void create_object_entry(const struct object_id *oid,
                                uint32_t hash,
                                int exclude,
                                int no_try_delta,
-                               uint32_t index_pos,
                                struct packed_git *found_pack,
                                off_t found_offset)
 {
        struct object_entry *entry;
 
-       entry = packlist_alloc(&to_pack, oid->hash, index_pos);
+       entry = packlist_alloc(&to_pack, oid);
        entry->hash = hash;
        oe_set_type(entry, type);
        if (exclude)
@@ -1166,17 +1303,17 @@ static int add_object_entry(const struct object_id *oid, enum object_type type,
 {
        struct packed_git *found_pack = NULL;
        off_t found_offset = 0;
-       uint32_t index_pos;
 
        display_progress(progress_state, ++nr_seen);
 
-       if (have_duplicate_entry(oid, exclude, &index_pos))
+       if (have_duplicate_entry(oid, exclude))
                return 0;
 
        if (!want_object_in_pack(oid, exclude, &found_pack, &found_offset)) {
                /* The pack is missing an object, so it will not have closure */
                if (write_bitmap_index) {
-                       warning(_(no_closure_warning));
+                       if (write_bitmap_index != WRITE_BITMAP_QUIET)
+                               warning(_(no_closure_warning));
                        write_bitmap_index = 0;
                }
                return 0;
@@ -1184,7 +1321,7 @@ static int add_object_entry(const struct object_id *oid, enum object_type type,
 
        create_object_entry(oid, type, pack_name_hash(name),
                            exclude, name && no_try_delta(name),
-                           index_pos, found_pack, found_offset);
+                           found_pack, found_offset);
        return 1;
 }
 
@@ -1193,17 +1330,15 @@ static int add_object_entry_from_bitmap(const struct object_id *oid,
                                        int flags, uint32_t name_hash,
                                        struct packed_git *pack, off_t offset)
 {
-       uint32_t index_pos;
-
        display_progress(progress_state, ++nr_seen);
 
-       if (have_duplicate_entry(oid, 0, &index_pos))
+       if (have_duplicate_entry(oid, 0))
                return 0;
 
        if (!want_object_in_pack(oid, 0, &pack, &offset))
                return 0;
 
-       create_object_entry(oid, type, name_hash, 0, 0, index_pos, pack, offset);
+       create_object_entry(oid, type, name_hash, 0, 0, pack, offset);
        return 1;
 }
 
@@ -1428,7 +1563,8 @@ static void add_preferred_base(struct object_id *oid)
        if (window <= num_preferred_base++)
                return;
 
-       data = read_object_with_reference(oid, tree_type, &size, &tree_oid);
+       data = read_object_with_reference(the_repository, oid,
+                                         tree_type, &size, &tree_oid);
        if (!data)
                return;
 
@@ -1484,21 +1620,17 @@ static void cleanup_preferred_base(void)
  * deltify other objects against, in order to avoid
  * circular deltas.
  */
-static int can_reuse_delta(const unsigned char *base_sha1,
+static int can_reuse_delta(const struct object_id *base_oid,
                           struct object_entry *delta,
                           struct object_entry **base_out)
 {
        struct object_entry *base;
-       struct object_id base_oid;
-
-       if (!base_sha1)
-               return 0;
 
        /*
         * First see if we're already sending the base (or it's explicitly in
         * our "excluded" list).
         */
-       base = packlist_find(&to_pack, base_sha1, NULL);
+       base = packlist_find(&to_pack, base_oid);
        if (base) {
                if (!in_same_island(&delta->idx.oid, &base->idx.oid))
                        return 0;
@@ -1511,10 +1643,9 @@ static int can_reuse_delta(const unsigned char *base_sha1,
         * even if it was buried too deep in history to make it into the
         * packing list.
         */
-       oidread(&base_oid, base_sha1);
-       if (thin && bitmap_has_oid_in_uninteresting(bitmap_git, &base_oid)) {
+       if (thin && bitmap_has_oid_in_uninteresting(bitmap_git, base_oid)) {
                if (use_delta_islands) {
-                       if (!in_same_island(&delta->idx.oid, &base_oid))
+                       if (!in_same_island(&delta->idx.oid, base_oid))
                                return 0;
                }
                *base_out = NULL;
@@ -1531,7 +1662,8 @@ static void check_object(struct object_entry *entry)
        if (IN_PACK(entry)) {
                struct packed_git *p = IN_PACK(entry);
                struct pack_window *w_curs = NULL;
-               const unsigned char *base_ref = NULL;
+               int have_base = 0;
+               struct object_id base_ref;
                struct object_entry *base_entry;
                unsigned long used, used_0;
                unsigned long avail;
@@ -1572,9 +1704,13 @@ static void check_object(struct object_entry *entry)
                        unuse_pack(&w_curs);
                        return;
                case OBJ_REF_DELTA:
-                       if (reuse_delta && !entry->preferred_base)
-                               base_ref = use_pack(p, &w_curs,
-                                               entry->in_pack_offset + used, NULL);
+                       if (reuse_delta && !entry->preferred_base) {
+                               oidread(&base_ref,
+                                       use_pack(p, &w_curs,
+                                                entry->in_pack_offset + used,
+                                                NULL));
+                               have_base = 1;
+                       }
                        entry->in_pack_header_size = used + the_hash_algo->rawsz;
                        break;
                case OBJ_OFS_DELTA:
@@ -1604,13 +1740,15 @@ static void check_object(struct object_entry *entry)
                                revidx = find_pack_revindex(p, ofs);
                                if (!revidx)
                                        goto give_up;
-                               base_ref = nth_packed_object_sha1(p, revidx->nr);
+                               if (!nth_packed_object_id(&base_ref, p, revidx->nr))
+                                       have_base = 1;
                        }
                        entry->in_pack_header_size = used + used_0;
                        break;
                }
 
-               if (can_reuse_delta(base_ref, entry, &base_entry)) {
+               if (have_base &&
+                   can_reuse_delta(&base_ref, entry, &base_entry)) {
                        oe_set_type(entry, entry->in_pack_type);
                        SET_SIZE(entry, in_pack_size); /* delta size */
                        SET_DELTA_SIZE(entry, in_pack_size);
@@ -1620,7 +1758,7 @@ static void check_object(struct object_entry *entry)
                                entry->delta_sibling_idx = base_entry->delta_child_idx;
                                SET_DELTA_CHILD(base_entry, entry);
                        } else {
-                               SET_DELTA_EXT(entry, base_ref);
+                               SET_DELTA_EXT(entry, &base_ref);
                        }
 
                        unuse_pack(&w_curs);
@@ -2334,15 +2472,6 @@ static void find_deltas(struct object_entry **list, unsigned *list_size,
        free(array);
 }
 
-static void try_to_free_from_threads(size_t size)
-{
-       packing_data_lock(&to_pack);
-       release_pack_memory(size);
-       packing_data_unlock(&to_pack);
-}
-
-static try_to_free_t old_try_to_free_routine;
-
 /*
  * The main object list is split into smaller lists, each is handed to
  * one worker.
@@ -2383,12 +2512,10 @@ static void init_threaded_search(void)
        pthread_mutex_init(&cache_mutex, NULL);
        pthread_mutex_init(&progress_mutex, NULL);
        pthread_cond_init(&progress_cond, NULL);
-       old_try_to_free_routine = set_try_to_free_routine(try_to_free_from_threads);
 }
 
 static void cleanup_threaded_search(void)
 {
-       set_try_to_free_routine(old_try_to_free_routine);
        pthread_cond_destroy(&progress_cond);
        pthread_mutex_destroy(&cache_mutex);
        pthread_mutex_destroy(&progress_mutex);
@@ -2560,6 +2687,13 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size,
        free(p);
 }
 
+static int obj_is_packed(const struct object_id *oid)
+{
+       return packlist_find(&to_pack, oid) ||
+               (reuse_packfile_bitmap &&
+                bitmap_walk_contains(bitmap_git, reuse_packfile_bitmap, oid));
+}
+
 static void add_tag_chain(const struct object_id *oid)
 {
        struct tag *tag;
@@ -2571,7 +2705,7 @@ static void add_tag_chain(const struct object_id *oid)
         * it was included via bitmaps, we would not have parsed it
         * previously).
         */
-       if (packlist_find(&to_pack, oid->hash, NULL))
+       if (obj_is_packed(oid))
                return;
 
        tag = lookup_tag(the_repository, oid);
@@ -2595,7 +2729,7 @@ static int add_ref_tag(const char *path, const struct object_id *oid, int flag,
 
        if (starts_with(path, "refs/tags/") && /* is a tag? */
            !peel_ref(path, &peeled)    && /* peelable? */
-           packlist_find(&to_pack, peeled.hash, NULL))      /* object packed? */
+           obj_is_packed(&peeled)) /* object packed? */
                add_tag_chain(oid);
        return 0;
 }
@@ -2663,6 +2797,7 @@ static void prepare_pack(int window, int depth)
 
        if (nr_deltas && n > 1) {
                unsigned nr_done = 0;
+
                if (progress)
                        progress_state = start_progress(_("Compressing objects"),
                                                        nr_deltas);
@@ -2707,8 +2842,8 @@ static int git_pack_config(const char *k, const char *v, void *cb)
                use_bitmap_index_default = git_config_bool(k, v);
                return 0;
        }
-       if (!strcmp(k, "pack.usesparse")) {
-               sparse = git_config_bool(k, v);
+       if (!strcmp(k, "pack.allowpackreuse")) {
+               allow_pack_reuse = git_config_bool(k, v);
                return 0;
        }
        if (!strcmp(k, "pack.threads")) {
@@ -2795,7 +2930,7 @@ static void show_object(struct object *obj, const char *name, void *data)
                for (p = strchr(name, '/'); p; p = strchr(p + 1, '/'))
                        depth++;
 
-               ent = packlist_find(&to_pack, obj->oid.hash, NULL);
+               ent = packlist_find(&to_pack, &obj->oid);
                if (ent && depth > oe_tree_depth(&to_pack, ent))
                        oe_set_tree_depth(&to_pack, ent, depth);
        }
@@ -2899,7 +3034,7 @@ static int ofscmp(const void *a_, const void *b_)
                return oidcmp(&a->object->oid, &b->object->oid);
 }
 
-static void add_objects_in_unpacked_packs(struct rev_info *revs)
+static void add_objects_in_unpacked_packs(void)
 {
        struct packed_git *p;
        struct in_pack in_pack;
@@ -2921,8 +3056,8 @@ static void add_objects_in_unpacked_packs(struct rev_info *revs)
                           in_pack.alloc);
 
                for (i = 0; i < p->num_objects; i++) {
-                       nth_packed_object_oid(&oid, p, i);
-                       o = lookup_unknown_object(oid.hash);
+                       nth_packed_object_id(&oid, p, i);
+                       o = lookup_unknown_object(&oid);
                        if (!(o->flags & OBJECT_ADDED))
                                mark_in_pack_object(o, p, &in_pack);
                        o->flags |= OBJECT_ADDED;
@@ -3011,7 +3146,7 @@ static int loosened_object_can_be_discarded(const struct object_id *oid,
        return 1;
 }
 
-static void loosen_unused_packed_objects(struct rev_info *revs)
+static void loosen_unused_packed_objects(void)
 {
        struct packed_git *p;
        uint32_t i;
@@ -3025,8 +3160,8 @@ static void loosen_unused_packed_objects(struct rev_info *revs)
                        die(_("cannot open pack index"));
 
                for (i = 0; i < p->num_objects; i++) {
-                       nth_packed_object_oid(&oid, p, i);
-                       if (!packlist_find(&to_pack, oid.hash, NULL) &&
+                       nth_packed_object_id(&oid, p, i);
+                       if (!packlist_find(&to_pack, &oid) &&
                            !has_sha1_pack_kept_or_nonlocal(&oid) &&
                            !loosened_object_can_be_discarded(&oid, p->mtime))
                                if (force_object_loose(&oid, p->mtime))
@@ -3042,8 +3177,8 @@ static void loosen_unused_packed_objects(struct rev_info *revs)
  */
 static int pack_options_allow_reuse(void)
 {
-       return pack_to_stdout &&
-              allow_ofs_delta &&
+       return allow_pack_reuse &&
+              pack_to_stdout &&
               !ignore_packed_keep_on_disk &&
               !ignore_packed_keep_in_core &&
               (!local || !have_non_local_packs) &&
@@ -3052,7 +3187,7 @@ static int pack_options_allow_reuse(void)
 
 static int get_object_list_from_bitmap(struct rev_info *revs)
 {
-       if (!(bitmap_git = prepare_bitmap_walk(revs)))
+       if (!(bitmap_git = prepare_bitmap_walk(revs, &filter_options)))
                return -1;
 
        if (pack_options_allow_reuse() &&
@@ -3060,13 +3195,14 @@ static int get_object_list_from_bitmap(struct rev_info *revs)
                        bitmap_git,
                        &reuse_packfile,
                        &reuse_packfile_objects,
-                       &reuse_packfile_offset)) {
+                       &reuse_packfile_bitmap)) {
                assert(reuse_packfile_objects);
                nr_result += reuse_packfile_objects;
                display_progress(progress_state, nr_result);
        }
 
-       traverse_bitmap_commit_list(bitmap_git, &add_object_entry_from_bitmap);
+       traverse_bitmap_commit_list(bitmap_git, revs,
+                                   &add_object_entry_from_bitmap);
        return 0;
 }
 
@@ -3134,7 +3270,7 @@ static void get_object_list(int ac, const char **av)
                return;
 
        if (use_delta_islands)
-               load_delta_islands(the_repository);
+               load_delta_islands(the_repository, progress);
 
        if (prepare_revision_walk(&revs))
                die(_("revision walk setup failed"));
@@ -3158,11 +3294,11 @@ static void get_object_list(int ac, const char **av)
        }
 
        if (keep_unreachable)
-               add_objects_in_unpacked_packs(&revs);
+               add_objects_in_unpacked_packs();
        if (pack_loose_unreachable)
                add_unreachable_loose_objects();
        if (unpack_unreachable)
-               loosen_unused_packed_objects(&revs);
+               loosen_unused_packed_objects();
 
        oid_array_clear(&recent_objects);
 }
@@ -3245,9 +3381,9 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
                OPT_BOOL(0, "all-progress-implied",
                         &all_progress_implied,
                         N_("similar to --all-progress when progress meter is shown")),
-               { OPTION_CALLBACK, 0, "index-version", NULL, N_("<version>[,<offset>]"),
+               OPT_CALLBACK_F(0, "index-version", NULL, N_("<version>[,<offset>]"),
                  N_("write the pack index file in the specified idx format version"),
-                 PARSE_OPT_NONEG, option_parse_index_version },
+                 PARSE_OPT_NONEG, option_parse_index_version),
                OPT_MAGNITUDE(0, "max-pack-size", &pack_size_limit,
                              N_("maximum size of each output pack file")),
                OPT_BOOL(0, "local", &local,
@@ -3292,9 +3428,9 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
                         N_("keep unreachable objects")),
                OPT_BOOL(0, "pack-loose-unreachable", &pack_loose_unreachable,
                         N_("pack loose unreachable objects")),
-               { OPTION_CALLBACK, 0, "unpack-unreachable", NULL, N_("time"),
+               OPT_CALLBACK_F(0, "unpack-unreachable", NULL, N_("time"),
                  N_("unpack unreachable objects newer than <time>"),
-                 PARSE_OPT_OPTARG, option_parse_unpack_unreachable },
+                 PARSE_OPT_OPTARG, option_parse_unpack_unreachable),
                OPT_BOOL(0, "sparse", &sparse,
                         N_("use the sparse reachability algorithm")),
                OPT_BOOL(0, "thin", &thin,
@@ -3311,12 +3447,17 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
                            N_("do not hide commits by grafts"), 0),
                OPT_BOOL(0, "use-bitmap-index", &use_bitmap_index,
                         N_("use a bitmap index if available to speed up counting objects")),
-               OPT_BOOL(0, "write-bitmap-index", &write_bitmap_index,
-                        N_("write a bitmap index together with the pack index")),
+               OPT_SET_INT(0, "write-bitmap-index", &write_bitmap_index,
+                           N_("write a bitmap index together with the pack index"),
+                           WRITE_BITMAP_TRUE),
+               OPT_SET_INT_F(0, "write-bitmap-index-quiet",
+                             &write_bitmap_index,
+                             N_("write a bitmap index if possible"),
+                             WRITE_BITMAP_QUIET, PARSE_OPT_HIDDEN),
                OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
-               { OPTION_CALLBACK, 0, "missing", NULL, N_("action"),
+               OPT_CALLBACK_F(0, "missing", NULL, N_("action"),
                  N_("handling for missing objects"), PARSE_OPT_NONEG,
-                 option_parse_missing_action },
+                 option_parse_missing_action),
                OPT_BOOL(0, "exclude-promisor-objects", &exclude_promisor_objects,
                         N_("do not pack objects in promisor packfiles")),
                OPT_BOOL(0, "delta-islands", &use_delta_islands,
@@ -3329,7 +3470,11 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
 
        read_replace_refs = 0;
 
-       sparse = git_env_bool("GIT_TEST_PACK_SPARSE", 0);
+       sparse = git_env_bool("GIT_TEST_PACK_SPARSE", -1);
+       prepare_repo_settings(the_repository);
+       if (sparse < 0)
+               sparse = the_repository->settings.pack_use_sparse;
+
        reset_pack_idx_option(&pack_idx_opts);
        git_config(git_pack_config, NULL);
 
@@ -3421,7 +3566,6 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
        if (filter_options.choice) {
                if (!pack_to_stdout)
                        die(_("cannot use --filter without --stdout"));
-               use_bitmap_index = 0;
        }
 
        /*
@@ -3512,7 +3656,9 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
        if (progress)
                fprintf_ln(stderr,
                           _("Total %"PRIu32" (delta %"PRIu32"),"
-                            " reused %"PRIu32" (delta %"PRIu32")"),
-                          written, written_delta, reused, reused_delta);
+                            " reused %"PRIu32" (delta %"PRIu32"),"
+                            " pack-reused %"PRIu32),
+                          written, written_delta, reused, reused_delta,
+                          reuse_packfile_objects);
        return 0;
 }