Skip to content

Commit 5176f20

Browse files
phil-blaingitster
authored andcommitted
pull: check for local submodule modifications with the right range
Ever since 'git pull' learned '--recurse-submodules' in a6d7eb2 (pull: optionally rebase submodules (remote submodule changes only), 2017-06-23), we check if there are local submodule modifications by checking the revision range 'curr_head --not rebase_fork_point'. The goal of this check is to abort the pull if there are submodule modifications in the local commits being rebased, since this scenario is not supported. However, the actual range of commits being rebased is not 'rebase_fork_point..curr_head', as the logic in 'get_rebase_newbase_and_upstream' reveals, it is 'upstream..curr_head'. If the 'git merge-base --fork-point' invocation in 'get_rebase_fork_point' fails to find a fork point between the current branch and the remote-tracking branch we are pulling from, 'rebase_fork_point' is null and since 4d36f88 (submodule: do not pass null OID to setup_revisions, 2018-05-24), 'submodule_touches_in_range' checks 'curr_head' and all its ancestors for submodule modifications. Since it is highly likely that there are submodule modifications in this range (which is in effect the whole history of the current branch), this prevents 'git pull --rebase --recurse-submodules' from succeeding if no fork point exists between the current branch and the remote-tracking branch being pulled. This can happen, for example, when the current branch was forked from a commit which was never recorded in the reflog of the remote-tracking branch we are pulling, as the last two paragraphs of the "Discussion on fork-point mode" section in git-merge-base(1) explain. Fix this bug by passing 'upstream' instead of 'rebase_fork_point' as the 'excl_oid' argument to 'submodule_touches_in_range'. Reported-by: Brice Goglin <[email protected]> Signed-off-by: Philippe Blain <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent f260c6b commit 5176f20

File tree

2 files changed

+30
-1
lines changed

2 files changed

+30
-1
lines changed

builtin/pull.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1037,7 +1037,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
10371037

10381038
if ((recurse_submodules == RECURSE_SUBMODULES_ON ||
10391039
recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND) &&
1040-
submodule_touches_in_range(the_repository, &rebase_fork_point, &curr_head))
1040+
submodule_touches_in_range(the_repository, &upstream, &curr_head))
10411041
die(_("cannot rebase with locally recorded submodule modifications"));
10421042
if (!autostash) {
10431043
struct commit_list *list = NULL;

t/t5572-pull-submodule.sh

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,35 @@ test_expect_success 'pull --rebase --recurse-submodules fails if both sides reco
144144
test_i18ngrep "locally recorded submodule modifications" err
145145
'
146146

147+
test_expect_success 'pull --rebase --recurse-submodules (no submodule changes, no fork-point)' '
148+
# This tests the following scenario :
149+
# - local submodule does not have new commits
150+
# - local superproject has new commits that *do not* change the submodule pointer
151+
# - upstream superproject has new commits that *do not* change the submodule pointer
152+
# - local superproject branch has no fork-point with its remote-tracking counter-part
153+
154+
# create upstream superproject
155+
test_create_repo submodule &&
156+
test_commit -C submodule first_in_sub &&
157+
158+
test_create_repo superprojet &&
159+
test_commit -C superprojet first_in_super &&
160+
git -C superprojet submodule add ../submodule &&
161+
git -C superprojet commit -m "add submodule" &&
162+
test_commit -C superprojet third_in_super &&
163+
164+
# clone superproject
165+
git clone --recurse-submodules superprojet superclone &&
166+
167+
# add commits upstream
168+
test_commit -C superprojet fourth_in_super &&
169+
170+
# create topic branch in clone, not based on any remote-tracking branch
171+
git -C superclone checkout -b feat HEAD~1 &&
172+
test_commit -C superclone first_on_feat &&
173+
git -C superclone pull --rebase --recurse-submodules origin master
174+
'
175+
147176
# NOTE:
148177
#
149178
# This test is particular because there is only a single commit in the upstream superproject

0 commit comments

Comments
 (0)