Thread (17 messages) 17 messages, 6 authors, 2016-06-15

Re: [PATCH 0/3] Reject non-ff pulls by default

From: Richard Hansen <hidden>
Date: 2016-06-15 22:58:38

On 2013-09-04 18:59, Junio C Hamano wrote:
"Philip Oakley" [off-list ref] writes:
quoted
From: "Junio C Hamano" <redacted>
quoted
John Keeping [off-list ref] writes:
quoted
I think there are two distinct uses for pull, which boil down to:

    (1) git pull
...
Peff already covered (1)---it is highly doubtful that a merge is
"almost always wrong".  In fact, if that _were_ the case, we should
simply be defaulting to rebase, not failing the command and asking
between merge and rebase like jc/pull-training-wheel topic did.

We simply do not know what the user wants, as it heavily depends on
the project, so we ask the user to choose one (and stick to it).
We only offer a limited list. It won't be sufficient for all use
cases. It wasn't for me.
Very interesting. Tell us more.
I'm a bit late to the discussion, but I wanted to chime in.  I detest
'git pull' and discourage everyone I meet from using it.  See:
<http://stackoverflow.com/questions/15316601/why-is-git-pull-considered-harmful>
for my reasons.

Instead, I encourage people to do this:

   git config --global alias.up '!git remote update -p; git merge
--ff-only @{u}'

and tell them to run 'git up' whenever they would be tempted to use a
plain 'git pull'.

I usually work with a central repository with topic branches.  I follow
this rule of thumb:
  * When merging a "same-named" branch (e.g., origin/foo into foo, foo
    into origin/foo), it should always be a fast-forward.  This may
    require rebasing.
  * When merging a "differently-named" branch (e.g., feature.xyz into
    master), it should never be a fast-forward.

In distributed workflows, I think of 'git pull <collaborator-repo>
<their-branch>' as merging a differently-named branch (I wouldn't be
merging if they hadn't told me that a separate feature they were working
on is complete), so I generally want the merge commit.  But when I do a
'git pull' without extra arguments, I'm updating a same-named branch so
I never want a merge.

When merging a differently-named branch, I prefer the merge --no-ff to
be preceded by a rebase to get a nice, pretty graph:

       * merge feature.xyz  <- master
       |\
       | * xyz part 3/3
       | * xyz part 2/3
       | * xyz part 1/3
       |/
       * merge feature.foo
       |\
       | * foo part 2/2
       | * foo part 1/2
       |/
       * merge feature.bar
       |\
       ...

The explicit merge has several benefits:
  * It clearly communicates to others that the feature is done.
  * It makes it easier to revert the entire feature by reverting the
    merge if necessary.
  * It allows our continuous integration tool to skip over the
    work-in-progress commits and test only complete features.
  * It makes it easier to review the entire feature in one diff.
  * 'git log --first-parent' shows a high-level summary of the changes
    over time, while a normal 'git log' shows the details.
When "git pull" stops because what was fetched in FETCH_HEAD does
not fast-forward, then what did _you_ do (and with the knowledge you
currently have, what would you do)?
I stop and review what's going on, then make a decision:
  * usually it's a rebase
  * sometimes it's a rebase --onto (because the branch was
    force-updated to undo a particularly bad commit)
  * sometimes it's a rebase -p (because there's an explicit merge of a
    different branch that I want to keep)
  * sometimes it's a reset --hard (my changes were made obsolete by a
    different upstream change)
  * sometimes it's a merge
  * sometimes I do nothing.  This is a fairly regular pattern:  I'm in
    the middle of working on something that I know will conflict with
    some changes that were just pushed upstream, and I want to finish
    my changes before starting the rebase.  My collaborator contacts me
    and asks, "Would you take a look at the changes I just pushed?"  If
    I type 'git pull' out of habit to get the commits, then I'll make a
    mess of my work-in-progress work tree.  If I type 'git up' out of
    habit, then the merge --ff-only will fail as expected and I can
    quickly review the commits without messing with my work tree or
    HEAD.

Even if I always rebase or always merge, I want to briefly review what
changed in the remote branch *before* I start the rebase.  This helps me
understand the conflicts I might encounter.

Thus, ff-only always works for me.  I might have to type a second merge
or rebase command, but that's OK -- it gives me an opportunity to think
about what I want first.  Non-ff merges are rare enough that the
interruption isn't annoying at all.
In a single project, would you
choose to sometimes rebase and sometimes merge, and if so, what is
the choice depend on?  "When I am on these selected branches, I want
to merge, but on other branches I want to rebase?"
My choice depends on the circumstances of the divergence.  It's never as
simple as branch X always has this policy while branch Y has that policy.
Are there cases where you do not want to either rebase nor merge?
If so what do you want to do after "git pull" fetches from the other
side?  Nothing?

	Side note: a knee-jerk response to a "yes" answer to the
	last question from me has always been "then why are you
	running 'git pull' in the first place.
Habit/muscle memory/I'm tired and not thinking 100% clearly.

-Richard
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help