From: Felipe Contreras <hidden> Date: 2021-07-05 12:32:13
Throughout the years many big threads have been started [1] [2] [3] [4]
[5] [6] because `git pull` is broken (for everyone that isn't a
maintainer), and nothing has been fixed.
The two main problems are:
1. The order of the parents is the opposite of what it should be
2. By default it should fail unless it's a fast-forward
However, every attempt to fix these issues gets entangled in an
inescapable web of interrelated problems.
That's because `git pull` is in fact *two* commands pretending to be
one.
I have spent several days re-reading old threads looking for anything
related to `git pull` and fast-forward throughout the entire history of
the git mailing list, going as far back as 2008.
This process has been illuminating.
The amount of people that have pondered about, and even suggested, a
`git update` command is striking:
* Linus Torvalds: [7]
* Junio C. Hamano: [8]
* Richard Hansen: [9]
* John Keeping: [10]
And of course me [11], who not only suggested it, but implemented it
as well [12].
It's not just the name, but the behavior too:
`git fetch` + `git merge --ff-only`
This way `git pull` can be used by maintainers to integrate pull
requests, and `git update` for everyone else (normal developers) to
update their local branch to its upstream.
Plus it has a --merge mode that creates a merge commit, but with the
parents in the right order (master to upstream, not upstream to master).
Both problems are fixed by this approach.
Also, a thorny issue since a long time ago has been how to properly
advise users what to do in case a fast-forward is not possible.
I propose a new command: `git fast-forward`. When a fast-forward is not
possible `git fast-forward` fails, and shows an advice (that can be
easily turned off).
Therefore in fact `git update` is really `git fetch` +
`git fast-forward`, and it's the latter that throws the advice. The
advice also suggests `git help fast-forward` which has an explanation
about what a fast-forward is, what are the options to synchronize
with the remote branch (merge and rebase), and what do they look like.
In addition there's a ton of fixes for `git pull` which have been sent
before, including the `pull.mode` configuration, the `--merge` option,
the per-branch `pullMode` configuration, `pull.mode=fast-forward`, and
an improved advice message to prepare users for a future default change:
The pull was not a fast-forward, in the future you will have to choose
between a merge or a rebase.
To quell this message you have two main options:
1. Adopt the new behavior:
git config --global pull.mode fast-forward
2. Maintain the current behavior:
git config --global pull.mode merge
For now we will fall back to the traditional behavior: merge.
For more information check "git help fast-forward".
It doesn't just improve the situation for normal developers, but it also
opens the possibility to fix a wart in `git pull --rebase`:
Right now:
git pull --merge github john (merge "github/john" into "master)
git pull --rebase github john (rebase "master" onto "github/john")
Since now `git update --rebase` can be used to rebase the current branch
onto its upstream, that leaves `git pull --rebase` open to rebase
github/john onto master, not the other way around like it currently is.
Junio has suggested there's no consensus over fast-forward by default,
but that's not true. Here is a non-exhaustive list of people that have
agreed the default should be fast-forward only.
* Linus Torvalds
* Junio C Hamano
* Jeff King
* Jonathan Nieder
* Richard Hansen
* Philip Oakley
* Elijah Newren
* John Keeping
* Ramkumar Ramachandra
* Alex Henrie
* W. Trevor King
* Greg Troxel
* Peter Kjellerstedt
* Konstantin Tokarev
* Robert Dailey
* Vít Ondruch
* Raymond E. Pasco
* Jacob Keller
* Felipe Contreras
There's only one person against the change: Matthieu Moy. His argument
back then [13] was: why ask users to merge or rebase if newcomers will
not pick a rebase? To that my response is: for the same reason we ask
them to do `git commit --all`: so that they eventually learn about the
staging area. Just like they can do `git commit --all`, they can do
`git pull --merge`. They can figure out what that means later.
The people in favor of reordering the parents:
* Andreas Krey
* John Szakmeister
* Jeremy Rosen
* John Keeping
And the people in favor of my old `git update`:
* Damien Robert
* Ping Yin
* Philippe Vaucher
This patch series doesn't implement all of the features my old
`git update` had, but it implements most of them, most
importantly--unlike `git pull`--it's not broken.
Right now only `git update` without arguments works, and only if the
upstream branch is configured. I have a pretty good idea of what the it
should do with different arguments (as I had already implemented that),
but for now that's open to discussion.
If you want to give it a try:
https://github.com/felipec/git/tree/fc/update
[1] https://lore.kernel.org/git/200910201947.50423.trast@student.ethz.ch/
[2] https://lore.kernel.org/git/20130522115042.GA20649@inner.h.apk.li/
[3] https://lore.kernel.org/git/1377988690-23460-1-git-send-email-felipe.contreras@gmail.com/
[4] https://lore.kernel.org/git/4ay6w9i74cygt6ii1b0db7wg.1398433713382@email.android.com/
[5] https://lore.kernel.org/git/5363BB9F.40102@xiplink.com/
[6] https://lore.kernel.org/git/20201204061623.1170745-1-felipe.contreras@gmail.com/
[7] https://lore.kernel.org/git/CA+55aFzxsNxgKD1uGZQCiib+=+wCMSa0=B+Ye3Zi-u6kpz8Vrg@mail.gmail.com/
[8] https://lore.kernel.org/git/xmqqppjyhnom.fsf@gitster.dls.corp.google.com/
[9] https://lore.kernel.org/git/5228A14B.3000804@bbn.com/
[10] https://lore.kernel.org/git/20130628174252.GF2232@serenity.lan/
[11] https://lore.kernel.org/git/5366db742d494_18f9e4b308aa@nysa.notmuch/
[12] https://github.com/felipec/git/commit/61e05c9798b3c74bab8b2d47ede4c12e8e305345
[13] https://lore.kernel.org/git/vpqbo3za8r9.fsf@anie.imag.fr/
Felipe Contreras (35):
merge: improve fatal fast-forward message
merge: split cmd_merge()
fast-forward: add new builtin
doc: fast-forward: explain what it is
fast-forward: add advice for novices
fast-forward: make the advise configurable
fast-forward: add help about merge vs. rebase
update: new built-in
update: add options and usage skeleton
update: add --ff option
update: add --merge mode
commit: support for multiple MERGE_MODE
merge: add --reverse-parents option
update: reverse the order of parents
update: fake a reverse order of parents in message
update: add --rebase mode
update: add mode configuation
update: add per-branch mode configuration
pull: cleanup autostash check
pull: trivial cleanup
pull: trivial whitespace style fix
pull: introduce --merge option
rebase: add REBASE_DEFAULT
pull: move configuration fetches
pull: show warning with --ff options
pull: add pull.mode
pull: add per-branch mode configuration
pull: add pull.mode=fast-forward
pull: reorganize mode conditionals
pull: add diverging advice on fast-forward mode
pull: improve --rebase and pull.rebase interaction
pull: improve default warning
pull: advice of future changes
FUTURE: pull: enable ff-only mode by default
!fixup FUTURE: pull: enable ff-only mode by default
.gitignore | 2 +
Documentation/config.txt | 4 +
Documentation/config/advice.txt | 2 +
Documentation/config/branch.txt | 10 ++
Documentation/config/pull.txt | 6 +
Documentation/config/update.txt | 5 +
Documentation/git-fast-forward.txt | 104 +++++++++++++++++
Documentation/git-pull.txt | 10 +-
Documentation/git-update.txt | 47 ++++++++
Documentation/merge-options.txt | 4 +
Makefile | 2 +
advice.c | 15 +++
advice.h | 2 +
builtin.h | 2 +
builtin/commit.c | 7 +-
builtin/merge.c | 59 +++++++---
builtin/pull.c | 156 +++++++++++++++++--------
builtin/update.c | 153 ++++++++++++++++++++++++
contrib/completion/git-completion.bash | 22 ++++
fmt-merge-msg.c | 21 +++-
fmt-merge-msg.h | 3 +-
git.c | 2 +
rebase.c | 12 ++
rebase.h | 13 ++-
t/t4013-diff-various.sh | 2 +-
t/t5520-pull.sh | 123 +++++++++++++++++--
t/t5521-pull-options.sh | 4 +-
t/t5524-pull-msg.sh | 4 +-
t/t5553-set-upstream.sh | 14 +--
t/t5563-update.sh | 87 ++++++++++++++
t/t5604-clone-reference.sh | 4 +-
t/t6402-merge-rename.sh | 16 +--
t/t6409-merge-subtree.sh | 6 +-
t/t6417-merge-ours-theirs.sh | 10 +-
t/t7600-merge.sh | 47 ++++++++
t/t7601-merge-pull-config.sh | 116 ------------------
t/t7603-merge-reduce-heads.sh | 2 +-
37 files changed, 870 insertions(+), 228 deletions(-)
create mode 100644 Documentation/config/update.txt
create mode 100644 Documentation/git-fast-forward.txt
create mode 100644 Documentation/git-update.txt
create mode 100644 builtin/update.c
create mode 100755 t/t5563-update.sh
--
2.32.0.36.g70aac2b1aa
@@ -1620,7 +1620,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)}if(fast_forward==FF_ONLY)-die(_("Not possible to fast-forward, aborting."));+die(_("unable to fast-forward"));if(autostash)create_autostash(the_repository,
From: Felipe Contreras <hidden> Date: 2021-07-05 12:32:17
We want to re-use most of cmd_merge() for a new command.
Signed-off-by: Felipe Contreras <redacted>
---
builtin/merge.c | 26 ++++++++++++++------------
1 file changed, 14 insertions(+), 12 deletions(-)
@@ -1314,7 +1314,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)if(orig_argc!=2)usage_msg_opt(_("--abort expects no arguments"),-builtin_merge_usage,builtin_merge_options);+usage,options);if(!file_exists(git_path_merge_head(the_repository)))die(_("There is no merge to abort (MERGE_HEAD missing)."));
@@ -1336,8 +1336,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)if(quit_current_merge){if(orig_argc!=2)usage_msg_opt(_("--quit expects no arguments"),-builtin_merge_usage,-builtin_merge_options);+usage,options);remove_merge_branch_state(the_repository);gotodone;
@@ -1349,7 +1348,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)if(orig_argc!=2)usage_msg_opt(_("--continue expects no arguments"),-builtin_merge_usage,builtin_merge_options);+usage,options);if(!file_exists(git_path_merge_head(the_repository)))die(_("There is no merge in progress (MERGE_HEAD missing)."));
From: Felipe Contreras <hidden> Date: 2021-07-05 12:32:18
This is one of the most common git operations, it makes sense it has its
own built-in.
This is basically the same as `git merge --ff-only` (for now).
Signed-off-by: Felipe Contreras <redacted>
---
.gitignore | 1 +
Documentation/git-fast-forward.txt | 26 ++++++++++++++++++++++++++
Makefile | 1 +
builtin.h | 1 +
builtin/merge.c | 15 +++++++++++++++
contrib/completion/git-completion.bash | 10 ++++++++++
git.c | 1 +
t/t7600-merge.sh | 21 +++++++++++++++++++++
8 files changed, 76 insertions(+)
create mode 100644 Documentation/git-fast-forward.txt
@@ -0,0 +1,26 @@+git-fast-forward(1)+===================++NAME+----+git-fast-forward - Advance the branch pointer++SYNOPSIS+--------+[verse]+'git fast-forward' [<commit>]++DESCRIPTION+-----------+Incorporates changes into the current branch. By default the upstream branch is+used, but a different commit can be specified in the arguments.++THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOUR MAY CHANGE.++SEE ALSO+--------+linkgit:git-merge[1]++GIT+---+Part of the linkgit:git[1] suite
@@ -15,11 +15,41 @@ DESCRIPTION Incorporates changes into the current branch. By default the upstream branch is used, but a different commit can be specified in the arguments.+Assume the following history exists and the current branch is+`master`:++------------+ D---C---B---A origin/master+ ^+ |+ master+------------++Then `git fast-forward` will advance the local `master` to `origin/master`:++------------+ D---C---B---A master, origin/master+------------++This operation is not always possible; if you made changes and the branches+have diverged:++------------+ D---C---B---A origin/master+ \+ X---Y master+------------++then the fast-forward command will fail.++In those cases you need to either `git merge`, or `git rebase` in order to+synchronize the two branches.+ THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOUR MAY CHANGE. SEE ALSO ---------linkgit:git-merge[1]+linkgit:git-merge[1], linkgit:git-rebase[1] GIT ---
@@ -326,3 +326,14 @@ void detach_advice(const char *new_name)fprintf(stderr,fmt,new_name);}++voiddiverging_advice(void)+{+advise(_("Diverging branches can't be fast-forwarded, you need to either:\n"+"\n"+"\tgit merge\n"+"\n"+"or:\n"+"\n"+"\tgit rebase\n"));+}
@@ -123,4 +123,6 @@ advice.*:: Advice shown when either linkgit:git-add[1] or linkgit:git-rm[1] is asked to update index entries outside the current sparse checkout.+ diverging::+ Advice shown when a fast-forward is not possible. --
@@ -329,7 +330,8 @@ void detach_advice(const char *new_name)voiddiverging_advice(void){-advise(_("Diverging branches can't be fast-forwarded, you need to either:\n"+advise_if_enabled(ADVICE_DIVERGING,+_("Diverging branches can't be fast-forwarded, you need to either:\n""\n""\tgit merge\n""\n"
@@ -47,6 +47,54 @@ synchronize the two branches. THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOUR MAY CHANGE.+MERGE OR REBASE+---------------++The decision to whether merge or rebase depends on the situation, and the+project. Traditionally git has prefered merge over rebase, but that creates a+new commit, and that's frowned up on some projects, so you can't just simply+choose to merge blindly.++------------+ D---C---B---A origin/master+ \+ X---Y master+------------++The nature of distributed version control systems make this divergence+unavoidable. You must decide how to synchronize this divergence.++If you choose to merge, the two heads (master and origin/master) will be joined+together in a new commit:++------------+ origin/master+ |+ v+ D---C---B---A---M master+ \ /+ X---Y---++------------++This new commit is called a merge commit and has two parents (A and Y).++Rebasing on the other hand rewrites the history:++------------+ origin/master+ |+ v+ D---C---B---A---X'---Y' master+------------++The commits that diverged (X and Y) are rewritten as if they were created on top+of the new base (A). This creates a linear history, which is cleaner, but some+people prefer to preserve the original hsitory.++In both cases it's likely you would have to resolve conflicts, the difference is+that in a merge you would have to do it all at once in one commit, while with a+rebase you would have to do it on every rewritten commit.+ SEE ALSO -------- linkgit:git-merge[1], linkgit:git-rebase[1]
@@ -337,5 +337,7 @@ void diverging_advice(void)"\n""or:\n""\n"-"\tgit rebase\n"));+"\tgit rebase\n"+"\n"+"For more information check \"git help fast-forward\".\n"));}
@@ -0,0 +1,32 @@+git-update(1)+=============++NAME+----+git-update - Update the current branch to the latest remote++SYNOPSIS+--------+[verse]+'git update'++DESCRIPTION+-----------++Incorporates changes from a remote repository into the current branch.++`git update` runs `git fetch` and then tries to advance the current branch to+the remote branch with `git fast-forward`. If you don't have any extra changes+the update operation is straight-forward, but if you do a further `git merge` or+`git rebase` will be needed.++THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOUR MAY CHANGE.++SEE ALSO+--------+linkgit:git-fetch[1], linkgit:git-fast-forward[1],+linkgit:git-merge[1], linkgit:git-rebase[1]++GIT+---+Part of the linkgit:git[1] suite
@@ -8,7 +8,7 @@ git-update - Update the current branch to the latest remote SYNOPSIS -------- [verse]-'git update'+'git update' [<options>] DESCRIPTION -----------
@@ -22,6 +22,13 @@ the update operation is straight-forward, but if you do a further `git merge` or THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOUR MAY CHANGE.+OPTIONS+-------++-f::+--ff::+ Forces a fast-forward.+ SEE ALSO -------- linkgit:git-fetch[1], linkgit:git-fast-forward[1],
@@ -29,6 +29,10 @@ OPTIONS --ff:: Forces a fast-forward.+-m::+--merge::+ Forces a merge.+ SEE ALSO -------- linkgit:git-fetch[1], linkgit:git-fast-forward[1],
@@ -149,6 +149,10 @@ ifndef::git-pull[] Note that not all merge strategies may support progress reporting.+--reverse-parents::+--no-reverse-parents::+ Reverse the order of parents in the merge commit.+ endif::git-pull[] --autostash::
@@ -91,6 +91,7 @@ static int signoff;staticconstchar*sign_commit;staticintautostash;staticintno_verify;+staticintreverse_parents;staticstructstrategyall_strategy[]={{"recursive",DEFAULT_TWOHEAD|NO_TRIVIAL},
@@ -306,6 +307,8 @@ static struct option builtin_merge_options[] = {OPT_BOOL(0,"overwrite-ignore",&overwrite_ignore,N_("update ignored files (default)")),OPT_BOOL(0,"signoff",&signoff,N_("add a Signed-off-by trailer")),OPT_BOOL(0,"no-verify",&no_verify,N_("bypass pre-merge-commit and commit-msg hooks")),+OPT_BOOL(0,"reverse-parents",&reverse_parents,+N_("reverse the order of parents")),OPT_END()};
@@ -913,6 +916,8 @@ static int merge_trivial(struct commit *head, struct commit_list *remoteheads)pptr=commit_list_append(head,pptr);pptr=commit_list_append(remoteheads->item,pptr);prepare_to_commit(remoteheads);+if(reverse_parents)+parents=reverse_commit_list(parents);if(commit_tree(merge_msg.buf,merge_msg.len,&result_tree,parents,&result_commit,NULL,sign_commit))die(_("failed to write commit object"));
@@ -937,6 +942,8 @@ static int finish_automerge(struct commit *head,parents=remoteheads;if(!head_subsumed||fast_forward==FF_NO)commit_list_insert(head,&parents);+if(reverse_parents)+parents=reverse_commit_list(parents);prepare_to_commit(remoteheads);if(commit_tree(merge_msg.buf,merge_msg.len,result_tree,parents,&result_commit,NULL,sign_commit))
@@ -432,6 +432,19 @@ static int dest_suppressed(const char *dest_branch)return0;}+staticvoidfmt_update_msg_title(structstrbuf*out,constchar*current_branch)+{+structsrc_data*src_data;+strbuf_addf(out,"Merge branch '%s'",current_branch);+src_data=srcs.items[0].util;+if(src_data->branch.nr){+constchar*branch_name=src_data->branch.items[0].string;+if(!dest_suppressed(branch_name))+strbuf_addf(out," into %s",branch_name);+}+strbuf_addch(out,'\n');+}+staticvoidfmt_merge_msg_title(structstrbuf*out,constchar*current_branch){
@@ -665,8 +678,12 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,die("error in line %d: %.*s",i,len,p);}-if(opts->add_title&&srcs.nr)-fmt_merge_msg_title(out,current_branch);+if(opts->add_title&&srcs.nr){+if(opts->reverse_parents)+fmt_update_msg_title(out,current_branch);+else+fmt_merge_msg_title(out,current_branch);+}if(origins.nr)fmt_merge_msg_sigs(out);
@@ -33,6 +33,10 @@ OPTIONS --merge:: Forces a merge.+-r::+--rebase::+ Forces a rebase.+ SEE ALSO -------- linkgit:git-fetch[1], linkgit:git-fast-forward[1],
@@ -0,0 +1,4 @@+update.mode::+ When `git update` is run, this determines the mode of operation,+ possible values are 'fast-forward', 'merge', and 'rebase'. The default+ is 'fast-forward'.
@@ -96,6 +96,11 @@ mode. it unless you understand the implications (see linkgit:git-rebase[1] for details).+branch.<name>.updateMode::+ When `git update` is run, this determines the mode of operation,+ possible values are 'fast-forward', 'merge', and 'rebase'.+ See `update.mode` for doing this in a non branch-specific manner.+ branch.<name>.description:: Branch description, can be edited with `git branch --edit-description`. Branch description is
@@ -1,4 +1,5 @@ update.mode:: When `git update` is run, this determines the mode of operation, possible values are 'fast-forward', 'merge', and 'rebase'. The default- is 'fast-forward'.+ is 'fast-forward'. See "branch.<name>.updateMode" for setting this on a+ per-branch basis.
From: Felipe Contreras <hidden> Date: 2021-07-05 12:32:45
Currently "git pull --rebase" takes a shortcut in the case a
fast-forward merge is possible; run_merge() is called with --ff-only.
However, "git merge" didn't have an --autostash option, so, when "git
pull --rebase --autostash" was called *and* the fast-forward merge
shortcut was taken, then the pull failed.
This was fixed in commit f15e7cf5cc (pull: ff --rebase --autostash
works in dirty repo, 2017-06-01) by simply skipping the fast-forward
merge shortcut.
Later on "git merge" learned the --autostash option [a03b55530a
(merge: teach --autostash option, 2020-04-07)], and so did "git pull"
[d9f15d37f1 (pull: pass --autostash to merge, 2020-04-07)].
Therefore it's not necessary to skip the fast-forward merge shortcut
anymore when called with --rebase --autostash.
Let's always take the fast-forward merge shortcut by essentially
reverting f15e7cf5cc.
Signed-off-by: Felipe Contreras <redacted>
---
builtin/pull.c | 16 +++++++---------
1 file changed, 7 insertions(+), 9 deletions(-)
@@ -1065,13 +1064,12 @@ int cmd_pull(int argc, const char **argv, const char *prefix)recurse_submodules==RECURSE_SUBMODULES_ON_DEMAND)&&submodule_touches_in_range(the_repository,&upstream,&curr_head))die(_("cannot rebase with locally recorded submodule modifications"));-if(!autostash){-if(can_ff){-/* we can fast-forward this without invoking rebase */-opt_ff="--ff-only";-ran_ff=1;-ret=run_merge();-}++if(can_ff){+/* we can fast-forward this without invoking rebase */+opt_ff="--ff-only";+ran_ff=1;+ret=run_merge();}if(!ran_ff)ret=run_rebase(&newbase,&upstream);
From: Felipe Contreras <hidden> Date: 2021-07-05 12:32:47
There's no need to store ran_ff. Now it's obvious from the conditionals.
Signed-off-by: Felipe Contreras <redacted>
---
builtin/pull.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
@@ -1068,11 +1067,10 @@ int cmd_pull(int argc, const char **argv, const char *prefix)if(can_ff){/* we can fast-forward this without invoking rebase */opt_ff="--ff-only";-ran_ff=1;ret=run_merge();-}-if(!ran_ff)+}else{ret=run_rebase(&newbase,&upstream);+}if(!ret&&(recurse_submodules==RECURSE_SUBMODULES_ON||recurse_submodules==RECURSE_SUBMODULES_ON_DEMAND))
From: Felipe Contreras <hidden> Date: 2021-07-05 12:32:50
Two spaces unaligned to anything is not part of the coding-style. A
single tab is.
Signed-off-by: Felipe Contreras <redacted>
---
builtin/pull.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
@@ -126,9 +126,9 @@ static struct option pull_options[] = {/* Options passed to git-merge or git-rebase */OPT_GROUP(N_("Options related to merging")),OPT_CALLBACK_F('r',"rebase",&opt_rebase,-"(false|true|merges|preserve|interactive)",-N_("incorporate changes by rebasing rather than merging"),-PARSE_OPT_OPTARG,parse_opt_rebase),+"(false|true|merges|preserve|interactive)",+N_("incorporate changes by rebasing rather than merging"),+PARSE_OPT_OPTARG,parse_opt_rebase),OPT_PASSTHRU('n',NULL,&opt_diffstat,NULL,N_("do not show a diffstat at the end of the merge"),PARSE_OPT_NOARG|PARSE_OPT_NONEG),
From: Felipe Contreras <hidden> Date: 2021-07-05 12:32:51
Previously --no-rebase (which still works for backwards compatibility).
Now we can update the default warning, and the git-pull(1) man page to
use --merge instead of the non-intuitive --no-rebase.
Signed-off-by: Felipe Contreras <redacted>
---
Documentation/git-pull.txt | 7 +++++--
builtin/pull.c | 4 +++-
t/t7601-merge-pull-config.sh | 8 ++++----
3 files changed, 12 insertions(+), 7 deletions(-)
@@ -131,8 +131,11 @@ It rewrites history, which does not bode well when you published that history already. Do *not* use this option unless you have read linkgit:git-rebase[1] carefully.---no-rebase::- Override earlier --rebase.+-m::+--merge::+ Force a merge.+++Previously this was --no-rebase, but that usage has been deprecated. Options related to fetching ~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -129,6 +129,8 @@ static struct option pull_options[] = {"(false|true|merges|preserve|interactive)",N_("incorporate changes by rebasing rather than merging"),PARSE_OPT_OPTARG,parse_opt_rebase),+OPT_SET_INT('m',"merge",&opt_rebase,+N_("incorporate changes by merging"),REBASE_FALSE),OPT_PASSTHRU('n',NULL,&opt_diffstat,NULL,N_("do not show a diffstat at the end of the merge"),PARSE_OPT_NOARG|PARSE_OPT_NONEG),
@@ -936,7 +938,7 @@ static void show_advice_pull_non_ff(void)" git config pull.ff only # fast-forward only\n""\n""You can replace \"git config\" with \"git config --global\" to set a default\n"-"preference for all repositories. You can also pass --rebase, --no-rebase,\n"+"preference for all repositories. You can also pass --rebase, --merge,\n""or --ff-only on the command line to override the configured default per\n""invocation.\n"));}
@@ -60,9 +60,9 @@ test_expect_success 'pull.rebase not set and --rebase given' 'test_i18ngrep!"Pulling without specifying how to reconcile"err'-test_expect_success'pull.rebase not set and --no-rebase given''+test_expect_success'pull.rebase not set and --merge given''gitreset--hardc0&&-gitpull--no-rebase.c12>err&&+gitpull--merge.c12>err&&test_i18ngrep!"Pulling without specifying how to reconcile"err'
@@ -119,9 +119,9 @@ test_expect_success 'pull.rebase not set and --rebase given (not-fast-forward)'test_i18ngrep!"Pulling without specifying how to reconcile"err'-test_expect_success'pull.rebase not set and --no-rebase given (not-fast-forward)''+test_expect_success'pull.rebase not set and --merge given (not-fast-forward)''gitreset--hardc2&&-gitpull--no-rebase.c12>err&&+gitpull--merge.c12>err&&test_i18ngrep!"Pulling without specifying how to reconcile"err'
From: Felipe Contreras <hidden> Date: 2021-07-05 12:32:53
By introducing a default we can distinguish when the user has forced an
option.
Therefore there's no need pass around an extra variable variable (it's
the same as opt_rebase == REBASE_DEFAULT), nor is there any need to
initialize opt_rebase to an invalid value.
Additionally this will allow us to override the default with a
configuration, and subsequently the configuration with arguments.
Cc: Junio C Hamano <redacted>
Signed-off-by: Felipe Contreras <redacted>
---
builtin/pull.c | 27 ++++++++++++---------------
rebase.h | 3 ++-
2 files changed, 14 insertions(+), 16 deletions(-)
@@ -443,7 +441,7 @@ static void NORETURN die_no_merge_candidates(const char *repo, const char **refsconstchar*remote=curr_branch?curr_branch->remote_name:NULL;if(*refspecs){-if(opt_rebase)+if(opt_rebase>=REBASE_TRUE)fprintf_ln(stderr,_("There is no candidate for rebasing against among the refs that you just fetched."));elsefprintf_ln(stderr,_("There are no candidates for merging among the refs that you just fetched."));
@@ -456,7 +454,7 @@ static void NORETURN die_no_merge_candidates(const char *repo, const char **refsrepo);}elseif(!curr_branch){fprintf_ln(stderr,_("You are not currently on a branch."));-if(opt_rebase)+if(opt_rebase>=REBASE_TRUE)fprintf_ln(stderr,_("Please specify which branch you want to rebase against."));elsefprintf_ln(stderr,_("Please specify which branch you want to merge with."));
@@ -471,7 +469,7 @@ static void NORETURN die_no_merge_candidates(const char *repo, const char **refsremote_name=_("<remote>");fprintf_ln(stderr,_("There is no tracking information for the current branch."));-if(opt_rebase)+if(opt_rebase>=REBASE_TRUE)fprintf_ln(stderr,_("Please specify which branch you want to rebase against."));elsefprintf_ln(stderr,_("Please specify which branch you want to merge with."));
From: Felipe Contreras <hidden> Date: 2021-07-05 12:32:56
Now that we have REBASE_DEFAULT we can fetch the configuration before
parsing the argument options.
The options will override the configuration, and if they don't;
opt_rebase will remain being REBASE_DEFAULT.
Signed-off-by: Felipe Contreras <redacted>
---
builtin/pull.c | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
From: Felipe Contreras <hidden> Date: 2021-07-05 12:32:56
We want the user to specify either --merge or --rebase, if she doesn't
we throw a warning.
Using --ff, --no-ff, or --ff-only does not make the merge explicit.
For example, if the user has the following configuration:
git config pull.rebase true
git pull --no-ff
A merge is not implied.
We should be consistent and either imply a merge--in which case a
previous "pull.rebase=true" configuration is overridden--or don't--in
which case the warning should be thrown.
Signed-off-by: Felipe Contreras <redacted>
---
builtin/pull.c | 2 +-
t/t7601-merge-pull-config.sh | 12 ++++++------
2 files changed, 7 insertions(+), 7 deletions(-)
@@ -96,21 +96,21 @@ test_expect_success 'pull.rebase not set and pull.ff=true (not-fast-forward)' 'gitreset--hardc2&&test_configpull.fftrue&&gitpull.c12>err&&-test_i18ngrep!"Pulling without specifying how to reconcile"err+test_i18ngrep"Pulling without specifying how to reconcile"err' test_expect_success'pull.rebase not set and pull.ff=false (not-fast-forward)''gitreset--hardc2&&test_configpull.fffalse&&gitpull.c12>err&&-test_i18ngrep!"Pulling without specifying how to reconcile"err+test_i18ngrep"Pulling without specifying how to reconcile"err' test_expect_success'pull.rebase not set and pull.ff=only (not-fast-forward)''gitreset--hardc2&&test_configpull.ffonly&&test_must_failgitpull.c12>err&&-test_i18ngrep!"Pulling without specifying how to reconcile"err+test_i18ngrep"Pulling without specifying how to reconcile"err' test_expect_success'pull.rebase not set and --rebase given (not-fast-forward)''
@@ -128,19 +128,19 @@ test_expect_success 'pull.rebase not set and --merge given (not-fast-forward)' ' test_expect_success'pull.rebase not set and --ff given (not-fast-forward)''gitreset--hardc2&&gitpull--ff.c12>err&&-test_i18ngrep!"Pulling without specifying how to reconcile"err+test_i18ngrep"Pulling without specifying how to reconcile"err' test_expect_success'pull.rebase not set and --no-ff given (not-fast-forward)''gitreset--hardc2&&gitpull--no-ff.c12>err&&-test_i18ngrep!"Pulling without specifying how to reconcile"err+test_i18ngrep"Pulling without specifying how to reconcile"err' test_expect_success'pull.rebase not set and --ff-only given (not-fast-forward)''gitreset--hardc2&&test_must_failgitpull--ff-only.c12>err&&-test_i18ngrep!"Pulling without specifying how to reconcile"err+test_i18ngrep"Pulling without specifying how to reconcile"err' test_expect_success'merge c1 with c2''
From: Felipe Contreras <hidden> Date: 2021-07-05 12:32:57
The evolution of pull options has somewhat served most users, however,
they have been found lacking for a very needed trio: merge / rebase /
fast-forward-only.
To avoid some of the problems of git pull Linus Torvalds suggested a
configuration pull.merge [1], however, instead of having pull.merge and
pull.rebase, we can have pull.mode which works for both.
Additionally this would allow us to have a saner per-branch
configuration: branch.<name>.pullMode.
This patch adds a pull.mode option with two possible values (for now);
merge and rebase. If set, it overrides what the user has specified in
pull.rebase, and it's updated with either --merge, or --rebase.
[1] https://lore.kernel.org/git/CA+55aFz2Uvq4vmyjJPao5tS-uuVvKm6mbP7Uz8sdq1VMxMGJCw@mail.gmail.com/
Signed-off-by: Felipe Contreras <redacted>
---
Documentation/config/pull.txt | 5 +++
builtin/pull.c | 68 ++++++++++++++++++++++++++++++++---
rebase.c | 10 ++++++
rebase.h | 9 +++++
t/t5520-pull.sh | 42 ++++++++++++++++++++++
t/t7601-merge-pull-config.sh | 14 ++++++++
6 files changed, 143 insertions(+), 5 deletions(-)
@@ -29,6 +29,11 @@ mode. it unless you understand the implications (see linkgit:git-rebase[1] for details).+pull.mode::+ When "git pull" is run, this determines if it would either merge or+ rebase the fetched branch. The possible values are 'merge',+ and 'rebase'.+ pull.octopus:: The default merge strategy to use when pulling multiple branches at once.
@@ -49,6 +51,14 @@ static enum rebase_type parse_config_rebase(const char *key, const char *value,returnREBASE_INVALID;}+staticenumpull_mode_typeparse_config_pull_mode(constchar*key,constchar*value)+{+enumpull_mode_typev=pull_mode_parse_value(value);+if(v==PULL_MODE_INVALID)+die(_("Invalid value for %s: %s"),key,value);+returnv;+}+/***Callbackfor--rebase,whichparsesargwithparse_config_rebase().*/
@@ -60,9 +70,21 @@ static int parse_opt_rebase(const struct option *opt, const char *arg, int unset*value=parse_config_rebase("--rebase",arg,0);else*value=unset?REBASE_FALSE:REBASE_TRUE;++if(*value>0)+mode=*value>=REBASE_TRUE?PULL_MODE_REBASE:PULL_MODE_MERGE;+return*value==REBASE_INVALID?-1:0;}+staticintparse_opt_merge(conststructoption*opt,constchar*arg,intunset)+{+enumrebase_type*value=opt->value;+mode=PULL_MODE_MERGE;+*value=REBASE_FALSE;+return0;+}+staticconstchar*constpull_usage[]={N_("git pull [<options>] [<repository> [<refspec>...]]"),NULL
@@ -129,8 +151,9 @@ static struct option pull_options[] = {"(false|true|merges|preserve|interactive)",N_("incorporate changes by rebasing rather than merging"),PARSE_OPT_OPTARG,parse_opt_rebase),-OPT_SET_INT('m',"merge",&opt_rebase,-N_("incorporate changes by merging"),REBASE_FALSE),+OPT_CALLBACK_F('m',"merge",&opt_rebase,NULL,+N_("incorporate changes by merging"),+PARSE_OPT_NOARG|PARSE_OPT_NONEG,parse_opt_merge),OPT_PASSTHRU('n',NULL,&opt_diffstat,NULL,N_("do not show a diffstat at the end of the merge"),PARSE_OPT_NOARG|PARSE_OPT_NONEG),
@@ -931,9 +964,9 @@ static void show_advice_pull_non_ff(void)"discouraged. You can squelch this message by running one of the following\n""commands sometime before your next pull:\n""\n"-" git config pull.rebase false # merge (the default strategy)\n"-" git config pull.rebase true # rebase\n"-" git config pull.ff only # fast-forward only\n"+" git config pull.mode merge # the default strategy\n"+" git config pull.mode rebase\n"+" git config pull.ff only # fast-forward only\n""\n""You can replace \"git config\" with \"git config --global\" to set a default\n""preference for all repositories. You can also pass --rebase, --merge,\n"
@@ -968,6 +1001,31 @@ int cmd_pull(int argc, const char **argv, const char *prefix)parse_repo_refspecs(argc,argv,&repo,&refspecs);+/*+*Iftheuserhasnotspecified--mergeor--rebase,fetchpull.modetooverride+*pull.rename.+*/+if(!mode){+mode=config_get_pull_mode(repo);++switch(mode){+casePULL_MODE_MERGE:+opt_rebase=REBASE_FALSE;+break;+casePULL_MODE_REBASE:+/* Do not oeverride other rebase modes */+if(opt_rebase<REBASE_TRUE)+opt_rebase=REBASE_TRUE;+break;+casePULL_MODE_DEFAULT:+if(opt_rebase>0)+mode=opt_rebase>=REBASE_TRUE?PULL_MODE_REBASE:PULL_MODE_MERGE;+break;+default:+break;+}+}+if(read_cache_unmerged())die_resolve_conflict("pull");
@@ -526,6 +536,17 @@ test_expect_success 'pull.rebase=false create a new merge commit' 'test_cmpexpectactual'+test_expect_success'pull.mode=merge create a new merge commit''+gitreset--hardbefore-preserve-rebase&&+test_configpull.modemerge&&+gitpull.copy&&+test_cmp_revHEAD^1before-preserve-rebase&&+test_cmp_revHEAD^2copy&&+echofile3>expect&&+gitshowHEAD:file3.t>actual&&+test_cmpexpectactual+'+ test_expect_success'pull.rebase=true flattens keep-merge''gitreset--hardbefore-preserve-rebase&&test_configpull.rebasetrue&&
@@ -555,6 +576,16 @@ test_expect_success REBASE_P \test_cmp_revHEAD^2keep-merge'+test_expect_successREBASE_P\+'pull.rebase=preserve rebases and merges keep-merge with pull.mode''+gitreset--hardbefore-preserve-rebase&&+test_configpull.moderebase&&+test_configpull.rebasepreserve&&+gitpull.copy&&+test_cmp_revHEAD^^copy&&+test_cmp_revHEAD^2keep-merge+'+ test_expect_success'pull.rebase=interactive''write_script"$TRASH_DIRECTORY/fake-editor"<<-\EOF&&echoIwashere>fake.out&&
@@ -596,6 +627,17 @@ test_expect_success '--rebase=false create a new merge commit' 'test_cmpexpectactual'+test_expect_success'--rebase=false create a new merge commit with pull.mode''+gitreset--hardbefore-preserve-rebase&&+test_configpull.moderebase&&+gitpull--rebase=false.copy&&+test_cmp_revHEAD^1before-preserve-rebase&&+test_cmp_revHEAD^2copy&&+echofile3>expect&&+gitshowHEAD:file3.t>actual&&+test_cmpexpectactual+'+ test_expect_success'--rebase=true rebases and flattens keep-merge''gitreset--hardbefore-preserve-rebase&&test_configpull.rebasepreserve&&
@@ -33,6 +33,13 @@ test_expect_success 'pull.rebase not set' 'test_i18ngrep!"Pulling without specifying how to reconcile"err'+test_expect_success'pull.mode set''+gitreset--hardc0&&+test_configpull.modemerge&&+gitpull.c12>err&&+test_i18ngrep!"Pulling without specifying how to reconcile"err+'+ test_expect_success'pull.rebase not set and pull.ff=true''gitreset--hardc0&&test_configpull.fftrue&&
@@ -92,6 +99,13 @@ test_expect_success 'pull.rebase not set (not-fast-forward)' 'test_i18ngrep"Pulling without specifying how to reconcile"decoded'+test_expect_success'pull.mode set''+gitreset--hardc2&&+test_configpull.modemerge&&+gitpull.c12>err&&+test_i18ngrep!"Pulling without specifying how to reconcile"err+'+ test_expect_success'pull.rebase not set and pull.ff=true (not-fast-forward)''gitreset--hardc2&&test_configpull.fftrue&&
@@ -101,6 +101,11 @@ branch.<name>.updateMode:: possible values are 'fast-forward', 'merge', and 'rebase'. See `update.mode` for doing this in a non branch-specific manner.+branch.<name>.pullMode::+ When `git pull` is run, this determines the mode of operation,+ possible values are 'merge' and 'rebase'. See `pull.mode` for doing this+ in a non branch-specific manner.+ branch.<name>.description:: Branch description, can be edited with `git branch --edit-description`. Branch description is
@@ -32,7 +32,8 @@ for details). pull.mode:: When "git pull" is run, this determines if it would either merge or rebase the fetched branch. The possible values are 'merge',- and 'rebase'.+ and 'rebase'. See "branch.<name>.pullMode" for setting this on a+ per-branch basis. pull.octopus:: The default merge strategy to use when pulling multiple branches
From: Felipe Contreras <hidden> Date: 2021-07-05 12:33:02
It is very typical for Git newcomers to inadvertently create merges and
worse; pushing them. This is one of the reasons many experienced users
prefer to avoid 'git pull', and recommend newcomers to avoid it as well.
To escape these problems--and keep 'git pull' useful--it has been
suggested that 'git pull' barfs by default if the merge is
non-fast-forward, which unfortunately would break backwards
compatibility.
This patch leaves everything in place to enable this new mode, but it
only gets enabled if the user specifically configures it:
pull.mode = fast-forward
Later on this mode can be enabled by default.
For *some* of the long discussions you can read:
https://lore.kernel.org/git/742df4c2-2bc5-8a4b-8de1-cd5e48718398@redhat.com/https://lore.kernel.org/git/20130522115042.GA20649@inner.h.apk.lihttps://lore.kernel.org/git/1377988690-23460-1-git-send-email-felipe.contreras@gmail.comhttps://lore.kernel.org/git/4ay6w9i74cygt6ii1b0db7wg.1398433713382@email.android.com
Signed-off-by: Felipe Contreras <redacted>
---
Documentation/config/branch.txt | 4 +--
Documentation/config/pull.txt | 4 +--
builtin/pull.c | 6 ++++-
rebase.c | 2 ++
rebase.h | 3 ++-
t/t5520-pull.sh | 44 +++++++++++++++++++++++++++++++++
6 files changed, 57 insertions(+), 6 deletions(-)
@@ -103,8 +103,8 @@ branch.<name>.updateMode:: branch.<name>.pullMode:: When `git pull` is run, this determines the mode of operation,- possible values are 'merge' and 'rebase'. See `pull.mode` for doing this- in a non branch-specific manner.+ possible values are 'fast-forward', 'merge', and 'rebase'.+ See `pull.mode` for doing this in a non branch-specific manner. branch.<name>.description:: Branch description, can be edited with
@@ -32,8 +32,8 @@ for details). pull.mode:: When "git pull" is run, this determines if it would either merge or rebase the fetched branch. The possible values are 'merge',- and 'rebase'. See "branch.<name>.pullMode" for setting this on a- per-branch basis.+ 'rebase', and 'fast-forward'. See "branch.<name>.pullMode" for setting+ this on a per-branch basis. pull.octopus:: The default merge strategy to use when pulling multiple branches
@@ -979,7 +979,7 @@ static void show_advice_pull_non_ff(void)"\n"" git config pull.mode merge # the default strategy\n"" git config pull.mode rebase\n"-" git config pull.ff only # fast-forward only\n"+" git config pull.mode fast-forward\n""\n""You can replace \"git config\" with \"git config --global\" to set a default\n""preference for all repositories. You can also pass --rebase, --merge,\n"
@@ -1113,6 +1114,9 @@ int cmd_pull(int argc, const char **argv, const char *prefix)can_ff=get_can_ff(&orig_head,&merge_heads.oid[0]);+if(mode==PULL_MODE_FAST_FORWARD&&!can_ff)+die(_("The pull was not fast-forward, either merge or rebase.\n"));+if(!opt_rebase&&!can_ff){if(opt_verbosity>=0)show_advice_pull_non_ff();
@@ -869,4 +869,48 @@ test_expect_success 'git pull --rebase against local branch' 'test_cmpexpectfile2'+setup_other(){+test_when_finished"git checkout main && git branch -D other test"&&+gitcheckout-bother$1&&+>new&&+gitaddnew&&+gitcommit-mnew&&+gitcheckout-btest-tother&&+gitreset--hardmain+}++setup_ff(){+setup_othermain+}++setup_non_ff(){+setup_othermain^+}++test_expect_success'fast-forward (pull.mode=fast-forward)''+setup_ff&&+git-cpull.mode=fast-forwardpull+'++test_expect_success'non-fast-forward (pull.mode=fast-forward)''+setup_non_ff&&+test_must_failgit-cpull.mode=fast-forwardpull+'++test_expect_success'non-fast-forward with merge (pull.mode=fast-forward)''+setup_non_ff&&+git-cpull.mode=fast-forwardpull--merge+'++test_expect_success'non-fast-forward with rebase (pull.mode=fast-forward)''+setup_non_ff&&+git-cpull.mode=fast-forwardpull--rebase+'++test_expect_success'non-fast-forward error message (pull.mode=fast-forward)''+setup_non_ff&&+test_must_failgit-cpull.mode=fast-forwardpull2>error&&+test_i18ngrep"The pull was not fast-forward"error+'+ test_done
From: Felipe Contreras <hidden> Date: 2021-07-05 12:33:03
Now that everything is in place we can shuffle around the conditionals
so it's clearer what we are trying to do.
No functional changes.
Signed-off-by: Felipe Contreras <redacted>
---
builtin/pull.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
@@ -1114,12 +1114,12 @@ int cmd_pull(int argc, const char **argv, const char *prefix)can_ff=get_can_ff(&orig_head,&merge_heads.oid[0]);-if(mode==PULL_MODE_FAST_FORWARD&&!can_ff)-die(_("The pull was not fast-forward, either merge or rebase.\n"));--if(!opt_rebase&&!can_ff){-if(opt_verbosity>=0)+if(!can_ff){+if(!mode&&opt_verbosity>=0)show_advice_pull_non_ff();++if(mode==PULL_MODE_FAST_FORWARD)+die(_("The pull was not fast-forward, either merge or rebase.\n"));}if(opt_rebase>=REBASE_TRUE){
@@ -1118,8 +1118,10 @@ int cmd_pull(int argc, const char **argv, const char *prefix)if(!mode&&opt_verbosity>=0)show_advice_pull_non_ff();-if(mode==PULL_MODE_FAST_FORWARD)+if(mode==PULL_MODE_FAST_FORWARD){+diverging_advice();die(_("The pull was not fast-forward, either merge or rebase.\n"));+}}if(opt_rebase>=REBASE_TRUE){
From: Felipe Contreras <hidden> Date: 2021-07-05 12:33:09
Currently --rebase without argument overrides pull.rebase:
git config pull.rebase merges
git pull --rebase
Up until now this hasn't been a big issue, since user has not been
forced to specify a merge, or a rebase. But with the introduction of
--merge and pull.mode, the user could in theory have the following
configuration:
git config pull.mode merge
git config pull.rebase merges
In such case, the user would expect:
git pull --rebase
To be the same as:
git pull --rebase=merges
If the user wants to override the configuration, she can do:
git pull --rebase=true
Signed-off-by: Felipe Contreras <redacted>
---
builtin/pull.c | 10 ++++++++--
t/t5520-pull.sh | 10 ++++++++++
2 files changed, 18 insertions(+), 2 deletions(-)
From: Felipe Contreras <hidden> Date: 2021-07-05 12:33:10
We don't want to start by recommending a permanent configuration, but a
temporary solution so they start training their fingers and maybe learn
how to do a rebase. So we start with the commands.
Also, we need to be clear about what we mean by "specifying"; merge, or
rebase.
Moreover, it's better use --global in the configuration commands like we
did with push.default.
And finally, point to the documentation that explains what is a
non-fast-forward, and how to solve it:
git help fast-forward
Signed-off-by: Felipe Contreras <redacted>
---
builtin/pull.c | 21 +++++++++++----------
1 file changed, 11 insertions(+), 10 deletions(-)
@@ -979,18 +979,19 @@ static int get_can_ff(struct object_id *orig_head, struct object_id *orig_merge_staticvoidshow_advice_pull_non_ff(void){-advise(_("Pulling without specifying how to reconcile divergent branches is\n"-"discouraged. You can squelch this message by running one of the following\n"-"commands sometime before your next pull:\n"+advise(_("Pulling without specifying how to reconcile divergent branches is discouraged;\n"+"you need to specify if you want a merge, or a rebase.\n""\n"-" git config pull.mode merge # the default strategy\n"-" git config pull.mode rebase\n"-" git config pull.mode fast-forward\n"+" git pull --merge # the default\n"+" git pull --rebase\n""\n"-"You can replace \"git config\" with \"git config --global\" to set a default\n"-"preference for all repositories. You can also pass --rebase, --merge,\n"-"or --ff-only on the command line to override the configured default per\n"-"invocation.\n"));+"You can quell this message by running one of the following commands:\n"+"\n"+" git config --global pull.mode merge\n"+" git config --global pull.mode rebase\n"+" git config --global pull.mode fast-forward\n"+"\n"+"For more information check \"git help fast-forward\"."));}intcmd_pull(intargc,constchar**argv,constchar*prefix)
From: Felipe Contreras <hidden> Date: 2021-07-05 12:33:13
Now that we have `pull.mode=fast-forward`, we can make it the default any
time we want to.
For now, simply explain the upcoming changes in the default warning, and
mention how to turn on the future default mode.
Signed-off-by: Felipe Contreras <redacted>
---
builtin/pull.c | 28 +++++++++++++------------
t/t5520-pull.sh | 8 ++++++++
t/t7601-merge-pull-config.sh | 40 ++++++++++++++++++------------------
3 files changed, 43 insertions(+), 33 deletions(-)
@@ -979,19 +979,21 @@ static int get_can_ff(struct object_id *orig_head, struct object_id *orig_merge_staticvoidshow_advice_pull_non_ff(void){-advise(_("Pulling without specifying how to reconcile divergent branches is discouraged;\n"-"you need to specify if you want a merge, or a rebase.\n"-"\n"-" git pull --merge # the default\n"-" git pull --rebase\n"-"\n"-"You can quell this message by running one of the following commands:\n"-"\n"-" git config --global pull.mode merge\n"-" git config --global pull.mode rebase\n"-" git config --global pull.mode fast-forward\n"-"\n"-"For more information check \"git help fast-forward\"."));+advise(_("The pull was not a fast-forward, in the future you will have to choose\n"+"between a merge or a rebase.\n"+"\n"+"To quell this message you have two main options:\n"+"\n"+"1. Adopt the new behavior:\n"+"\n"+" git config --global pull.mode fast-forward\n"+"\n"+"2. Maintain the current behavior:\n"+"\n"+" git config --global pull.mode merge\n"+"\n"+"For now we will fall back to the traditional behavior: merge.\n"+"For more information check \"git help fast-forward\"."));}intcmd_pull(intargc,constchar**argv,constchar*prefix)
@@ -923,4 +923,12 @@ test_expect_success 'non-fast-forward error message (pull.mode=fast-forward)' 'test_i18ngrep"The pull was not fast-forward"error'+test_expect_success'non-fast-forward warning (default)''+setup_non_ff&&+gitpull2>error&&+caterror&&+test_i18ngrep"The pull was not a fast-forward"error&&+test_i18ngrep"in the future you will have to choose"error+'+ test_done
@@ -30,65 +30,65 @@ test_expect_success 'setup' ' test_expect_success'pull.rebase not set''gitreset--hardc0&&gitpull.c12>err&&-test_i18ngrep!"Pulling without specifying how to reconcile"err+test_i18ngrep!"in the future you will have to choose"err' test_expect_success'pull.mode set''gitreset--hardc0&&test_configpull.modemerge&&gitpull.c12>err&&-test_i18ngrep!"Pulling without specifying how to reconcile"err+test_i18ngrep!"in the future you will have to choose"err' test_expect_success'pull.rebase not set and pull.ff=true''gitreset--hardc0&&test_configpull.fftrue&&gitpull.c12>err&&-test_i18ngrep!"Pulling without specifying how to reconcile"err+test_i18ngrep!"in the future you will have to choose"err' test_expect_success'pull.rebase not set and pull.ff=false''gitreset--hardc0&&test_configpull.fffalse&&gitpull.c12>err&&-test_i18ngrep!"Pulling without specifying how to reconcile"err+test_i18ngrep!"in the future you will have to choose"err' test_expect_success'pull.rebase not set and pull.ff=only''gitreset--hardc0&&test_configpull.ffonly&&gitpull.c12>err&&-test_i18ngrep!"Pulling without specifying how to reconcile"err+test_i18ngrep!"in the future you will have to choose"err' test_expect_success'pull.rebase not set and --rebase given''gitreset--hardc0&&gitpull--rebase.c12>err&&-test_i18ngrep!"Pulling without specifying how to reconcile"err+test_i18ngrep!"in the future you will have to choose"err' test_expect_success'pull.rebase not set and --merge given''gitreset--hardc0&&gitpull--merge.c12>err&&-test_i18ngrep!"Pulling without specifying how to reconcile"err+test_i18ngrep!"in the future you will have to choose"err' test_expect_success'pull.rebase not set and --ff given''gitreset--hardc0&&gitpull--ff.c12>err&&-test_i18ngrep!"Pulling without specifying how to reconcile"err+test_i18ngrep!"in the future you will have to choose"err' test_expect_success'pull.rebase not set and --no-ff given''gitreset--hardc0&&gitpull--no-ff.c12>err&&-test_i18ngrep!"Pulling without specifying how to reconcile"err+test_i18ngrep!"in the future you will have to choose"err' test_expect_success'pull.rebase not set and --ff-only given''gitreset--hardc0&&gitpull--ff-only.c12>err&&-test_i18ngrep!"Pulling without specifying how to reconcile"err+test_i18ngrep!"in the future you will have to choose"err' test_expect_success'pull.rebase not set (not-fast-forward)''
@@ -96,65 +96,65 @@ test_expect_success 'pull.rebase not set (not-fast-forward)' 'git-ccolor.advice=alwayspull.c12>err&&test_decode_color<err>decoded&&test_i18ngrep"<YELLOW>hint: "decoded&&-test_i18ngrep"Pulling without specifying how to reconcile"decoded+test_i18ngrep"in the future you will have to choose"decoded' test_expect_success'pull.mode set''gitreset--hardc2&&test_configpull.modemerge&&gitpull.c12>err&&-test_i18ngrep!"Pulling without specifying how to reconcile"err+test_i18ngrep!"in the future you will have to choose"err' test_expect_success'pull.rebase not set and pull.ff=true (not-fast-forward)''gitreset--hardc2&&test_configpull.fftrue&&gitpull.c12>err&&-test_i18ngrep"Pulling without specifying how to reconcile"err+test_i18ngrep"in the future you will have to choose"err' test_expect_success'pull.rebase not set and pull.ff=false (not-fast-forward)''gitreset--hardc2&&test_configpull.fffalse&&gitpull.c12>err&&-test_i18ngrep"Pulling without specifying how to reconcile"err+test_i18ngrep"in the future you will have to choose"err' test_expect_success'pull.rebase not set and pull.ff=only (not-fast-forward)''gitreset--hardc2&&test_configpull.ffonly&&test_must_failgitpull.c12>err&&-test_i18ngrep"Pulling without specifying how to reconcile"err+test_i18ngrep"in the future you will have to choose"err' test_expect_success'pull.rebase not set and --rebase given (not-fast-forward)''gitreset--hardc2&&gitpull--rebase.c12>err&&-test_i18ngrep!"Pulling without specifying how to reconcile"err+test_i18ngrep!"in the future you will have to choose"err' test_expect_success'pull.rebase not set and --merge given (not-fast-forward)''gitreset--hardc2&&gitpull--merge.c12>err&&-test_i18ngrep!"Pulling without specifying how to reconcile"err+test_i18ngrep!"in the future you will have to choose"err' test_expect_success'pull.rebase not set and --ff given (not-fast-forward)''gitreset--hardc2&&gitpull--ff.c12>err&&-test_i18ngrep"Pulling without specifying how to reconcile"err+test_i18ngrep"in the future you will have to choose"err' test_expect_success'pull.rebase not set and --no-ff given (not-fast-forward)''gitreset--hardc2&&gitpull--no-ff.c12>err&&-test_i18ngrep"Pulling without specifying how to reconcile"err+test_i18ngrep"in the future you will have to choose"err' test_expect_success'pull.rebase not set and --ff-only given (not-fast-forward)''gitreset--hardc2&&test_must_failgitpull--ff-only.c12>err&&-test_i18ngrep"Pulling without specifying how to reconcile"err+test_i18ngrep"in the future you will have to choose"err' test_expect_success'merge c1 with c2''
From: Felipe Contreras <hidden> Date: 2021-07-05 12:33:14
The user has been warned that this change was coming and should have
already configured his/her preference.
It's time to flip the switch and make ff-only the default.
There's no need for the annoying warning anymore.
Signed-off-by: Felipe Contreras <redacted>
---
Documentation/git-pull.txt | 3 +
builtin/pull.c | 30 +-------
t/t5520-pull.sh | 28 +++-----
t/t7601-merge-pull-config.sh | 130 -----------------------------------
4 files changed, 16 insertions(+), 175 deletions(-)
@@ -35,6 +35,9 @@ Default values for <repository> and <branch> are read from the "remote" and "merge" configuration for the current branch as set by linkgit:git-branch[1] `--track`.+By default non-fast-forward merges fail, so you need to specify if you want to+do a merge or a rebase.+ Assume the following history exists and the current branch is "`master`":
@@ -977,25 +977,6 @@ static int get_can_ff(struct object_id *orig_head, struct object_id *orig_merge_returnret;}-staticvoidshow_advice_pull_non_ff(void)-{-advise(_("The pull was not a fast-forward, in the future you will have to choose\n"-"between a merge or a rebase.\n"-"\n"-"To quell this message you have two main options:\n"-"\n"-"1. Adopt the new behavior:\n"-"\n"-" git config --global pull.mode fast-forward\n"-"\n"-"2. Maintain the current behavior:\n"-"\n"-" git config --global pull.mode merge\n"-"\n"-"For now we will fall back to the traditional behavior: merge.\n"-"For more information check \"git help fast-forward\"."));-}-intcmd_pull(intargc,constchar**argv,constchar*prefix){constchar*repo,**refspecs;
@@ -1123,14 +1104,9 @@ int cmd_pull(int argc, const char **argv, const char *prefix)can_ff=get_can_ff(&orig_head,&merge_heads.oid[0]);-if(!can_ff){-if(!mode&&opt_verbosity>=0)-show_advice_pull_non_ff();--if(mode==PULL_MODE_FAST_FORWARD){-diverging_advice();-die(_("The pull was not fast-forward, either merge or rebase.\n"));-}+if((!mode||mode==PULL_MODE_FAST_FORWARD)&&!can_ff){+diverging_advice();+die(_("The pull was not fast-forward, either merge or rebase.\n"));}if(opt_rebase>=REBASE_TRUE){
@@ -897,38 +897,30 @@ setup_non_ff () {setup_othermain^}-test_expect_success'fast-forward (pull.mode=fast-forward)''+test_expect_success'fast-forward (default)''setup_ff&&-git-cpull.mode=fast-forwardpull+gitpull'-test_expect_success'non-fast-forward (pull.mode=fast-forward)''+test_expect_success'non-fast-forward (default)''setup_non_ff&&-test_must_failgit-cpull.mode=fast-forwardpull+test_must_failgitpull'-test_expect_success'non-fast-forward with merge (pull.mode=fast-forward)''+test_expect_success'non-fast-forward with merge (default)''setup_non_ff&&-git-cpull.mode=fast-forwardpull--merge+gitpull--merge'-test_expect_success'non-fast-forward with rebase (pull.mode=fast-forward)''+test_expect_success'non-fast-forward with rebase (default)''setup_non_ff&&-git-cpull.mode=fast-forwardpull--rebase+gitpull--rebase'-test_expect_success'non-fast-forward error message (pull.mode=fast-forward)''+test_expect_success'non-fast-forward error message (default)''setup_non_ff&&-test_must_failgit-cpull.mode=fast-forwardpull2>error&&+test_must_failgitpull2>error&&test_i18ngrep"The pull was not fast-forward"error'-test_expect_success'non-fast-forward warning (default)''-setup_non_ff&&-gitpull2>error&&-caterror&&-test_i18ngrep"The pull was not a fast-forward"error&&-test_i18ngrep"in the future you will have to choose"error-'- test_done
@@ -27,136 +27,6 @@ test_expect_success 'setup' 'gittagc3'-test_expect_success'pull.rebase not set''-gitreset--hardc0&&-gitpull.c12>err&&-test_i18ngrep!"in the future you will have to choose"err-'--test_expect_success'pull.mode set''-gitreset--hardc0&&-test_configpull.modemerge&&-gitpull.c12>err&&-test_i18ngrep!"in the future you will have to choose"err-'--test_expect_success'pull.rebase not set and pull.ff=true''-gitreset--hardc0&&-test_configpull.fftrue&&-gitpull.c12>err&&-test_i18ngrep!"in the future you will have to choose"err-'--test_expect_success'pull.rebase not set and pull.ff=false''-gitreset--hardc0&&-test_configpull.fffalse&&-gitpull.c12>err&&-test_i18ngrep!"in the future you will have to choose"err-'--test_expect_success'pull.rebase not set and pull.ff=only''-gitreset--hardc0&&-test_configpull.ffonly&&-gitpull.c12>err&&-test_i18ngrep!"in the future you will have to choose"err-'--test_expect_success'pull.rebase not set and --rebase given''-gitreset--hardc0&&-gitpull--rebase.c12>err&&-test_i18ngrep!"in the future you will have to choose"err-'--test_expect_success'pull.rebase not set and --merge given''-gitreset--hardc0&&-gitpull--merge.c12>err&&-test_i18ngrep!"in the future you will have to choose"err-'--test_expect_success'pull.rebase not set and --ff given''-gitreset--hardc0&&-gitpull--ff.c12>err&&-test_i18ngrep!"in the future you will have to choose"err-'--test_expect_success'pull.rebase not set and --no-ff given''-gitreset--hardc0&&-gitpull--no-ff.c12>err&&-test_i18ngrep!"in the future you will have to choose"err-'--test_expect_success'pull.rebase not set and --ff-only given''-gitreset--hardc0&&-gitpull--ff-only.c12>err&&-test_i18ngrep!"in the future you will have to choose"err-'--test_expect_success'pull.rebase not set (not-fast-forward)''-gitreset--hardc2&&-git-ccolor.advice=alwayspull.c12>err&&-test_decode_color<err>decoded&&-test_i18ngrep"<YELLOW>hint: "decoded&&-test_i18ngrep"in the future you will have to choose"decoded-'--test_expect_success'pull.mode set''-gitreset--hardc2&&-test_configpull.modemerge&&-gitpull.c12>err&&-test_i18ngrep!"in the future you will have to choose"err-'--test_expect_success'pull.rebase not set and pull.ff=true (not-fast-forward)''-gitreset--hardc2&&-test_configpull.fftrue&&-gitpull.c12>err&&-test_i18ngrep"in the future you will have to choose"err-'--test_expect_success'pull.rebase not set and pull.ff=false (not-fast-forward)''-gitreset--hardc2&&-test_configpull.fffalse&&-gitpull.c12>err&&-test_i18ngrep"in the future you will have to choose"err-'--test_expect_success'pull.rebase not set and pull.ff=only (not-fast-forward)''-gitreset--hardc2&&-test_configpull.ffonly&&-test_must_failgitpull.c12>err&&-test_i18ngrep"in the future you will have to choose"err-'--test_expect_success'pull.rebase not set and --rebase given (not-fast-forward)''-gitreset--hardc2&&-gitpull--rebase.c12>err&&-test_i18ngrep!"in the future you will have to choose"err-'--test_expect_success'pull.rebase not set and --merge given (not-fast-forward)''-gitreset--hardc2&&-gitpull--merge.c12>err&&-test_i18ngrep!"in the future you will have to choose"err-'--test_expect_success'pull.rebase not set and --ff given (not-fast-forward)''-gitreset--hardc2&&-gitpull--ff.c12>err&&-test_i18ngrep"in the future you will have to choose"err-'--test_expect_success'pull.rebase not set and --no-ff given (not-fast-forward)''-gitreset--hardc2&&-gitpull--no-ff.c12>err&&-test_i18ngrep"in the future you will have to choose"err-'--test_expect_success'pull.rebase not set and --ff-only given (not-fast-forward)''-gitreset--hardc2&&-test_must_failgitpull--ff-only.c12>err&&-test_i18ngrep"in the future you will have to choose"err-'- test_expect_success'merge c1 with c2''gitreset--hardc1&&test-fc0.c&&
@@ -226,7 +226,7 @@ test_expect_success 'fail if the index has unresolved entries' 'test_commitmodified2file&&gitls-files-u>unmerged&&test_must_be_emptyunmerged&&-test_must_failgitpull.second&&+test_must_failgitpull--merge.second&&gitls-files-u>unmerged&&test_file_not_emptyunmerged&&cpfileexpected&&
@@ -108,27 +108,27 @@ test_expect_success 'setup commit on main and other pull' ' test_expect_success'pull --set-upstream upstream main sets branch main but not other''clear_configmainother&&-gitpull--set-upstreamupstreammain&&+gitpull--merge--set-upstreamupstreammain&&check_configmainupstreamrefs/heads/main&&check_config_missingother' test_expect_success'pull --set-upstream main:other2 does not set the branch other2''clear_configother2&&-gitpull--set-upstreamupstreammain:other2&&+gitpull--merge--set-upstreamupstreammain:other2&&check_config_missingother2' test_expect_success'pull --set-upstream upstream other sets branch main''clear_configmainother&&-gitpull--set-upstreamupstreamother&&+gitpull--merge--set-upstreamupstreamother&&check_configmainupstreamrefs/heads/other&&check_config_missingother' test_expect_success'pull --set-upstream upstream tag does not set the tag''clear_configthree&&-gitpull--tags--set-upstreamupstreamthree&&+gitpull--merge--tags--set-upstreamupstreamthree&&check_config_missingthree'
@@ -144,16 +144,16 @@ test_expect_success 'pull --set-upstream http://nosuchdomain.example.com fails w test_expect_success'pull --set-upstream upstream HEAD sets branch HEAD''clear_configmainother&&-gitpull--set-upstreamupstreamHEAD&&+gitpull--merge--set-upstreamupstreamHEAD&&check_configmainupstreamHEAD&&gitcheckoutother&&-gitpull--set-upstreamupstreamHEAD&&+gitpull--merge--set-upstreamupstreamHEAD&&check_configotherupstreamHEAD' test_expect_success'pull --set-upstream upstream with more than one branch does nothing''clear_configmainthree&&-gitpull--set-upstreamupstreammainthree&&+gitpull--merge--set-upstreamupstreammainthree&&check_config_missingmain&&check_config_missingthree'
@@ -87,7 +87,7 @@ test_expect_success 'updating origin' '' test_expect_success'pulling changes from origin''-git-CCpullorigin+git-CCpull--mergeorigin'# the 2 local objects are commit and tree from the merge
@@ -96,7 +96,7 @@ test_expect_success 'that alternate to origin gets used' '' test_expect_success'pulling changes from origin''-git-CDpullorigin+git-CDpull--mergeorigin'# the 5 local objects are expected; file3 blob, commit in A to add it
@@ -173,7 +173,7 @@ test_expect_success 'interference with untracked working tree file' 'gitreset--hard&&gitshow-branch&&echo>Athisfileshouldnotmatter&&-test_expect_code1gitpull.white&&+test_expect_code1gitpull--merge.white&&test_path_is_fileA'
@@ -183,7 +183,7 @@ test_expect_success 'interference with untracked working tree file' 'gitshow-branch&&rm-fA&&echo>Athisfileshouldnotmatter&&-test_expect_code1gitpull.red&&+test_expect_code1gitpull--merge.red&&test_path_is_fileA'
@@ -193,7 +193,7 @@ test_expect_success 'interference with untracked working tree file' 'gitcheckout-fmain&&gittag-fanchor&&gitshow-branch&&-gitpull.yellow&&+gitpull--merge.yellow&&test_path_is_missingM&&gitreset--hardanchor'
@@ -232,7 +232,7 @@ test_expect_success 'interference with untracked working tree file' 'gittag-fanchor&&gitshow-branch&&echo>Mthisfileshouldnotmatter&&-gitpull.main&&+gitpull--merge.main&&test_path_is_fileM&&!{gitls-files-s|
@@ -1620,7 +1620,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)}if(fast_forward==FF_ONLY)-die(_("Not possible to fast-forward, aborting."));+die(_("unable to fast-forward"));
I read the existing message a bit more like "this makes no sense
anymore" (correct) and the latter more like "we encountered an
error". Perhaps something like:
"Can't merge X with Y, in --ff-only mode, would need to create a merge commit", tip_name
@@ -326,3 +326,14 @@ void detach_advice(const char *new_name)fprintf(stderr,fmt,new_name);}++voiddiverging_advice(void)+{+advise(_("Diverging branches can't be fast-forwarded, you need to either:\n"+"\n"+"\tgit merge\n"+"\n"+"or:\n"+"\n"+"\tgit rebase\n"));+}
@@ -1625,8 +1625,10 @@ static int merge_common(int argc, const char **argv, const char *prefix,}}-if(fast_forward==FF_ONLY)+if(fast_forward==FF_ONLY){+diverging_advice();die(_("unable to fast-forward"));+}if(autostash)create_autostash(the_repository,
...ah, and re my comment on the earlier patch here's where we're adding
advice.
I'd think just squash that into this, or mention in the commit message
"a later commit will add an advice() before this, where this new wording
will make more sense" or something...
Nit: If the value isn't important let's leave it out, also if you add a
trailing comma the subsequent commit where you add another value is less
churny. C supports that just fine.
@@ -29,6 +29,10 @@ OPTIONS --ff:: Forces a fast-forward.+-m::+--merge::+ Forces a merge.+ SEE ALSO -------- linkgit:git-fetch[1], linkgit:git-fast-forward[1],
@@ -1620,7 +1620,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)}if(fast_forward==FF_ONLY)-die(_("Not possible to fast-forward, aborting."));+die(_("unable to fast-forward"));
I read the existing message a bit more like "this makes no sense
anymore" (correct) and the latter more like "we encountered an
error".
I mean, this is the documentation of --ff-only:
With `--ff-only`, resolve the merge as a fast-forward when possible.
When not possible, refuse to merge and exit with a non-zero status.
So if you do `git merge --ff-only` you are telling git: "I want you to
exit with an error when the fast-forward is not possible".
If you do:
% git merge --ff-only
fatal: Not possible to fast-forward, aborting.
That "aborting" part is redundant; we know `git merge` should abort if
the fast-forward is not possible, we explicitely told git to do that.
Moreover the "fatal: " prefix also indicates that git aborted.
Then you have "Not possible to fast-forward", which if memory serves
well should be in lowercase (altghough can't find that in the
guidelines).
"unable to fast-forward" is simply a more succinct way of saying
"not possible to fast-forward". Sure, we are not explaining why,
although I can't think of any other reason why we could not fast-forward.
Perhaps something like:
"Can't merge X with Y, in --ff-only mode, would need to create a merge commit", tip_name
I don't think die() messages should be that big, how about?
branches diverged, can't fast-forward
--
Felipe Contreras
From: Felipe Contreras <hidden> Date: 2021-07-06 20:42:39
Ævar Arnfjörð Bjarmason wrote:
On Mon, Jul 05 2021, Felipe Contreras wrote:
quoted
--- a/builtin/merge.c+++ b/builtin/merge.c
@@ -1625,8 +1625,10 @@ static int merge_common(int argc, const char **argv, const char *prefix,}}-if(fast_forward==FF_ONLY)+if(fast_forward==FF_ONLY){+diverging_advice();die(_("unable to fast-forward"));+}if(autostash)create_autostash(the_repository,
...ah, and re my comment on the earlier patch here's where we're adding
advice.
I'd think just squash that into this, or mention in the commit message
"a later commit will add an advice() before this, where this new wording
will make more sense" or something...
I don't think we lost any information in the previous patch. In fact
with my suggestion we gained a little bit.
--
Felipe Contreras
Nit: If the value isn't important let's leave it out,
Yes, in one instantiation of the series it did matter, but not in the
current one. I'll drop it.
also if you add a trailing comma the subsequent commit where you add
another value is less churny. C supports that just fine.
I know, and I actually prefer that style, but I've seen the comma
dropped in many instances in the current code base. I was just following
the current style.
But if you prefer it as well I'll add it.
--
Felipe Contreras
diff --git a/builtin/merge.c b/builtin/merge.c index
a8a843b1f5..05e631229d 100644
--- a/builtin/merge.c+++ b/builtin/merge.c
@@ -1620,7 +1620,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)}if(fast_forward==FF_ONLY)-die(_("Not possible to fast-forward, aborting."));+die(_("unable to fast-forward"));
I read the existing message a bit more like "this makes no sense
anymore" (correct) and the latter more like "we encountered an error".
I mean, this is the documentation of --ff-only:
With `--ff-only`, resolve the merge as a fast-forward when possible.
When not possible, refuse to merge and exit with a non-zero status.
So if you do `git merge --ff-only` you are telling git: "I want you to exit with an error when the fast-forward is not possible".
If you do:
% git merge --ff-only
fatal: Not possible to fast-forward, aborting.
That "aborting" part is redundant; we know `git merge` should abort if the fast-forward is not possible, we explicitely told git to do that.
`git merge` is a special operation where errors (conflicts, for one) may leave the repository in a merge pending state where you subsequently may have to use `git merge --abort` to reset the situation or `git add` to continue. The `aborting` output makes it clear that you do not have to do the `--abort` and *cannot* do the `add` because there was an implicit `--abort` done resulting from the failure. This is important information for the user.
OK. Sure.
FTR. These tests come from 2013, they don't fit my current style and I
wanted to rewrite them completely since there's a lot of duplicated
code. But I thought: what the hell, they work. Plus there's only so much
time I'm willing to spend on an RFC v1 of this series (which probably
won't be merged anyway).
Cheers.
--
Felipe Contreras
diff --git a/builtin/merge.c b/builtin/merge.c index
a8a843b1f5..05e631229d 100644
--- a/builtin/merge.c+++ b/builtin/merge.c
@@ -1620,7 +1620,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)}if(fast_forward==FF_ONLY)-die(_("Not possible to fast-forward, aborting."));+die(_("unable to fast-forward"));
I read the existing message a bit more like "this makes no sense
anymore" (correct) and the latter more like "we encountered an error".
I mean, this is the documentation of --ff-only:
With `--ff-only`, resolve the merge as a fast-forward when possible.
When not possible, refuse to merge and exit with a non-zero status.
So if you do `git merge --ff-only` you are telling git: "I want you to exit with an error when the fast-forward is not possible".
If you do:
% git merge --ff-only
fatal: Not possible to fast-forward, aborting.
That "aborting" part is redundant; we know `git merge` should abort if the fast-forward is not possible, we explicitely told git to do that.
`git merge` is a special operation where errors (conflicts, for one)
may leave the repository in a merge pending state where you
subsequently may have to use `git merge --abort` to reset the
situation or `git add` to continue. The `aborting` output makes it
clear that you do not have to do the `--abort` and *cannot* do the
`add` because there was an implicit `--abort` done resulting from the
failure.
But this is not a `git merge`, this is a `git merge --ff-only`; they are
different operations. There *never* is a need for `--abort` with
`git merge --ff-only`.
Anyway, the error message is meant for `git fast-forward` which
definitely doesn't need any `--abort`.
Initially I created a new variable to have a different error message for
`git merge --ff-only` and `git fast-forward`, precisely to avoid
changing the current error message of `git merge --ff-only` and thus
avoid any inertial comments like this one. But then I thought there was
no need to complicate the series when both can be improved at once.
Apparently that's not the case.
I guess I'll add it back.
Cheers.
--
Felipe Contreras
diff --git a/builtin/merge.c b/builtin/merge.c index
a8a843b1f5..05e631229d 100644
--- a/builtin/merge.c+++ b/builtin/merge.c
@@ -1620,7 +1620,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)}if(fast_forward==FF_ONLY)-die(_("Not possible to fast-forward, aborting."));+die(_("unable to fast-forward"));
I read the existing message a bit more like "this makes no sense
anymore" (correct) and the latter more like "we encountered an error".
I mean, this is the documentation of --ff-only:
With `--ff-only`, resolve the merge as a fast-forward when possible.
When not possible, refuse to merge and exit with a non-zero status.
So if you do `git merge --ff-only` you are telling git: "I want you to exit with an error when the fast-forward is not possible".
If you do:
% git merge --ff-only
fatal: Not possible to fast-forward, aborting.
That "aborting" part is redundant; we know `git merge` should abort if the fast-forward is not possible, we explicitely told git to do that.
`git merge` is a special operation where errors (conflicts, for one)
may leave the repository in a merge pending state where you
subsequently may have to use `git merge --abort` to reset the
situation or `git add` to continue. The `aborting` output makes it
clear that you do not have to do the `--abort` and *cannot* do the
`add` because there was an implicit `--abort` done resulting from the
failure.
But this is not a `git merge`, this is a `git merge --ff-only`; they are different operations. There *never* is a need for `--abort` with `git
merge --ff-only`.
Well, you know that and I know that, but having to explain this to every new git user who will operationally use git merge --ff-only within hours or days of their first clone is a different matter.
Anyway, the error message is meant for `git fast-forward` which definitely doesn't need any `--abort`.
Initially I created a new variable to have a different error message for `git merge --ff-only` and `git fast-forward`, precisely to avoid
changing the current error message of `git merge --ff-only` and thus avoid any inertial comments like this one. But then I thought there
was no need to complicate the series when both can be improved at once.
Apparently that's not the case.
I guess I'll add it back.
From: Felipe Contreras <hidden> Date: 2021-07-06 22:14:12
Randall S. Becker wrote:
On July 6, 2021 5:12 PM, Felipe Contreras wrote:
quoted
But this is not a `git merge`, this is a `git merge --ff-only`; they
are different operations. There *never* is a need for `--abort` with
`git merge --ff-only`.
Well, you know that and I know that, but having to explain this to
every new git user who will operationally use git merge --ff-only
within hours or days of their first clone is a different matter.
New users don't do `git merge --ff-only`, they very likely don't do
`git merge` either, nor do they do `git pull --ff-only`. This is obvious
from the countless threads where users do `git pull` without knowing
that they will create a true merge by mistake.
Even less likely is that they will know about `git merge --abort`, and even
less that they will know both `git merge --ff-only` and
`git merge --abort`.
Even even less likely that they will mistakenly expect
`git merge --ff-only` to be left inside a temporary stated to be
resolved by `git merge --abort`.
But as Junio said, *if* such a hypothetical user exists, we don't want
to keep misleading them into thinking that a true merge was somehow
aborted, because it wasn't.
It's much better to simply let go the current error message.
Cheers.
--
Felipe Contreras