diff --git a/commit-reach.c b/commit-reach.c index 5df471a313..3d579d8f7f 100644 --- a/commit-reach.c +++ b/commit-reach.c @@ -572,7 +572,7 @@ int repo_is_descendant_of(struct repository *r, struct commit_list *from_list = NULL; int result; commit_list_insert(commit, &from_list); - result = can_all_from_reach(from_list, with_commit, 0); + result = can_all_from_reach(r, from_list, with_commit, 0); commit_list_free(from_list); return result; } else { @@ -853,7 +853,8 @@ int commit_contains(struct ref_filter *filter, struct commit *commit, return repo_is_descendant_of(the_repository, commit, list); } -int can_all_from_reach_with_flag(struct object_array *from, +int can_all_from_reach_with_flag(struct repository *r, + struct object_array *from, unsigned int with_flag, unsigned int assign_flag, timestamp_t min_commit_date, @@ -872,8 +873,7 @@ int can_all_from_reach_with_flag(struct object_array *from, if (!from_one || from_one->flags & assign_flag) continue; - from_one = deref_tag(the_repository, from_one, - "a from object", 0); + from_one = deref_tag(r, from_one, "a from object", 0); if (!from_one || from_one->type != OBJ_COMMIT) { /* * no way to tell if this is reachable by @@ -886,7 +886,7 @@ int can_all_from_reach_with_flag(struct object_array *from, } list[nr_commits] = (struct commit *)from_one; - if (repo_parse_commit(the_repository, list[nr_commits]) || + if (repo_parse_commit(r, list[nr_commits]) || commit_graph_generation(list[nr_commits]) < min_generation) { result = 0; goto cleanup; @@ -921,7 +921,7 @@ int can_all_from_reach_with_flag(struct object_array *from, if (!(parent->item->object.flags & assign_flag)) { parent->item->object.flags |= assign_flag; - if (repo_parse_commit(the_repository, parent->item) || + if (repo_parse_commit(r, parent->item) || parent->item->date < min_commit_date || commit_graph_generation(parent->item) < min_generation) continue; @@ -955,8 +955,8 @@ cleanup: return result; } -int can_all_from_reach(struct commit_list *from, struct commit_list *to, - int cutoff_by_min_date) +int can_all_from_reach(struct repository *r, struct commit_list *from, + struct commit_list *to, int cutoff_by_min_date) { struct object_array from_objs = OBJECT_ARRAY_INIT; struct commit_list *from_iter = from, *to_iter = to; @@ -967,7 +967,7 @@ int can_all_from_reach(struct commit_list *from, struct commit_list *to, while (from_iter) { add_object_array(&from_iter->item->object, NULL, &from_objs); - if (!repo_parse_commit(the_repository, from_iter->item)) { + if (!repo_parse_commit(r, from_iter->item)) { timestamp_t generation; if (from_iter->item->date < min_commit_date) min_commit_date = from_iter->item->date; @@ -981,7 +981,7 @@ int can_all_from_reach(struct commit_list *from, struct commit_list *to, } while (to_iter) { - if (!repo_parse_commit(the_repository, to_iter->item)) { + if (!repo_parse_commit(r, to_iter->item)) { timestamp_t generation; if (to_iter->item->date < min_commit_date) min_commit_date = to_iter->item->date; @@ -996,7 +996,7 @@ int can_all_from_reach(struct commit_list *from, struct commit_list *to, to_iter = to_iter->next; } - result = can_all_from_reach_with_flag(&from_objs, PARENT2, PARENT1, + result = can_all_from_reach_with_flag(r, &from_objs, PARENT2, PARENT1, min_commit_date, min_generation); while (from) { diff --git a/commit-reach.h b/commit-reach.h index 3f3a563d8a..5e2b82655b 100644 --- a/commit-reach.h +++ b/commit-reach.h @@ -88,13 +88,14 @@ int commit_contains(struct ref_filter *filter, struct commit *commit, * commits with date below 'min_commit_date' or generation below * 'min_generation'. */ -int can_all_from_reach_with_flag(struct object_array *from, +int can_all_from_reach_with_flag(struct repository *r, + struct object_array *from, unsigned int with_flag, unsigned int assign_flag, timestamp_t min_commit_date, timestamp_t min_generation); -int can_all_from_reach(struct commit_list *from, struct commit_list *to, - int commit_date_cutoff); +int can_all_from_reach(struct repository *r, struct commit_list *from, + struct commit_list *to, int commit_date_cutoff); /* diff --git a/fetch-pack.c b/fetch-pack.c index 120e01f3cf..26dbbdc4f6 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -2330,8 +2330,8 @@ void negotiate_using_fetch(const struct oid_array *negotiation_restrict_tips, die(_("unexpected 'ready' from remote")); else do_check_stateless_delimiter(stateless_rpc, &reader); - if (can_all_from_reach_with_flag(&nt_object_array, COMMON, - REACH_SCRATCH, 0, + if (can_all_from_reach_with_flag(the_repository, &nt_object_array, + COMMON, REACH_SCRATCH, 0, min_generation)) last_iteration = 1; trace2_region_leave_printf("negotiation", "round", diff --git a/t/helper/test-reach.c b/t/helper/test-reach.c index 5d86a96c17..8ea77a782c 100644 --- a/t/helper/test-reach.c +++ b/t/helper/test-reach.c @@ -127,7 +127,7 @@ int cmd__reach(int ac, const char **av) print_sorted_commit_ids(list); commit_list_free(list); } else if (!strcmp(av[1], "can_all_from_reach")) { - printf("%s(X,Y):%d\n", av[1], can_all_from_reach(X, Y, 1)); + printf("%s(X,Y):%d\n", av[1], can_all_from_reach(r, X, Y, 1)); } else if (!strcmp(av[1], "can_all_from_reach_with_flag")) { struct commit_list *iter = Y; @@ -136,7 +136,8 @@ int cmd__reach(int ac, const char **av) iter = iter->next; } - printf("%s(X,_,_,0,0):%d\n", av[1], can_all_from_reach_with_flag(&X_obj, 2, 4, 0, 0)); + printf("%s(X,_,_,0,0):%d\n", av[1], + can_all_from_reach_with_flag(r, &X_obj, 2, 4, 0, 0)); } else if (!strcmp(av[1], "commit_contains")) { struct ref_filter filter = REF_FILTER_INIT; struct contains_cache cache; diff --git a/t/t6437-submodule-merge.sh b/t/t6437-submodule-merge.sh index a564758f52..afb484b963 100755 --- a/t/t6437-submodule-merge.sh +++ b/t/t6437-submodule-merge.sh @@ -517,4 +517,43 @@ test_expect_success 'merging should fail with no merge base' ' ) ' +test_expect_success 'setup for commit-graphs in superproject and submodule' ' + git init commit-graph && + (cd commit-graph && + git init sub && + for i in 1 2 3 4 5 6 7 8 9 10 + do + test_commit -C sub "sub-$i" || return 1 + done && + + git -C sub checkout --detach sub-1 && + git add sub && + git commit -m base && + + # Write the commit-graph of the superproject while it only + # contains a single commit. Any commit-graph position of the + # submodule is thus out of bounds for the superproject. + git commit-graph write --reachable && + + git checkout -b side && + git -C sub checkout --detach sub-5 && + git add sub && + git commit -m side && + + git checkout main && + git -C sub checkout --detach sub-10 && + git add sub && + git commit -m main && + + git -C sub commit-graph write --reachable) +' + +test_expect_success 'merge does not mix up superproject and submodule commit-graphs' ' + (cd commit-graph && + git merge side && + git rev-parse HEAD:sub >actual && + git -C sub rev-parse sub-10^{commit} >expect && + test_cmp expect actual) +' + test_done diff --git a/upload-pack.c b/upload-pack.c index a52856d869..550fea6763 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -565,9 +565,9 @@ static int ok_to_give_up(struct upload_pack_data *data) if (!data->have_obj.nr) return 0; - return can_all_from_reach_with_flag(&data->want_obj, THEY_HAVE, - COMMON_KNOWN, data->oldest_have, - min_generation); + return can_all_from_reach_with_flag(the_repository, &data->want_obj, + THEY_HAVE, COMMON_KNOWN, + data->oldest_have, min_generation); } static int get_common_commits(struct upload_pack_data *data,