@@ -12,6 +12,7 @@
#include "packfile.h"
#include "repository.h"
#include "object-store.h"
+#include "prio-queue.h"
/*
* An entry on the bitmap index, representing the bitmap for a given
@@ -679,6 +680,81 @@ static int in_bitmapped_pack(struct bitmap_index *bitmap_git,
return 0;
}
+#define PARENT1 (1u<<16)
+#define PARENT2 (1u<<17)
+#define STALE (1u<<18)
+
+static const int all_flags = { PARENT1 | PARENT2 | STALE };
+
+static int queue_has_nonstale(struct prio_queue *queue)
+{
+ int i;
+ for (i = 0; i < queue->nr; i++) {
+ struct commit *commit = queue->array[i].data;
+ if (!(commit->object.flags & STALE))
+ return 1;
+ }
+ return 0;
+}
+
+static int has_uninteresting_bitmap_in_frontier(struct repository *r,
+ struct commit_list *list,
+ struct bitmap_index *bitmap_git)
+{
+ int res = 0;
+ struct commit_list *iter = list;
+ struct prio_queue queue = { compare_commits_by_commit_date };
+
+ while (iter) {
+ prio_queue_put(&queue, iter->item);
+ iter = iter->next;
+ }
+
+ while (queue_has_nonstale(&queue)) {
+ struct commit *commit = prio_queue_get(&queue);
+ struct commit_list *parents;
+ int flags;
+
+ flags = commit->object.flags & (PARENT1 | PARENT2 | STALE);
+ if (flags == (PARENT1 | PARENT2)) {
+ /* Mark parents of a found merge stale */
+ flags |= STALE;
+ }
+
+ if (flags & PARENT1) {
+ khiter_t pos = kh_get_oid_map(bitmap_git->bitmaps, commit->object.oid);
+
+ if (pos < kh_end(bitmap_git->bitmaps)) {
+ res = 1;
+ goto cleanup;
+ }
+ }
+
+ parents = commit->parents;
+ while (parents) {
+ struct commit *p = parents->item;
+ parents = parents->next;
+ if ((p->object.flags & flags) == flags)
+ continue;
+ if (repo_parse_commit(r, p))
+ goto cleanup;
+ p->object.flags |= flags;
+ prio_queue_put(&queue, p);
+ }
+ }
+
+cleanup:
+ clear_prio_queue(&queue);
+
+ iter = list;
+ while (iter) {
+ clear_commit_marks(iter->item, all_flags);
+ iter = iter->next;
+ }
+
+ return res;
+}
+
struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs)
{
unsigned int i;
@@ -689,6 +765,8 @@ struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs)
struct bitmap *wants_bitmap = NULL;
struct bitmap *haves_bitmap = NULL;
+ struct commit_list *commits = NULL;
+
struct bitmap_index *bitmap_git = xcalloc(1, sizeof(*bitmap_git));
/* try to open a bitmapped pack, but don't parse it yet
* because we may not need to use it */
@@ -704,16 +782,22 @@ struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs)
while (object->type == OBJ_TAG) {
struct tag *tag = (struct tag *) object;
- if (object->flags & UNINTERESTING)
+ if (object->flags & UNINTERESTING) {
+ object->flags |= PARENT1;
object_list_insert(object, &haves);
- else
+ } else {
+ object->flags |= PARENT2;
object_list_insert(object, &wants);
+ }
if (!tag->tagged)
die("bad tag");
object = parse_object_or_die(&tag->tagged->oid, NULL);
}
+ if (object->type == OBJ_COMMIT)
+ commit_list_insert((struct commit *)object, &commits);
+
if (object->flags & UNINTERESTING)
object_list_insert(object, &haves);
else
@@ -740,6 +824,10 @@ struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs)
if (load_pack_bitmap(bitmap_git) < 0)
goto cleanup;
+ if (!has_uninteresting_bitmap_in_frontier(the_repository, commits, bitmap_git))
+ goto cleanup;
+
+ /* this is the real no-turning-back point! */
object_array_clear(&revs->pending);
if (haves) {
@@ -422,7 +422,7 @@ test_expect_success 'fetch without bitmaps ignores delta against old base' '
'
# And do the same for the bitmap case, where we do expect to find the delta.
-test_expect_success 'fetch with bitmaps can reuse old base' '
+test_expect_failure 'fetch with bitmaps can reuse old base' '
test_config pack.usebitmaps true &&
test_when_finished "rm -rf client.git" &&
git init --bare client.git &&