Re: Pull is Mostly Evil
From: Felipe Contreras <hidden>
Date: 2016-06-15 23:00:59
Richard Hansen wrote:
I think the fundamental difference is in the relationship between the local and the remote branch (which branch derives from the other). The relationship between the branches determines what the user wants from 'git pull'. In my experience 'git pull' is mostly (only?) used for the following three tasks:
I agree.
1. update a local branch to incorporate the latest upstream changes
In this case, the local branch (master) is a derivative of the
upstream branch (origin/master). The user wants all of the
commits in the remote branch to be in the local branch. And the
user would like the local changes, if any, to descend from the tip
of the remote branch.My current propsal of making `git pull` by default do --ff-only would solve this. In addition I think by default 'master' should be merged to 'origin/master', if say --merge is given.
For this case, 'git pull --ff-only' followed by 'git rebase -p'
works well, as does 'git pull --rebase=preserve' if the user is
comfortable rebasing without reviewing the incoming commits first.I suppose you mean a `git rebase -p` if the `git pull --ff-only` failed. This might be OK on most projects, but not all. What happens after a `git pull --ff-only` fails should be totally up to the user.
2. update a published feature branch with the latest changes from its
parent branch
In this case, the local branch (foo) is a derivative of the
upstream branch (origin/foo) which is itself a derivative of
another branch (origin/master). All commits in origin/master
should be in origin/foo, and ideally all commits unique to
origin/foo would descend from the tip of origin/master.I don't understand why are you tainting the example with 'origin/foo', 'foo' and 'origin/master' are enough for this example. In fact, the mention of 'origin/master' made it wrong: after the pull not all the commits of origin/master would be in origin/foo, you need a push for that. We have enough in our plate to taint this with yet another branch and push. For this case `git pull origin master` already work correctly for most projects. We probably shouldn't change that.
3. integrate a more-or-less complete feature/fix back into the line
of development it forked off of
In this case the local branch is a primary line of development and
the remote branch contains the derivative work. Think Linus
pulling in contributions. Different situations will call for
different ways to handle this case, but most will probably want
some or all of:
* rebase the remote commits onto local HEADNo. Most people will merge the remote branch as it is. There's no reason to rebase, specially if you are creating a merge commit.
* merge into local HEAD so that the first parent (if a real merge
and not a ff) is the previous version of the main line of
development and the second parent is the derivative work
* merge --no-ff so that:
- the merge can serve as a cover letter (who reviewed it,
which bug reports were fixed, where the changes came from,
etc.)
- the commits that compose the new topic are grouped together
- the first-parent path represents a series of completed tasksIt is very rare that an integrator is even able to do a fast-forward merge anyway. So being explicit about --no-ff might better, but it would hardly make a difference. Either way, a good integrator would configure pull.ff = false. I'd say `git pull origin master` already works fine for this case. -- Felipe Contreras