Why am I merging "remote-tracking branch 'origin/develop' into develop"?
Asked Answered
S

3

160

I'm the only one in my organization who's making commits with the following message:

Merge remote-tracking branch 'origin/develop' into develop

Not sure what I'm doing to cause them, but I'd like to stop.

What command am I issuing to create this commit, and what is the proper command I ought to be using to not produce it?

Smalley answered 20/6, 2011 at 4:15 Comment(2)
The answer made by Richard Hansen is fine. But I think it could be confusing for beginners. My solution is to keep doing pull --rebase but to avoid the danger, I stash my changes before the pull. Then, after pulling, I apply it. I resolve conflicts. Finally I can commit & push.Propagandize
Does git pull --autostash --rebase work for you @Johnjohn?Corallite
A
244

git pull is probably creating the commit. If you make a local commit and then run git pull after someone else pushes a commit up to the repository, Git downloads the other developer's commit and then merges it into your local branch.

How to avoid these merge commits in the future

You could use git pull --rebase to prevent this from happening in the future, but rebasing has its perils, and I recommend avoiding pull altogether.

Instead, I encourage you to follow this usage pattern:

# download the latest commits
git remote update -p

# update the local branch
git merge --ff-only @{u}

# if the above fails with a complaint that the local branch has
# diverged:
git rebase -p @{u}

Explanation

  • git remote update -p downloads all of the commits in the remote repositories and updates the remote tracking branches (e.g., origin/master). It does NOT touch your working directory, index, or local branches.

    The -p argument prunes deleted upstream branches. Thus, if the foo branch is deleted in the origin repository, git remote update -p will automatically delete your origin/foo ref.

  • git merge --ff-only @{u} tells Git to merge the upstream branch (the @{u} argument) into your local branch but only if your local branch can be "fast forwarded" to the upstream branch (in other words, if it hasn't diverged).

  • git rebase -p @{u} effectively moves the commits you've made but haven't yet pushed on top of the upstream branch, which eliminates the need to create the silly merge commits you're trying to avoid. This improves the linearity of the development history, making it easier to review.

    The -p option tells Git to preserve merges. This prevents Git from linearizing the commits being rebased. This is important if, for example, you merged a feature branch into master. Without -p, every commit on the feature branch would be duplicated on master as part of the linearization done by git rebase. This would make the development history harder to review, not easier.

    Beware: git rebase might not do what you expect it to do, so review the results before pushing. For example:

    git log --graph --oneline --decorate --date-order --color --boundary @{u}..
    

I prefer this approach over git pull --rebase for the following reasons:

  • It allows you to see the incoming upstream commits before your modify your history to incorporate them.
  • It allows you to pass the -p (--preserve-merges) option to git rebase in case you need to rebase an intentional merge (e.g., merge of an already-pushed feature branch into master).

Shorthand: git up instead of git pull

To make it easy to do the above, I recommend creating an alias called up:

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

Now all you need to do to bring your branch up to date is to run:

git up

instead of git pull. If you get an error because your local branch has diverged from the upstream branch, that's your cue to rebase.

Why not git pull --rebase?

Running git pull --rebase is equivalent to running git fetch followed by git rebase. This attempts to fast-forward to the new upstream commits, but if that's not possible then it will rebase your local commits onto the new upstream commits. This is usually OK, but be careful:

  • Rebase is an advanced topic, and you should understand the implications before rebasing.
  • git pull --rebase does not give you an opportunity to examine the commits before incorporating them. Depending on what changed upstream, it's quite possible that rebase is the wrong operation—a rebase --onto, merge, reset, or push -f might be more appropriate than a plain rebase.
  • It is not (currently) possible to pass --preserve-merges to the rebase operation, so any intentional merge of a feature branch will be linearized, replaying (and thus duplicating) all of the feature branch commits.

"Fixing" an existing merge commit created by git pull

If you haven't yet pushed a merge commit created by git pull, you can rebase out the merge commit. Assuming you haven't made any intentional merges (e.g., merging an already-pushed feature branch into your current branch), the following should do it:

git rebase @{u}

The above command tells Git to select all of the non-merge commits reachable from HEAD (the current commit), minus all the commits reachable from @{u} (which is shorthand for "the upstream branch", i.e., origin/master if HEAD is master), replay (cherry-pick) them on top of the upstream branch, and then move the current branch reference to point to the result of replaying the commits. This effectively moves the non-merge commits onto the most recent upstream commit, which eliminates the merge created by git pull.

If you have an intentional merge commit, you don't want to run git rebase @{u} because it will replay everything from the other branch. Dealing with this case is substantially more complicated, which is why it's good to use git up and avoid git pull altogether. You'll probably have to use reset to undo the merge created by pull and then do git rebase -p @{u}. The -p argument to git rebase hasn't worked reliably for me, so you might end up having to use reset to undo the intentional merge, update your local branch to @{u}, and then redo the intentional merge (which is a pain if there were a lot of hairy merge conflicts).

Alcestis answered 20/6, 2011 at 4:55 Comment(19)
+1 for discussing --preserve-merges, except you didn't actually document that in the commands you told him to run, so -1 for that.Stairwell
@Seth: Thanks for the comment; I updated the answer to recommend -p. I avoided recommending it before because it's not needed very often and its behavior is not well documented.Alcestis
Solid answer, but what does the @{u} do?Smalley
@Jordan: @{u} is an alias for this particular branch's configured upstream git branch --set-upstream. See man git-rev-parse for a description of this and other magic.Stairwell
Is Richard Hansen's solution goal to avoid future appearance of such "Merge remote-tracking commits" or to fix (=remove) existing one?Ricercare
What id the difference between git remote update -p and git fetch?Patriapatriarch
@eckes: git remote update -p is the same as git fetch --all -p. I got in the habit of using git remote update -p back when fetch didn't have the -p option.Alcestis
What is difference between git pull —rebase and doing git merge --ff-only @{u} after git remote update -p?Swadeshi
@iSid: (1) git pull --rebase does not prune deleted upstream branches, and (2) if there is a divergence (fast-forward not possible), git pull --rebase will rebase, while git merge --ff-only @{u} will simply exit with an error, giving you the opportunity to rebase or merge (or rebase --onto or reset or push -f or...) as appropriateAlcestis
why should we avoid the situation mentioned by the OP? When we commit our change to the remote branch, local Git will first update the local remote-tracking branch and then merge the remote-tracking branch to our local branch. After merge succeeds, then our change will update to the remote branch, which seems a normal step. Is my udnderstanding right?Pointdevice
@user1914692: Once the merge is complete, Git will update the local branch to point to the newly created merge commit, not to the same commit as the remote branch. This new merge commit is the problem, especially when pushed.Alcestis
I didn't make any local changes and commits, but when I did git pull still get this message, how is that possible?Conjoined
@Sawyer: Someone else might have force-pushed into the shared repository.Alcestis
@RichardHansen from the log i can see no, other people also get this probkemConjoined
@Sawyer: OK. Your best bet is to post a new question about this.Alcestis
does anyone actually want these merge commits? git should just make it so that these commits are not created by defaultHyohyoid
@jtate: This has been debated a few times on the git developer mailing list. Most of the git devs seem to agree that pull needs to change, but AFAIK there hasn't been consensus as to how it should behave.Alcestis
The git-rebase documentation says that -p/--preserve-merges is deprecated and you should use -r/--rebase-merges now.Adroit
Thanks for your sharing. What is @{u} mean here?Puttier
I
22
git fetch
git rebase origin/master

That should do it. Or if you want to continue to use pull

git pull --rebase

You can also setup that branch in your config to rebase automatically, or be setup like that automatically for any other future tracking branches you make. Then you can go back to just using

git pull

More on this in the "pull with rebase instead of merge" section of this page:

https://mislav.net/2010/07/git-tips/

Incondite answered 20/6, 2011 at 5:59 Comment(0)
F
0

Merge remote-tracking branch 'origin/develop' into develop

It's a git pull that merged origin/develop (remote changes) into develop (local changes) and we had a lot of problems because of those, loosing code and all.

So now our workflow prevent any problems with git pull merging and keep things simple. Basically it's like a rebase but by merging branch, easily doable in the most basic gui. Others changes are always merged into yours so in case of conflict you only fix what affect the lines you changed! And only your changes appear in the final commit.

  1. Checkout and pull develop
  2. Create a feature branch X from develop
  3. Do your work onto X
  4. To get possible incoming changes checkout and pull develop
  5. If there was remote changes merge develop onto X
  6. If there is conflicts resolve them
  7. If you did 5 or 6 then go back to 4
  8. Merge X onto develop
  9. Push develop

Yeah it look like a bit of a hassle, changing branch, pulling and all. But if you look at rebase doc, they warn against using it in shared branch. So you'll end up creating the same X branch then git fetch origin develop and git rebase origin/develop and you still need to merge that rebased X branch back onto the shared branch develop, so the same amount of work.

Normally if there was remote change at step 5 and specially if there was conflict at step 6. You need to test again and it take time, so that's why you go back to step 4. There is a race condition doing step 8 and 9, but it's really a corner case where someone else push right before you.

Folly answered 8/7, 2021 at 20:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.