]> git.ipfire.org Git - thirdparty/git.git/blobdiff - pack-bitmap.c
entry: check for fstat() errors after checkout
[thirdparty/git.git] / pack-bitmap.c
index f0a1937a1cc5fbb13fc705df8d193a43a0648198..49a8d10d0cf99716ea37b78bec578ca96c17de20 100644 (file)
 #include "packfile.h"
 #include "repository.h"
 #include "object-store.h"
+#include "list-objects-filter-options.h"
 
 /*
  * An entry on the bitmap index, representing the bitmap for a given
  * commit.
  */
 struct stored_bitmap {
-       unsigned char sha1[20];
+       struct object_id oid;
        struct ewah_bitmap *root;
        struct stored_bitmap *xor;
        int flags;
@@ -60,8 +61,8 @@ struct bitmap_index {
        struct ewah_bitmap *blobs;
        struct ewah_bitmap *tags;
 
-       /* Map from SHA1 -> `stored_bitmap` for all the bitmapped commits */
-       khash_sha1 *bitmaps;
+       /* Map from object ID -> `stored_bitmap` for all the bitmapped commits */
+       kh_oid_map_t *bitmaps;
 
        /* Number of bitmapped commits */
        uint32_t entry_count;
@@ -80,16 +81,17 @@ struct bitmap_index {
                struct object **objects;
                uint32_t *hashes;
                uint32_t count, alloc;
-               khash_sha1_pos *positions;
+               kh_oid_pos_t *positions;
        } ext_index;
 
        /* Bitmap result of the last performed walk */
        struct bitmap *result;
 
+       /* "have" bitmap from the last performed walk */
+       struct bitmap *haves;
+
        /* Version of the bitmap index */
        unsigned int version;
-
-       unsigned loaded : 1;
 };
 
 static struct ewah_bitmap *lookup_stored_bitmap(struct stored_bitmap *st)
@@ -137,7 +139,7 @@ static int load_bitmap_header(struct bitmap_index *index)
 {
        struct bitmap_disk_header *header = (void *)index->map;
 
-       if (index->map_size < sizeof(*header) + 20)
+       if (index->map_size < sizeof(*header) + the_hash_algo->rawsz)
                return error("Corrupted bitmap index (missing header data)");
 
        if (memcmp(header->magic, BITMAP_IDX_SIGNATURE, sizeof(BITMAP_IDX_SIGNATURE)) != 0)
@@ -156,19 +158,19 @@ static int load_bitmap_header(struct bitmap_index *index)
                                "(Git requires BITMAP_OPT_FULL_DAG)");
 
                if (flags & BITMAP_OPT_HASH_CACHE) {
-                       unsigned char *end = index->map + index->map_size - 20;
+                       unsigned char *end = index->map + index->map_size - the_hash_algo->rawsz;
                        index->hashes = ((uint32_t *)end) - index->pack->num_objects;
                }
        }
 
        index->entry_count = ntohl(header->entry_count);
-       index->map_pos += sizeof(*header);
+       index->map_pos += sizeof(*header) - GIT_MAX_RAWSZ + the_hash_algo->rawsz;
        return 0;
 }
 
 static struct stored_bitmap *store_bitmap(struct bitmap_index *index,
                                          struct ewah_bitmap *root,
-                                         const unsigned char *sha1,
+                                         const struct object_id *oid,
                                          struct stored_bitmap *xor_with,
                                          int flags)
 {
@@ -180,15 +182,15 @@ static struct stored_bitmap *store_bitmap(struct bitmap_index *index,
        stored->root = root;
        stored->xor = xor_with;
        stored->flags = flags;
-       hashcpy(stored->sha1, sha1);
+       oidcpy(&stored->oid, oid);
 
-       hash_pos = kh_put_sha1(index->bitmaps, stored->sha1, &ret);
+       hash_pos = kh_put_oid_map(index->bitmaps, stored->oid, &ret);
 
        /* a 0 return code means the insertion succeeded with no changes,
         * because the SHA1 already existed on the map. this is bad, there
         * shouldn't be duplicated commits in the index */
        if (ret == 0) {
-               error("Duplicate entry in bitmap index: %s", sha1_to_hex(sha1));
+               error("Duplicate entry in bitmap index: %s", oid_to_hex(oid));
                return NULL;
        }
 
@@ -220,13 +222,13 @@ static int load_bitmap_entries_v1(struct bitmap_index *index)
                struct ewah_bitmap *bitmap = NULL;
                struct stored_bitmap *xor_bitmap = NULL;
                uint32_t commit_idx_pos;
-               const unsigned char *sha1;
+               struct object_id oid;
 
                commit_idx_pos = read_be32(index->map, &index->map_pos);
                xor_offset = read_u8(index->map, &index->map_pos);
                flags = read_u8(index->map, &index->map_pos);
 
-               sha1 = nth_packed_object_sha1(index->pack, commit_idx_pos);
+               nth_packed_object_id(&oid, index->pack, commit_idx_pos);
 
                bitmap = read_bitmap_1(index);
                if (!bitmap)
@@ -243,7 +245,7 @@ static int load_bitmap_entries_v1(struct bitmap_index *index)
                }
 
                recent_bitmaps[i % MAX_XOR_OFFSET] = store_bitmap(
-                       index, bitmap, sha1, xor_bitmap, flags);
+                       index, bitmap, &oid, xor_bitmap, flags);
        }
 
        return 0;
@@ -303,11 +305,12 @@ static int open_pack_bitmap_1(struct bitmap_index *bitmap_git, struct packed_git
 
 static int load_pack_bitmap(struct bitmap_index *bitmap_git)
 {
-       assert(bitmap_git->map && !bitmap_git->loaded);
+       assert(bitmap_git->map);
 
-       bitmap_git->bitmaps = kh_init_sha1();
-       bitmap_git->ext_index.positions = kh_init_sha1_pos();
-       load_pack_revindex(bitmap_git->pack);
+       bitmap_git->bitmaps = kh_init_oid_map();
+       bitmap_git->ext_index.positions = kh_init_oid_pos();
+       if (load_pack_revindex(bitmap_git->pack))
+               goto failed;
 
        if (!(bitmap_git->commits = read_bitmap_1(bitmap_git)) ||
                !(bitmap_git->trees = read_bitmap_1(bitmap_git)) ||
@@ -318,24 +321,31 @@ static int load_pack_bitmap(struct bitmap_index *bitmap_git)
        if (load_bitmap_entries_v1(bitmap_git) < 0)
                goto failed;
 
-       bitmap_git->loaded = 1;
        return 0;
 
 failed:
        munmap(bitmap_git->map, bitmap_git->map_size);
        bitmap_git->map = NULL;
        bitmap_git->map_size = 0;
+
+       kh_destroy_oid_map(bitmap_git->bitmaps);
+       bitmap_git->bitmaps = NULL;
+
+       kh_destroy_oid_pos(bitmap_git->ext_index.positions);
+       bitmap_git->ext_index.positions = NULL;
+
        return -1;
 }
 
-static int open_pack_bitmap(struct bitmap_index *bitmap_git)
+static int open_pack_bitmap(struct repository *r,
+                           struct bitmap_index *bitmap_git)
 {
        struct packed_git *p;
        int ret = -1;
 
-       assert(!bitmap_git->map && !bitmap_git->loaded);
+       assert(!bitmap_git->map);
 
-       for (p = get_packed_git(the_repository); p; p = p->next) {
+       for (p = get_all_packs(r); p; p = p->next) {
                if (open_pack_bitmap_1(bitmap_git, p) == 0)
                        ret = 0;
        }
@@ -343,11 +353,11 @@ static int open_pack_bitmap(struct bitmap_index *bitmap_git)
        return ret;
 }
 
-struct bitmap_index *prepare_bitmap_git(void)
+struct bitmap_index *prepare_bitmap_git(struct repository *r)
 {
        struct bitmap_index *bitmap_git = xcalloc(1, sizeof(*bitmap_git));
 
-       if (!open_pack_bitmap(bitmap_git) && !load_pack_bitmap(bitmap_git))
+       if (!open_pack_bitmap(r, bitmap_git) && !load_pack_bitmap(bitmap_git))
                return bitmap_git;
 
        free_bitmap_index(bitmap_git);
@@ -361,10 +371,10 @@ struct include_data {
 };
 
 static inline int bitmap_position_extended(struct bitmap_index *bitmap_git,
-                                          const unsigned char *sha1)
+                                          const struct object_id *oid)
 {
-       khash_sha1_pos *positions = bitmap_git->ext_index.positions;
-       khiter_t pos = kh_get_sha1_pos(positions, sha1);
+       kh_oid_pos_t *positions = bitmap_git->ext_index.positions;
+       khiter_t pos = kh_get_oid_pos(positions, *oid);
 
        if (pos < kh_end(positions)) {
                int bitmap_pos = kh_value(positions, pos);
@@ -375,9 +385,9 @@ static inline int bitmap_position_extended(struct bitmap_index *bitmap_git,
 }
 
 static inline int bitmap_position_packfile(struct bitmap_index *bitmap_git,
-                                          const unsigned char *sha1)
+                                          const struct object_id *oid)
 {
-       off_t offset = find_pack_entry_one(sha1, bitmap_git->pack);
+       off_t offset = find_pack_entry_one(oid->hash, bitmap_git->pack);
        if (!offset)
                return -1;
 
@@ -385,10 +395,10 @@ static inline int bitmap_position_packfile(struct bitmap_index *bitmap_git,
 }
 
 static int bitmap_position(struct bitmap_index *bitmap_git,
-                          const unsigned char *sha1)
+                          const struct object_id *oid)
 {
-       int pos = bitmap_position_packfile(bitmap_git, sha1);
-       return (pos >= 0) ? pos : bitmap_position_extended(bitmap_git, sha1);
+       int pos = bitmap_position_packfile(bitmap_git, oid);
+       return (pos >= 0) ? pos : bitmap_position_extended(bitmap_git, oid);
 }
 
 static int ext_index_add_object(struct bitmap_index *bitmap_git,
@@ -400,7 +410,7 @@ static int ext_index_add_object(struct bitmap_index *bitmap_git,
        int hash_ret;
        int bitmap_pos;
 
-       hash_pos = kh_put_sha1_pos(eindex->positions, object->oid.hash, &hash_ret);
+       hash_pos = kh_put_oid_pos(eindex->positions, object->oid, &hash_ret);
        if (hash_ret > 0) {
                if (eindex->count >= eindex->alloc) {
                        eindex->alloc = (eindex->alloc + 16) * 3 / 2;
@@ -430,7 +440,7 @@ static void show_object(struct object *object, const char *name, void *data_)
        struct bitmap_show_data *data = data_;
        int bitmap_pos;
 
-       bitmap_pos = bitmap_position(data->bitmap_git, object->oid.hash);
+       bitmap_pos = bitmap_position(data->bitmap_git, &object->oid);
 
        if (bitmap_pos < 0)
                bitmap_pos = ext_index_add_object(data->bitmap_git, object,
@@ -445,7 +455,7 @@ static void show_commit(struct commit *commit, void *data)
 
 static int add_to_include_set(struct bitmap_index *bitmap_git,
                              struct include_data *data,
-                             const unsigned char *sha1,
+                             const struct object_id *oid,
                              int bitmap_pos)
 {
        khiter_t hash_pos;
@@ -456,7 +466,7 @@ static int add_to_include_set(struct bitmap_index *bitmap_git,
        if (bitmap_get(data->base, bitmap_pos))
                return 0;
 
-       hash_pos = kh_get_sha1(bitmap_git->bitmaps, sha1);
+       hash_pos = kh_get_oid_map(bitmap_git->bitmaps, *oid);
        if (hash_pos < kh_end(bitmap_git->bitmaps)) {
                struct stored_bitmap *st = kh_value(bitmap_git->bitmaps, hash_pos);
                bitmap_or_ewah(data->base, lookup_stored_bitmap(st));
@@ -472,13 +482,13 @@ static int should_include(struct commit *commit, void *_data)
        struct include_data *data = _data;
        int bitmap_pos;
 
-       bitmap_pos = bitmap_position(data->bitmap_git, commit->object.oid.hash);
+       bitmap_pos = bitmap_position(data->bitmap_git, &commit->object.oid);
        if (bitmap_pos < 0)
                bitmap_pos = ext_index_add_object(data->bitmap_git,
                                                  (struct object *)commit,
                                                  NULL);
 
-       if (!add_to_include_set(data->bitmap_git, data, commit->object.oid.hash,
+       if (!add_to_include_set(data->bitmap_git, data, &commit->object.oid,
                                bitmap_pos)) {
                struct commit_list *parent = commit->parents;
 
@@ -516,7 +526,7 @@ static struct bitmap *find_objects(struct bitmap_index *bitmap_git,
                roots = roots->next;
 
                if (object->type == OBJ_COMMIT) {
-                       khiter_t pos = kh_get_sha1(bitmap_git->bitmaps, object->oid.hash);
+                       khiter_t pos = kh_get_oid_map(bitmap_git->bitmaps, object->oid);
 
                        if (pos < kh_end(bitmap_git->bitmaps)) {
                                struct stored_bitmap *st = kh_value(bitmap_git->bitmaps, pos);
@@ -558,7 +568,7 @@ static struct bitmap *find_objects(struct bitmap_index *bitmap_git,
                int pos;
 
                roots = roots->next;
-               pos = bitmap_position(bitmap_git, object->oid.hash);
+               pos = bitmap_position(bitmap_git, &object->oid);
 
                if (pos < 0 || base == NULL || !bitmap_get(base, pos)) {
                        object->flags &= ~UNINTERESTING;
@@ -597,6 +607,7 @@ static struct bitmap *find_objects(struct bitmap_index *bitmap_git,
 }
 
 static void show_extended_objects(struct bitmap_index *bitmap_git,
+                                 struct rev_info *revs,
                                  show_reachable_fn show_reach)
 {
        struct bitmap *objects = bitmap_git->result;
@@ -610,17 +621,48 @@ static void show_extended_objects(struct bitmap_index *bitmap_git,
                        continue;
 
                obj = eindex->objects[i];
+               if ((obj->type == OBJ_BLOB && !revs->blob_objects) ||
+                   (obj->type == OBJ_TREE && !revs->tree_objects) ||
+                   (obj->type == OBJ_TAG && !revs->tag_objects))
+                       continue;
+
                show_reach(&obj->oid, obj->type, 0, eindex->hashes[i], NULL, 0);
        }
 }
 
+static void init_type_iterator(struct ewah_iterator *it,
+                              struct bitmap_index *bitmap_git,
+                              enum object_type type)
+{
+       switch (type) {
+       case OBJ_COMMIT:
+               ewah_iterator_init(it, bitmap_git->commits);
+               break;
+
+       case OBJ_TREE:
+               ewah_iterator_init(it, bitmap_git->trees);
+               break;
+
+       case OBJ_BLOB:
+               ewah_iterator_init(it, bitmap_git->blobs);
+               break;
+
+       case OBJ_TAG:
+               ewah_iterator_init(it, bitmap_git->tags);
+               break;
+
+       default:
+               BUG("object type %d not stored by bitmap type index", type);
+               break;
+       }
+}
+
 static void show_objects_for_type(
        struct bitmap_index *bitmap_git,
-       struct ewah_bitmap *type_filter,
        enum object_type object_type,
        show_reachable_fn show_reach)
 {
-       size_t pos = 0, i = 0;
+       size_t i = 0;
        uint32_t offset;
 
        struct ewah_iterator it;
@@ -628,13 +670,15 @@ static void show_objects_for_type(
 
        struct bitmap *objects = bitmap_git->result;
 
-       if (bitmap_git->reuse_objects == bitmap_git->pack->num_objects)
-               return;
+       init_type_iterator(&it, bitmap_git, object_type);
 
-       ewah_iterator_init(&it, type_filter);
-
-       while (i < objects->word_alloc && ewah_iterator_next(&filter, &it)) {
+       for (i = 0; i < objects->word_alloc &&
+                       ewah_iterator_next(&filter, &it); i++) {
                eword_t word = objects->words[i] & filter;
+               size_t pos = (i * BITS_IN_EWORD);
+
+               if (!word)
+                       continue;
 
                for (offset = 0; offset < BITS_IN_EWORD; ++offset) {
                        struct object_id oid;
@@ -646,20 +690,14 @@ static void show_objects_for_type(
 
                        offset += ewah_bit_ctz64(word >> offset);
 
-                       if (pos + offset < bitmap_git->reuse_objects)
-                               continue;
-
                        entry = &bitmap_git->pack->revindex[pos + offset];
-                       nth_packed_object_oid(&oid, bitmap_git->pack, entry->nr);
+                       nth_packed_object_id(&oid, bitmap_git->pack, entry->nr);
 
                        if (bitmap_git->hashes)
                                hash = get_be32(bitmap_git->hashes + entry->nr);
 
                        show_reach(&oid, object_type, 0, hash, bitmap_git->pack, entry->offset);
                }
-
-               pos += BITS_IN_EWORD;
-               i++;
        }
 }
 
@@ -677,7 +715,179 @@ static int in_bitmapped_pack(struct bitmap_index *bitmap_git,
        return 0;
 }
 
-struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs)
+static struct bitmap *find_tip_blobs(struct bitmap_index *bitmap_git,
+                                    struct object_list *tip_objects)
+{
+       struct bitmap *result = bitmap_new();
+       struct object_list *p;
+
+       for (p = tip_objects; p; p = p->next) {
+               int pos;
+
+               if (p->item->type != OBJ_BLOB)
+                       continue;
+
+               pos = bitmap_position(bitmap_git, &p->item->oid);
+               if (pos < 0)
+                       continue;
+
+               bitmap_set(result, pos);
+       }
+
+       return result;
+}
+
+static void filter_bitmap_blob_none(struct bitmap_index *bitmap_git,
+                                   struct object_list *tip_objects,
+                                   struct bitmap *to_filter)
+{
+       struct eindex *eindex = &bitmap_git->ext_index;
+       struct bitmap *tips;
+       struct ewah_iterator it;
+       eword_t mask;
+       uint32_t i;
+
+       /*
+        * The non-bitmap version of this filter never removes
+        * blobs which the other side specifically asked for,
+        * so we must match that behavior.
+        */
+       tips = find_tip_blobs(bitmap_git, tip_objects);
+
+       /*
+        * We can use the blob type-bitmap to work in whole words
+        * for the objects that are actually in the bitmapped packfile.
+        */
+       for (i = 0, init_type_iterator(&it, bitmap_git, OBJ_BLOB);
+            i < to_filter->word_alloc && ewah_iterator_next(&mask, &it);
+            i++) {
+               if (i < tips->word_alloc)
+                       mask &= ~tips->words[i];
+               to_filter->words[i] &= ~mask;
+       }
+
+       /*
+        * Clear any blobs that weren't in the packfile (and so would not have
+        * been caught by the loop above. We'll have to check them
+        * individually.
+        */
+       for (i = 0; i < eindex->count; i++) {
+               uint32_t pos = i + bitmap_git->pack->num_objects;
+               if (eindex->objects[i]->type == OBJ_BLOB &&
+                   bitmap_get(to_filter, pos) &&
+                   !bitmap_get(tips, pos))
+                       bitmap_unset(to_filter, pos);
+       }
+
+       bitmap_free(tips);
+}
+
+static unsigned long get_size_by_pos(struct bitmap_index *bitmap_git,
+                                    uint32_t pos)
+{
+       struct packed_git *pack = bitmap_git->pack;
+       unsigned long size;
+       struct object_info oi = OBJECT_INFO_INIT;
+
+       oi.sizep = &size;
+
+       if (pos < pack->num_objects) {
+               struct revindex_entry *entry = &pack->revindex[pos];
+               if (packed_object_info(the_repository, pack,
+                                      entry->offset, &oi) < 0) {
+                       struct object_id oid;
+                       nth_packed_object_id(&oid, pack, entry->nr);
+                       die(_("unable to get size of %s"), oid_to_hex(&oid));
+               }
+       } else {
+               struct eindex *eindex = &bitmap_git->ext_index;
+               struct object *obj = eindex->objects[pos - pack->num_objects];
+               if (oid_object_info_extended(the_repository, &obj->oid, &oi, 0) < 0)
+                       die(_("unable to get size of %s"), oid_to_hex(&obj->oid));
+       }
+
+       return size;
+}
+
+static void filter_bitmap_blob_limit(struct bitmap_index *bitmap_git,
+                                    struct object_list *tip_objects,
+                                    struct bitmap *to_filter,
+                                    unsigned long limit)
+{
+       struct eindex *eindex = &bitmap_git->ext_index;
+       struct bitmap *tips;
+       struct ewah_iterator it;
+       eword_t mask;
+       uint32_t i;
+
+       tips = find_tip_blobs(bitmap_git, tip_objects);
+
+       for (i = 0, init_type_iterator(&it, bitmap_git, OBJ_BLOB);
+            i < to_filter->word_alloc && ewah_iterator_next(&mask, &it);
+            i++) {
+               eword_t word = to_filter->words[i] & mask;
+               unsigned offset;
+
+               for (offset = 0; offset < BITS_IN_EWORD; offset++) {
+                       uint32_t pos;
+
+                       if ((word >> offset) == 0)
+                               break;
+                       offset += ewah_bit_ctz64(word >> offset);
+                       pos = i * BITS_IN_EWORD + offset;
+
+                       if (!bitmap_get(tips, pos) &&
+                           get_size_by_pos(bitmap_git, pos) >= limit)
+                               bitmap_unset(to_filter, pos);
+               }
+       }
+
+       for (i = 0; i < eindex->count; i++) {
+               uint32_t pos = i + bitmap_git->pack->num_objects;
+               if (eindex->objects[i]->type == OBJ_BLOB &&
+                   bitmap_get(to_filter, pos) &&
+                   !bitmap_get(tips, pos) &&
+                   get_size_by_pos(bitmap_git, pos) >= limit)
+                       bitmap_unset(to_filter, pos);
+       }
+
+       bitmap_free(tips);
+}
+
+static int filter_bitmap(struct bitmap_index *bitmap_git,
+                        struct object_list *tip_objects,
+                        struct bitmap *to_filter,
+                        struct list_objects_filter_options *filter)
+{
+       if (!filter || filter->choice == LOFC_DISABLED)
+               return 0;
+
+       if (filter->choice == LOFC_BLOB_NONE) {
+               if (bitmap_git)
+                       filter_bitmap_blob_none(bitmap_git, tip_objects,
+                                               to_filter);
+               return 0;
+       }
+
+       if (filter->choice == LOFC_BLOB_LIMIT) {
+               if (bitmap_git)
+                       filter_bitmap_blob_limit(bitmap_git, tip_objects,
+                                                to_filter,
+                                                filter->blob_limit_value);
+               return 0;
+       }
+
+       /* filter choice not handled */
+       return -1;
+}
+
+static int can_filter_bitmap(struct list_objects_filter_options *filter)
+{
+       return !filter_bitmap(NULL, NULL, NULL, filter);
+}
+
+struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs,
+                                        struct list_objects_filter_options *filter)
 {
        unsigned int i;
 
@@ -687,10 +897,23 @@ struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs)
        struct bitmap *wants_bitmap = NULL;
        struct bitmap *haves_bitmap = NULL;
 
-       struct bitmap_index *bitmap_git = xcalloc(1, sizeof(*bitmap_git));
+       struct bitmap_index *bitmap_git;
+
+       /*
+        * We can't do pathspec limiting with bitmaps, because we don't know
+        * which commits are associated with which object changes (let alone
+        * even which objects are associated with which paths).
+        */
+       if (revs->prune)
+               return NULL;
+
+       if (!can_filter_bitmap(filter))
+               return NULL;
+
        /* try to open a bitmapped pack, but don't parse it yet
         * because we may not need to use it */
-       if (open_pack_bitmap(bitmap_git) < 0)
+       bitmap_git = xcalloc(1, sizeof(*bitmap_git));
+       if (open_pack_bitmap(revs->repo, bitmap_git) < 0)
                goto cleanup;
 
        for (i = 0; i < revs->pending.nr; ++i) {
@@ -707,9 +930,7 @@ struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs)
                        else
                                object_list_insert(object, &wants);
 
-                       if (!tag->tagged)
-                               die("bad tag");
-                       object = parse_object_or_die(&tag->tagged->oid, NULL);
+                       object = parse_object_or_die(get_tagged_oid(tag), NULL);
                }
 
                if (object->flags & UNINTERESTING)
@@ -735,7 +956,7 @@ struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs)
         * from disk. this is the point of no return; after this the rev_list
         * becomes invalidated and we must perform the revwalk through bitmaps
         */
-       if (!bitmap_git->loaded && load_pack_bitmap(bitmap_git) < 0)
+       if (load_pack_bitmap(bitmap_git) < 0)
                goto cleanup;
 
        object_array_clear(&revs->pending);
@@ -758,96 +979,173 @@ struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs)
        if (haves_bitmap)
                bitmap_and_not(wants_bitmap, haves_bitmap);
 
+       filter_bitmap(bitmap_git, wants, wants_bitmap, filter);
+
        bitmap_git->result = wants_bitmap;
+       bitmap_git->haves = haves_bitmap;
+
+       object_list_free(&wants);
+       object_list_free(&haves);
 
-       bitmap_free(haves_bitmap);
        return bitmap_git;
 
 cleanup:
        free_bitmap_index(bitmap_git);
+       object_list_free(&wants);
+       object_list_free(&haves);
        return NULL;
 }
 
-int reuse_partial_packfile_from_bitmap(struct bitmap_index *bitmap_git,
-                                      struct packed_git **packfile,
-                                      uint32_t *entries,
-                                      off_t *up_to)
+static void try_partial_reuse(struct bitmap_index *bitmap_git,
+                             size_t pos,
+                             struct bitmap *reuse,
+                             struct pack_window **w_curs)
 {
+       struct revindex_entry *revidx;
+       off_t offset;
+       enum object_type type;
+       unsigned long size;
+
+       if (pos >= bitmap_git->pack->num_objects)
+               return; /* not actually in the pack */
+
+       revidx = &bitmap_git->pack->revindex[pos];
+       offset = revidx->offset;
+       type = unpack_object_header(bitmap_git->pack, w_curs, &offset, &size);
+       if (type < 0)
+               return; /* broken packfile, punt */
+
+       if (type == OBJ_REF_DELTA || type == OBJ_OFS_DELTA) {
+               off_t base_offset;
+               int base_pos;
+
+               /*
+                * Find the position of the base object so we can look it up
+                * in our bitmaps. If we can't come up with an offset, or if
+                * that offset is not in the revidx, the pack is corrupt.
+                * There's nothing we can do, so just punt on this object,
+                * and the normal slow path will complain about it in
+                * more detail.
+                */
+               base_offset = get_delta_base(bitmap_git->pack, w_curs,
+                                            &offset, type, revidx->offset);
+               if (!base_offset)
+                       return;
+               base_pos = find_revindex_position(bitmap_git->pack, base_offset);
+               if (base_pos < 0)
+                       return;
+
+               /*
+                * We assume delta dependencies always point backwards. This
+                * lets us do a single pass, and is basically always true
+                * due to the way OFS_DELTAs work. You would not typically
+                * find REF_DELTA in a bitmapped pack, since we only bitmap
+                * packs we write fresh, and OFS_DELTA is the default). But
+                * let's double check to make sure the pack wasn't written with
+                * odd parameters.
+                */
+               if (base_pos >= pos)
+                       return;
+
+               /*
+                * And finally, if we're not sending the base as part of our
+                * reuse chunk, then don't send this object either. The base
+                * would come after us, along with other objects not
+                * necessarily in the pack, which means we'd need to convert
+                * to REF_DELTA on the fly. Better to just let the normal
+                * object_entry code path handle it.
+                */
+               if (!bitmap_get(reuse, base_pos))
+                       return;
+       }
+
        /*
-        * Reuse the packfile content if we need more than
-        * 90% of its objects
+        * If we got here, then the object is OK to reuse. Mark it.
         */
-       static const double REUSE_PERCENT = 0.9;
+       bitmap_set(reuse, pos);
+}
 
+int reuse_partial_packfile_from_bitmap(struct bitmap_index *bitmap_git,
+                                      struct packed_git **packfile_out,
+                                      uint32_t *entries,
+                                      struct bitmap **reuse_out)
+{
        struct bitmap *result = bitmap_git->result;
-       uint32_t reuse_threshold;
-       uint32_t i, reuse_objects = 0;
+       struct bitmap *reuse;
+       struct pack_window *w_curs = NULL;
+       size_t i = 0;
+       uint32_t offset;
 
        assert(result);
 
-       for (i = 0; i < result->word_alloc; ++i) {
-               if (result->words[i] != (eword_t)~0) {
-                       reuse_objects += ewah_bit_ctz64(~result->words[i]);
-                       break;
-               }
+       while (i < result->word_alloc && result->words[i] == (eword_t)~0)
+               i++;
 
-               reuse_objects += BITS_IN_EWORD;
-       }
+       /* Don't mark objects not in the packfile */
+       if (i > bitmap_git->pack->num_objects / BITS_IN_EWORD)
+               i = bitmap_git->pack->num_objects / BITS_IN_EWORD;
 
-#ifdef GIT_BITMAP_DEBUG
-       {
-               const unsigned char *sha1;
-               struct revindex_entry *entry;
+       reuse = bitmap_word_alloc(i);
+       memset(reuse->words, 0xFF, i * sizeof(eword_t));
 
-               entry = &bitmap_git->reverse_index->revindex[reuse_objects];
-               sha1 = nth_packed_object_sha1(bitmap_git->pack, entry->nr);
+       for (; i < result->word_alloc; ++i) {
+               eword_t word = result->words[i];
+               size_t pos = (i * BITS_IN_EWORD);
 
-               fprintf(stderr, "Failed to reuse at %d (%016llx)\n",
-                       reuse_objects, result->words[i]);
-               fprintf(stderr, " %s\n", sha1_to_hex(sha1));
+               for (offset = 0; offset < BITS_IN_EWORD; ++offset) {
+                       if ((word >> offset) == 0)
+                               break;
+
+                       offset += ewah_bit_ctz64(word >> offset);
+                       try_partial_reuse(bitmap_git, pos + offset, reuse, &w_curs);
+               }
        }
-#endif
 
-       if (!reuse_objects)
-               return -1;
+       unuse_pack(&w_curs);
 
-       if (reuse_objects >= bitmap_git->pack->num_objects) {
-               bitmap_git->reuse_objects = *entries = bitmap_git->pack->num_objects;
-               *up_to = -1; /* reuse the full pack */
-               *packfile = bitmap_git->pack;
-               return 0;
+       *entries = bitmap_popcount(reuse);
+       if (!*entries) {
+               bitmap_free(reuse);
+               return -1;
        }
 
-       reuse_threshold = bitmap_popcount(bitmap_git->result) * REUSE_PERCENT;
+       /*
+        * Drop any reused objects from the result, since they will not
+        * need to be handled separately.
+        */
+       bitmap_and_not(result, reuse);
+       *packfile_out = bitmap_git->pack;
+       *reuse_out = reuse;
+       return 0;
+}
 
-       if (reuse_objects < reuse_threshold)
-               return -1;
+int bitmap_walk_contains(struct bitmap_index *bitmap_git,
+                        struct bitmap *bitmap, const struct object_id *oid)
+{
+       int idx;
 
-       bitmap_git->reuse_objects = *entries = reuse_objects;
-       *up_to = bitmap_git->pack->revindex[reuse_objects].offset;
-       *packfile = bitmap_git->pack;
+       if (!bitmap)
+               return 0;
 
-       return 0;
+       idx = bitmap_position(bitmap_git, oid);
+       return idx >= 0 && bitmap_get(bitmap, idx);
 }
 
 void traverse_bitmap_commit_list(struct bitmap_index *bitmap_git,
+                                struct rev_info *revs,
                                 show_reachable_fn show_reachable)
 {
        assert(bitmap_git->result);
 
-       show_objects_for_type(bitmap_git, bitmap_git->commits,
-               OBJ_COMMIT, show_reachable);
-       show_objects_for_type(bitmap_git, bitmap_git->trees,
-               OBJ_TREE, show_reachable);
-       show_objects_for_type(bitmap_git, bitmap_git->blobs,
-               OBJ_BLOB, show_reachable);
-       show_objects_for_type(bitmap_git, bitmap_git->tags,
-               OBJ_TAG, show_reachable);
-
-       show_extended_objects(bitmap_git, show_reachable);
+       show_objects_for_type(bitmap_git, OBJ_COMMIT, show_reachable);
+       if (revs->tree_objects)
+               show_objects_for_type(bitmap_git, OBJ_TREE, show_reachable);
+       if (revs->blob_objects)
+               show_objects_for_type(bitmap_git, OBJ_BLOB, show_reachable);
+       if (revs->tag_objects)
+               show_objects_for_type(bitmap_git, OBJ_TAG, show_reachable);
 
-       bitmap_free(bitmap_git->result);
-       bitmap_git->result = NULL;
+       show_extended_objects(bitmap_git, revs, show_reachable);
 }
 
 static uint32_t count_object_type(struct bitmap_index *bitmap_git,
@@ -860,26 +1158,7 @@ static uint32_t count_object_type(struct bitmap_index *bitmap_git,
        struct ewah_iterator it;
        eword_t filter;
 
-       switch (type) {
-       case OBJ_COMMIT:
-               ewah_iterator_init(&it, bitmap_git->commits);
-               break;
-
-       case OBJ_TREE:
-               ewah_iterator_init(&it, bitmap_git->trees);
-               break;
-
-       case OBJ_BLOB:
-               ewah_iterator_init(&it, bitmap_git->blobs);
-               break;
-
-       case OBJ_TAG:
-               ewah_iterator_init(&it, bitmap_git->tags);
-               break;
-
-       default:
-               return 0;
-       }
+       init_type_iterator(&it, bitmap_git, type);
 
        while (i < objects->word_alloc && ewah_iterator_next(&filter, &it)) {
                eword_t word = objects->words[i++] & filter;
@@ -927,7 +1206,7 @@ static void test_show_object(struct object *object, const char *name,
        struct bitmap_test_data *tdata = data;
        int bitmap_pos;
 
-       bitmap_pos = bitmap_position(tdata->bitmap_git, object->oid.hash);
+       bitmap_pos = bitmap_position(tdata->bitmap_git, &object->oid);
        if (bitmap_pos < 0)
                die("Object not in bitmap: %s\n", oid_to_hex(&object->oid));
 
@@ -941,7 +1220,7 @@ static void test_show_commit(struct commit *commit, void *data)
        int bitmap_pos;
 
        bitmap_pos = bitmap_position(tdata->bitmap_git,
-                                    commit->object.oid.hash);
+                                    &commit->object.oid);
        if (bitmap_pos < 0)
                die("Object not in bitmap: %s\n", oid_to_hex(&commit->object.oid));
 
@@ -958,7 +1237,7 @@ void test_bitmap_walk(struct rev_info *revs)
        struct bitmap_test_data tdata;
        struct bitmap_index *bitmap_git;
 
-       if (!(bitmap_git = prepare_bitmap_git()))
+       if (!(bitmap_git = prepare_bitmap_git(revs->repo)))
                die("failed to load bitmap indexes");
 
        if (revs->pending.nr != 1)
@@ -968,7 +1247,7 @@ void test_bitmap_walk(struct rev_info *revs)
                bitmap_git->version, bitmap_git->entry_count);
 
        root = revs->pending.objects[0].item;
-       pos = kh_get_sha1(bitmap_git->bitmaps, root->oid.hash);
+       pos = kh_get_oid_map(bitmap_git->bitmaps, root->oid);
 
        if (pos < kh_end(bitmap_git->bitmaps)) {
                struct stored_bitmap *st = kh_value(bitmap_git->bitmaps, pos);
@@ -1042,7 +1321,7 @@ static int rebuild_bitmap(uint32_t *reposition,
 
 int rebuild_existing_bitmaps(struct bitmap_index *bitmap_git,
                             struct packing_data *mapping,
-                            khash_sha1 *reused_bitmaps,
+                            kh_oid_map_t *reused_bitmaps,
                             int show_progress)
 {
        uint32_t i, num_objects;
@@ -1058,13 +1337,13 @@ int rebuild_existing_bitmaps(struct bitmap_index *bitmap_git,
        reposition = xcalloc(num_objects, sizeof(uint32_t));
 
        for (i = 0; i < num_objects; ++i) {
-               const unsigned char *sha1;
+               struct object_id oid;
                struct revindex_entry *entry;
                struct object_entry *oe;
 
                entry = &bitmap_git->pack->revindex[i];
-               sha1 = nth_packed_object_sha1(bitmap_git->pack, entry->nr);
-               oe = packlist_find(mapping, sha1, NULL);
+               nth_packed_object_id(&oid, bitmap_git->pack, entry->nr);
+               oe = packlist_find(mapping, &oid);
 
                if (oe)
                        reposition[i] = oe_in_pack_pos(mapping, oe) + 1;
@@ -1081,9 +1360,9 @@ int rebuild_existing_bitmaps(struct bitmap_index *bitmap_git,
                        if (!rebuild_bitmap(reposition,
                                            lookup_stored_bitmap(stored),
                                            rebuild)) {
-                               hash_pos = kh_put_sha1(reused_bitmaps,
-                                                      stored->sha1,
-                                                      &hash_ret);
+                               hash_pos = kh_put_oid_map(reused_bitmaps,
+                                                         stored->oid,
+                                                         &hash_ret);
                                kh_value(reused_bitmaps, hash_pos) =
                                        bitmap_to_ewah(rebuild);
                        }
@@ -1110,9 +1389,17 @@ void free_bitmap_index(struct bitmap_index *b)
        ewah_pool_free(b->trees);
        ewah_pool_free(b->blobs);
        ewah_pool_free(b->tags);
-       kh_destroy_sha1(b->bitmaps);
+       kh_destroy_oid_map(b->bitmaps);
        free(b->ext_index.objects);
        free(b->ext_index.hashes);
        bitmap_free(b->result);
+       bitmap_free(b->haves);
        free(b);
 }
+
+int bitmap_has_oid_in_uninteresting(struct bitmap_index *bitmap_git,
+                                   const struct object_id *oid)
+{
+       return bitmap_git &&
+               bitmap_walk_contains(bitmap_git, bitmap_git->haves, oid);
+}