Skip to content

Commit 7d0daf3

Browse files
committed
Merge branch 'en/pull-conflicting-options'
"git pull" had various corner cases that were not well thought out around its --rebase backend, e.g. "git pull --ff-only" did not stop but went ahead and rebased when the history on other side is not a descendant of our history. The series tries to fix them up. * en/pull-conflicting-options: pull: fix handling of multiple heads pull: update docs & code for option compatibility with rebasing pull: abort by default when fast-forwarding is not possible pull: make --rebase and --no-rebase override pull.ff=only pull: since --ff-only overrides, handle it first pull: abort if --ff-only is given and fast-forwarding is impossible t7601: add tests of interactions with multiple merge heads and config t7601: test interaction of merge/rebase/fast-forward flags and options
2 parents c420321 + 6f843a3 commit 7d0daf3

18 files changed

+371
-83
lines changed

Documentation/git-merge.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ merge has resulted in conflicts.
6161

6262
OPTIONS
6363
-------
64+
:git-merge: 1
65+
6466
include::merge-options.txt[]
6567

6668
-m <msg>::

Documentation/git-pull.txt

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,17 @@ SYNOPSIS
1515
DESCRIPTION
1616
-----------
1717

18-
Incorporates changes from a remote repository into the current
19-
branch. In its default mode, `git pull` is shorthand for
20-
`git fetch` followed by `git merge FETCH_HEAD`.
21-
22-
More precisely, 'git pull' runs 'git fetch' with the given
23-
parameters and calls 'git merge' to merge the retrieved branch
24-
heads into the current branch.
25-
With `--rebase`, it runs 'git rebase' instead of 'git merge'.
18+
Incorporates changes from a remote repository into the current branch.
19+
If the current branch is behind the remote, then by default it will
20+
fast-forward the current branch to match the remote. If the current
21+
branch and the remote have diverged, the user needs to specify how to
22+
reconcile the divergent branches with `--rebase` or `--no-rebase` (or
23+
the corresponding configuration option in `pull.rebase`).
24+
25+
More precisely, `git pull` runs `git fetch` with the given parameters
26+
and then depending on configuration options or command line flags,
27+
will call either `git rebase` or `git merge` to reconcile diverging
28+
branches.
2629

2730
<repository> should be the name of a remote repository as
2831
passed to linkgit:git-fetch[1]. <refspec> can name an
@@ -132,7 +135,7 @@ published that history already. Do *not* use this option
132135
unless you have read linkgit:git-rebase[1] carefully.
133136

134137
--no-rebase::
135-
Override earlier --rebase.
138+
This is shorthand for --rebase=false.
136139

137140
Options related to fetching
138141
~~~~~~~~~~~~~~~~~~~~~~~~~~~

Documentation/merge-options.txt

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
--no-commit::
33
Perform the merge and commit the result. This option can
44
be used to override --no-commit.
5+
ifdef::git-pull[]
6+
Only useful when merging.
7+
endif::git-pull[]
58
+
69
With --no-commit perform the merge and stop just before creating
710
a merge commit, to give the user a chance to inspect and further
@@ -39,6 +42,7 @@ set to `no` at the beginning of them.
3942
to `MERGE_MSG` before being passed on to the commit machinery in the
4043
case of a merge conflict.
4144

45+
ifdef::git-merge[]
4246
--ff::
4347
--no-ff::
4448
--ff-only::
@@ -47,6 +51,22 @@ set to `no` at the beginning of them.
4751
default unless merging an annotated (and possibly signed) tag
4852
that is not stored in its natural place in the `refs/tags/`
4953
hierarchy, in which case `--no-ff` is assumed.
54+
endif::git-merge[]
55+
ifdef::git-pull[]
56+
--ff-only::
57+
Only update to the new history if there is no divergent local
58+
history. This is the default when no method for reconciling
59+
divergent histories is provided (via the --rebase=* flags).
60+
61+
--ff::
62+
--no-ff::
63+
When merging rather than rebasing, specifies how a merge is
64+
handled when the merged-in history is already a descendant of
65+
the current history. If merging is requested, `--ff` is the
66+
default unless merging an annotated (and possibly signed) tag
67+
that is not stored in its natural place in the `refs/tags/`
68+
hierarchy, in which case `--no-ff` is assumed.
69+
endif::git-pull[]
5070
+
5171
With `--ff`, when possible resolve the merge as a fast-forward (only
5272
update the branch pointer to match the merged branch; do not create a
@@ -55,9 +75,11 @@ descendant of the current history), create a merge commit.
5575
+
5676
With `--no-ff`, create a merge commit in all cases, even when the merge
5777
could instead be resolved as a fast-forward.
78+
ifdef::git-merge[]
5879
+
5980
With `--ff-only`, resolve the merge as a fast-forward when possible.
6081
When not possible, refuse to merge and exit with a non-zero status.
82+
endif::git-merge[]
6183

6284
-S[<keyid>]::
6385
--gpg-sign[=<keyid>]::
@@ -73,6 +95,9 @@ When not possible, refuse to merge and exit with a non-zero status.
7395
In addition to branch names, populate the log message with
7496
one-line descriptions from at most <n> actual commits that are being
7597
merged. See also linkgit:git-fmt-merge-msg[1].
98+
ifdef::git-pull[]
99+
Only useful when merging.
100+
endif::git-pull[]
76101
+
77102
With --no-log do not list one-line descriptions from the
78103
actual commits being merged.
@@ -102,10 +127,17 @@ With --no-squash perform the merge and commit the result. This
102127
option can be used to override --squash.
103128
+
104129
With --squash, --commit is not allowed, and will fail.
130+
ifdef::git-pull[]
131+
+
132+
Only useful when merging.
133+
endif::git-pull[]
105134

106135
--no-verify::
107136
This option bypasses the pre-merge and commit-msg hooks.
108137
See also linkgit:githooks[5].
138+
ifdef::git-pull[]
139+
Only useful when merging.
140+
endif::git-pull[]
109141

110142
-s <strategy>::
111143
--strategy=<strategy>::
@@ -127,6 +159,10 @@ With --squash, --commit is not allowed, and will fail.
127159
default trust model, this means the signing key has been signed by
128160
a trusted key. If the tip commit of the side branch is not signed
129161
with a valid key, the merge is aborted.
162+
ifdef::git-pull[]
163+
+
164+
Only useful when merging.
165+
endif::git-pull[]
130166

131167
--summary::
132168
--no-summary::
@@ -167,3 +203,7 @@ endif::git-pull[]
167203
projects that started their lives independently. As that is
168204
a very rare occasion, no configuration variable to enable
169205
this by default exists and will not be added.
206+
ifdef::git-pull[]
207+
+
208+
Only useful when merging.
209+
endif::git-pull[]

advice.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,11 @@ void NORETURN die_conclude_merge(void)
286286
die(_("Exiting because of unfinished merge."));
287287
}
288288

289+
void NORETURN die_ff_impossible(void)
290+
{
291+
die(_("Not possible to fast-forward, aborting."));
292+
}
293+
289294
void advise_on_updating_sparse_paths(struct string_list *pathspec_list)
290295
{
291296
struct string_list_item *item;

advice.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ void advise_if_enabled(enum advice_type type, const char *advice, ...);
9696
int error_resolve_conflict(const char *me);
9797
void NORETURN die_resolve_conflict(const char *me);
9898
void NORETURN die_conclude_merge(void);
99+
void NORETURN die_ff_impossible(void);
99100
void advise_on_updating_sparse_paths(struct string_list *pathspec_list);
100101
void detach_advice(const char *new_name);
101102

builtin/merge.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1622,7 +1622,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
16221622
}
16231623

16241624
if (fast_forward == FF_ONLY)
1625-
die(_("Not possible to fast-forward, aborting."));
1625+
die_ff_impossible();
16261626

16271627
if (autostash)
16281628
create_autostash(the_repository,

builtin/pull.c

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -893,6 +893,8 @@ static int run_rebase(const struct object_id *newbase,
893893
strvec_pushv(&args, opt_strategy_opts.v);
894894
if (opt_gpg_sign)
895895
strvec_push(&args, opt_gpg_sign);
896+
if (opt_signoff)
897+
strvec_push(&args, opt_signoff);
896898
if (opt_autostash == 0)
897899
strvec_push(&args, "--no-autostash");
898900
else if (opt_autostash == 1)
@@ -911,12 +913,18 @@ static int run_rebase(const struct object_id *newbase,
911913
return ret;
912914
}
913915

914-
static int get_can_ff(struct object_id *orig_head, struct object_id *orig_merge_head)
916+
static int get_can_ff(struct object_id *orig_head,
917+
struct oid_array *merge_heads)
915918
{
916919
int ret;
917920
struct commit_list *list = NULL;
918921
struct commit *merge_head, *head;
922+
struct object_id *orig_merge_head;
919923

924+
if (merge_heads->nr > 1)
925+
return 0;
926+
927+
orig_merge_head = &merge_heads->oid[0];
920928
head = lookup_commit_reference(the_repository, orig_head);
921929
commit_list_insert(head, &list);
922930
merge_head = lookup_commit_reference(the_repository, orig_merge_head);
@@ -927,9 +935,9 @@ static int get_can_ff(struct object_id *orig_head, struct object_id *orig_merge_
927935

928936
static void show_advice_pull_non_ff(void)
929937
{
930-
advise(_("Pulling without specifying how to reconcile divergent branches is\n"
931-
"discouraged. You can squelch this message by running one of the following\n"
932-
"commands sometime before your next pull:\n"
938+
advise(_("You have divergent branches and need to specify how to reconcile them.\n"
939+
"You can do so by running one of the following commands sometime before\n"
940+
"your next pull:\n"
933941
"\n"
934942
" git config pull.rebase false # merge (the default strategy)\n"
935943
" git config pull.rebase true # rebase\n"
@@ -966,8 +974,22 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
966974

967975
parse_repo_refspecs(argc, argv, &repo, &refspecs);
968976

969-
if (!opt_ff)
977+
if (!opt_ff) {
970978
opt_ff = xstrdup_or_null(config_get_ff());
979+
/*
980+
* A subtle point: opt_ff was set on the line above via
981+
* reading from config. opt_rebase, in contrast, is set
982+
* before this point via command line options. The setting
983+
* of opt_rebase via reading from config (using
984+
* config_get_rebase()) does not happen until later. We
985+
* are relying on the next if-condition happening before
986+
* the config_get_rebase() call so that an explicit
987+
* "--rebase" can override a config setting of
988+
* pull.ff=only.
989+
*/
990+
if (opt_rebase >= 0 && opt_ff && !strcmp(opt_ff, "--ff-only"))
991+
opt_ff = "--ff";
992+
}
971993

972994
if (opt_rebase < 0)
973995
opt_rebase = config_get_rebase(&rebase_unspecified);
@@ -1041,14 +1063,25 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
10411063
die(_("Cannot merge multiple branches into empty head."));
10421064
return pull_into_void(merge_heads.oid, &curr_head);
10431065
}
1044-
if (opt_rebase && merge_heads.nr > 1)
1045-
die(_("Cannot rebase onto multiple branches."));
1066+
if (merge_heads.nr > 1) {
1067+
if (opt_rebase)
1068+
die(_("Cannot rebase onto multiple branches."));
1069+
if (opt_ff && !strcmp(opt_ff, "--ff-only"))
1070+
die(_("Cannot fast-forward to multiple branches."));
1071+
}
10461072

1047-
can_ff = get_can_ff(&orig_head, &merge_heads.oid[0]);
1073+
can_ff = get_can_ff(&orig_head, &merge_heads);
10481074

1049-
if (rebase_unspecified && !opt_ff && !can_ff) {
1050-
if (opt_verbosity >= 0)
1051-
show_advice_pull_non_ff();
1075+
/* ff-only takes precedence over rebase */
1076+
if (opt_ff && !strcmp(opt_ff, "--ff-only")) {
1077+
if (!can_ff)
1078+
die_ff_impossible();
1079+
opt_rebase = REBASE_FALSE;
1080+
}
1081+
/* If no action specified and we can't fast forward, then warn. */
1082+
if (!opt_ff && rebase_unspecified && !can_ff) {
1083+
show_advice_pull_non_ff();
1084+
die(_("Need to specify how to reconcile divergent branches."));
10521085
}
10531086

10541087
if (opt_rebase) {

t/t4013-diff-various.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ test_expect_success setup '
6565
export GIT_AUTHOR_DATE GIT_COMMITTER_DATE &&
6666
6767
git checkout master &&
68-
git pull -s ours . side &&
68+
git pull -s ours --no-rebase . side &&
6969
7070
GIT_AUTHOR_DATE="2006-06-26 00:05:00 +0000" &&
7171
GIT_COMMITTER_DATE="2006-06-26 00:05:00 +0000" &&

t/t5520-pull.sh

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -136,12 +136,12 @@ test_expect_success 'the default remote . should not break explicit pull' '
136136
git reset --hard HEAD^ &&
137137
echo file >expect &&
138138
test_cmp expect file &&
139-
git pull . second &&
139+
git pull --no-rebase . second &&
140140
echo modified >expect &&
141141
test_cmp expect file &&
142142
git reflog -1 >reflog.actual &&
143143
sed "s/^[0-9a-f][0-9a-f]*/OBJID/" reflog.actual >reflog.fuzzy &&
144-
echo "OBJID HEAD@{0}: pull . second: Fast-forward" >reflog.expected &&
144+
echo "OBJID HEAD@{0}: pull --no-rebase . second: Fast-forward" >reflog.expected &&
145145
test_cmp reflog.expected reflog.fuzzy
146146
'
147147

@@ -226,7 +226,7 @@ test_expect_success 'fail if the index has unresolved entries' '
226226
test_commit modified2 file &&
227227
git ls-files -u >unmerged &&
228228
test_must_be_empty unmerged &&
229-
test_must_fail git pull . second &&
229+
test_must_fail git pull --no-rebase . second &&
230230
git ls-files -u >unmerged &&
231231
test_file_not_empty unmerged &&
232232
cp file expected &&
@@ -409,37 +409,37 @@ test_expect_success 'pull --rebase --no-autostash & rebase.autostash unset' '
409409

410410
test_expect_success 'pull succeeds with dirty working directory and merge.autostash set' '
411411
test_config merge.autostash true &&
412-
test_pull_autostash 2
412+
test_pull_autostash 2 --no-rebase
413413
'
414414

415415
test_expect_success 'pull --autostash & merge.autostash=true' '
416416
test_config merge.autostash true &&
417-
test_pull_autostash 2 --autostash
417+
test_pull_autostash 2 --autostash --no-rebase
418418
'
419419

420420
test_expect_success 'pull --autostash & merge.autostash=false' '
421421
test_config merge.autostash false &&
422-
test_pull_autostash 2 --autostash
422+
test_pull_autostash 2 --autostash --no-rebase
423423
'
424424

425425
test_expect_success 'pull --autostash & merge.autostash unset' '
426426
test_unconfig merge.autostash &&
427-
test_pull_autostash 2 --autostash
427+
test_pull_autostash 2 --autostash --no-rebase
428428
'
429429

430430
test_expect_success 'pull --no-autostash & merge.autostash=true' '
431431
test_config merge.autostash true &&
432-
test_pull_autostash_fail --no-autostash
432+
test_pull_autostash_fail --no-autostash --no-rebase
433433
'
434434

435435
test_expect_success 'pull --no-autostash & merge.autostash=false' '
436436
test_config merge.autostash false &&
437-
test_pull_autostash_fail --no-autostash
437+
test_pull_autostash_fail --no-autostash --no-rebase
438438
'
439439

440440
test_expect_success 'pull --no-autostash & merge.autostash unset' '
441441
test_unconfig merge.autostash &&
442-
test_pull_autostash_fail --no-autostash
442+
test_pull_autostash_fail --no-autostash --no-rebase
443443
'
444444

445445
test_expect_success 'pull.rebase' '

t/t5521-pull-options.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ test_expect_success 'git pull --force' '
113113
git pull two &&
114114
test_commit A &&
115115
git branch -f origin &&
116-
git pull --all --force
116+
git pull --no-rebase --all --force
117117
)
118118
'
119119

@@ -179,7 +179,7 @@ test_expect_success 'git pull --allow-unrelated-histories' '
179179
(
180180
cd dst &&
181181
test_must_fail git pull ../src side &&
182-
git pull --allow-unrelated-histories ../src side
182+
git pull --no-rebase --allow-unrelated-histories ../src side
183183
)
184184
'
185185

0 commit comments

Comments
 (0)