Skip to content

Commit

Permalink
Merge branch 'jt/commit-graph-missing'
Browse files Browse the repository at this point in the history
A regression where commit objects missing from a commit-graph can
cause an infinite loop when doing a fetch in a partial clone has
been fixed.

* jt/commit-graph-missing:
  fetch-pack: die if in commit graph but not obj db
  Revert "fetch-pack: add a deref_without_lazy_fetch_extended()"
  • Loading branch information
gitster committed Nov 12, 2024
2 parents 51ba601 + 5d4cc78 commit 486c9d3
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 22 deletions.
42 changes: 22 additions & 20 deletions fetch-pack.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,37 +122,49 @@ static void for_each_cached_alternate(struct fetch_negotiator *negotiator,
cb(negotiator, cache.items[i]);
}

static struct commit *deref_without_lazy_fetch_extended(const struct object_id *oid,
int mark_tags_complete,
enum object_type *type,
unsigned int oi_flags)
static void die_in_commit_graph_only(const struct object_id *oid)
{
struct object_info info = { .typep = type };
die(_("You are attempting to fetch %s, which is in the commit graph file but not in the object database.\n"
"This is probably due to repo corruption.\n"
"If you are attempting to repair this repo corruption by refetching the missing object, use 'git fetch --refetch' with the missing object."),
oid_to_hex(oid));
}

static struct commit *deref_without_lazy_fetch(const struct object_id *oid,
int mark_tags_complete_and_check_obj_db)
{
enum object_type type;
struct object_info info = { .typep = &type };
struct commit *commit;

commit = lookup_commit_in_graph(the_repository, oid);
if (commit)
if (commit) {
if (mark_tags_complete_and_check_obj_db) {
if (!has_object(the_repository, oid, 0))
die_in_commit_graph_only(oid);
}
return commit;
}

while (1) {
if (oid_object_info_extended(the_repository, oid, &info,
oi_flags))
OBJECT_INFO_SKIP_FETCH_OBJECT | OBJECT_INFO_QUICK))
return NULL;
if (*type == OBJ_TAG) {
if (type == OBJ_TAG) {
struct tag *tag = (struct tag *)
parse_object(the_repository, oid);

if (!tag->tagged)
return NULL;
if (mark_tags_complete)
if (mark_tags_complete_and_check_obj_db)
tag->object.flags |= COMPLETE;
oid = &tag->tagged->oid;
} else {
break;
}
}

if (*type == OBJ_COMMIT) {
if (type == OBJ_COMMIT) {
struct commit *commit = lookup_commit(the_repository, oid);
if (!commit || repo_parse_commit(the_repository, commit))
return NULL;
Expand All @@ -162,16 +174,6 @@ static struct commit *deref_without_lazy_fetch_extended(const struct object_id *
return NULL;
}


static struct commit *deref_without_lazy_fetch(const struct object_id *oid,
int mark_tags_complete)
{
enum object_type type;
unsigned flags = OBJECT_INFO_SKIP_FETCH_OBJECT | OBJECT_INFO_QUICK;
return deref_without_lazy_fetch_extended(oid, mark_tags_complete,
&type, flags);
}

static int rev_list_insert_ref(struct fetch_negotiator *negotiator,
const struct object_id *oid)
{
Expand Down
4 changes: 2 additions & 2 deletions t/t5330-no-lazy-fetch-with-commit-graph.sh
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ test_expect_success 'fetch any commit from promisor with the usage of the commit
git -C with-commit-graph config remote.origin.partialclonefilter blob:none &&
test_commit -C with-commit any-commit &&
anycommit=$(git -C with-commit rev-parse HEAD) &&
GIT_TRACE="$(pwd)/trace.txt" \
test_must_fail env GIT_TRACE="$(pwd)/trace.txt" \
git -C with-commit-graph fetch origin $anycommit 2>err &&
! grep "fatal: promisor-remote: unable to fork off fetch subprocess" err &&
test_grep ! "fatal: promisor-remote: unable to fork off fetch subprocess" err &&
grep "git fetch origin" trace.txt >actual &&
test_line_count = 1 actual
'
Expand Down

0 comments on commit 486c9d3

Please sign in to comment.