From: Johannes Schindelin <johannes.schindelin@xxxxxx> When `git fetch --update-shallow` needs to test for commit ancestry, it can naturally run into a missing object (e.g. if it is a parent of a shallow commit). To accommodate, the merge base logic will need to be able to handle this situation gracefully. Currently, that logic pretends that a missing parent commit is equivalent to a a missing parent commit, and for the purpose of `--update-shallow` that is exactly what we need it to do. Therefore, let's introduce a flag to indicate when that is precisely the logic we want. We need a flag, and cannot rely on `is_repository_shallow()` to indicate that situation, because that function would return 0: There may not actually be a `shallow` file, as demonstrated e.g. by t5537.10 ("add new shallow root with receive.updateshallow on") and t5538.4 ("add new shallow root with receive.updateshallow on"). Signed-off-by: Johannes Schindelin <johannes.schindelin@xxxxxx> --- commit-reach.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/commit-reach.c b/commit-reach.c index 248a0f2b39d..1d1d8c989de 100644 --- a/commit-reach.c +++ b/commit-reach.c @@ -53,7 +53,8 @@ static int queue_has_nonstale(struct prio_queue *queue) static struct commit_list *paint_down_to_common(struct repository *r, struct commit *one, int n, struct commit **twos, - timestamp_t min_generation) + timestamp_t min_generation, + int ignore_missing_commits) { struct prio_queue queue = { compare_commits_by_gen_then_commit_date }; struct commit_list *result = NULL; @@ -106,6 +107,13 @@ static struct commit_list *paint_down_to_common(struct repository *r, if ((p->object.flags & flags) == flags) continue; if (repo_parse_commit(r, p)) { + /* + * At this stage, we know that the commit is + * missing: `repo_parse_commit()` uses + * `OBJECT_INFO_DIE_IF_CORRUPT` and therefore + * corrupt commits would already have been + * dispatched with a `die()`. + */ free_commit_list(result); return NULL; } @@ -142,7 +150,7 @@ static struct commit_list *merge_bases_many(struct repository *r, return NULL; } - list = paint_down_to_common(r, one, n, twos, 0); + list = paint_down_to_common(r, one, n, twos, 0, 0); while (list) { struct commit *commit = pop_commit(&list); @@ -213,7 +221,7 @@ static int remove_redundant_no_gen(struct repository *r, min_generation = curr_generation; } common = paint_down_to_common(r, array[i], filled, - work, min_generation); + work, min_generation, 0); if (array[i]->object.flags & PARENT2) redundant[i] = 1; for (j = 0; j < filled; j++) @@ -503,7 +511,7 @@ int repo_in_merge_bases_many(struct repository *r, struct commit *commit, bases = paint_down_to_common(r, commit, nr_reference, reference, - generation); + generation, ignore_missing_commits); if (commit->object.flags & PARENT2) ret = 1; clear_commit_marks(commit, all_flags); -- gitgitgadget