2022-01-31
Git 2.34 has changed how you configure fast-forward only pulls and rebasing
I'll start with the conclusion and give you the story afterward.
Before Git 2.34, if you were tracking upstream repositories and
perhaps carrying local changes on top,
it was sensible to configure 'pull.ff only
' globally (in your
~/.gitconfig) to stop 'git pull
' from warning you and then set
'pull.rebase true
' in repositories that you had local changes in.
As of Git 2.34, this causes a plain 'git pull
' to abort in any
repository that has local changes. The simplest fix is to also set
'git config pull.ff true
'
in each repository where you've set pull.rebase. This may become
unnecessary in some future Git version, because the Git 2.34 behavior
may be a bug.
When Git started out, 'git pull
'
defaulted to trying to fast-forward what had been fetched and then
automatically doing a merge if it wasn't possible (basically to
'git pull -ff
', although I'm not sure they're exactly the same).
In theory this was what you wanted as a developer; in practice it
was easy to get surprise merges that you didn't want in various
situations. Soon people began suggesting that you use 'git pull
--ff-only
' or better yet, configure 'pull.ff only
' through git
config
. At a certain point,
the Git developers themselves decided this wasn't the greatest
default and began having 'git pull
' warn about it and ask you
to do something about it (cf).
I started out setting 'pull.ff only
' on some repositories as part
of my multi-repo workflow or tracking
some upstreams. When Git started warning
about plain 'git pull
' with nothing configured, I upgraded this
to a global setting of 'pull.ff only
' in my ~/.gitconfig, since
I didn't have any repositories where I want to automatically pull
and merge. Almost always I'm either exactly tracking an upstream
(where I'm going to reset to origin/main if the upstream does
something weird) or I'm carrying local changes that I want to
automatically rebase on top of the new
upstream. For a long time this worked fine, and then I updated to
the Fedora 34 version of Git 2.34.1 and suddenly my automatic
rebasing on pulls broke (you can read an example in my Fedora bug
report).
As of Git 2.34, two things have changed. First, the default behavior
of 'git pull' is now to abort if it can't fast-forward the upstream
into your local branch (ie, 'git pull --ff-only
'); basically,
the previous warning has become an error.
Second, the configuration setting of 'pull.ff only
' now takes
priority over 'pull.rebase true
' (although not over an explicit
--rebase on the command line). If you have both in a repository
with things to rebase, you effectively wind up running 'git pull
--ff-only
', which fails because you have additional local changes
that Git thinks would have to be merged. The behavior of 'pull.ff
only' here may be an accidental bug and is certainly not historical
behavior, but we have to deal with the Git release we get, not the
one we'd like.
(This isn't explicitly documented in the release notes (also),
although they do talk about a general overhaul of this area.
The 2.34 manual pages are not the clearest about the behavior
and they don't explicitly say that 'pull.ff only' takes priority,
although the git pull
manpage somewhat implies that --ff-only
conflicts with --rebase.)
As far as I can see, I have two options to get the behavior I want.
First, I can continue to set 'pull.ff only
' globally, for safety,
and then set 'pull.ff true
' in any repository where I also set
'pull.rebase true
'. I'm not sure that this is completely harmless
in old versions of Git, though. The other option, if I'm only going
to be using Git 2.34 and later and I trust Git not to make any
surprising changes here, is to not set pull.ff
globally and set
only 'pull.rebase true
' in my 'I have changes on top of upstream'
repositories that I want to automatically rebase on pulls.
(I've tested both approaches and they appear to work. Carefully
reading the Git source code confirms that 'git pull --ff-only
'
is basically the default, although it's not actually implemented
quite that way. See builtin/pull.c for the
gory details.)
PS: A nice long history of the changes in this area in 'git pull' from 2020 or so onward is here. There have been a number of steps. The history has already been updated a bit for Git 2.35 and may be updated more in the future, so check in on it for the latest news.