When should I use git pull --rebase?

Git

Git Problem Overview


I know of some people who use git pull --rebase by default and others who insist never to use it. I believe I understand the difference between merging and rebasing, but I'm trying to put this in the context of git pull. Is it just about not wanting to see lots of merge commit messages, or are there other issues?

Git Solutions


Solution 1 - Git

I would like to provide a different perspective on what "git pull --rebase" actually means, because it seems to get lost sometimes.

If you've ever used Subversion (or CVS), you may be used to the behavior of "svn update". If you have changes to commit and the commit fails because changes have been made upstream, you "svn update". Subversion proceeds by merging upstream changes with yours, potentially resulting in conflicts.

What Subversion just did, was essentially "pull --rebase". The act of re-formulating your local changes to be relative to the newer version is the "rebasing" part of it. If you had done "svn diff" prior to the failed commit attempt, and compare the resulting diff with the output of "svn diff" afterwards, the difference between the two diffs is what the rebasing operation did.

The major difference between Git and Subversion in this case is that in Subversion, "your" changes only exist as non-committed changes in your working copy, while in Git you have actual commits locally. In other words, in Git you have forked the history; your history and the upstream history has diverged, but you have a common ancestor.

In my opinion, in the normal case of having your local branch simply reflecting the upstream branch and doing continuous development on it, the right thing to do is always "--rebase", because that is what you are semantically actually doing. You and others are hacking away at the intended linear history of a branch. The fact that someone else happened to push slightly prior to your attempted push is irrelevant, and it seems counter-productive for each such accident of timing to result in merges in the history.

If you actually feel the need for something to be a branch for whatever reason, that is a different concern in my opinion. But unless you have a specific and active desire to represent your changes in the form of a merge, the default behavior should, in my opinion, be "git pull --rebase".

Please consider other people that need to observe and understand the history of your project. Do you want the history littered with hundreds of merges all over the place, or do you want only the select few merges that represent real merges of intentional divergent development efforts?

Solution 2 - Git

You should use git pull --rebase when

  • your changes do not deserve a separate branch

Indeed -- why not then? It's more clear, and doesn't impose a logical grouping on your commits.


Ok, I suppose it needs some clarification. In Git, as you probably know, you're encouraged to branch and merge. Your local branch, into which you pull changes, and remote branch are, actually, different branches, and git pull is about merging them. It's reasonable, since you push not very often and usually accumulate a number of changes before they constitute a completed feature.

However, sometimes--by whatever reason--you think that it would actually be better if these two--remote and local--were one branch. Like in SVN. It is here where git pull --rebase comes into play. You no longer merge--you actually commit on top of the remote branch. That's what it actually is about.

Whether it's dangerous or not is the question of whether you are treating local and remote branch as one inseparable thing. Sometimes it's reasonable (when your changes are small, or if you're at the beginning of a robust development, when important changes are brought in by small commits). Sometimes it's not (when you'd normally create another branch, but you were too lazy to do that). But that's a different question.

Solution 3 - Git

Perhaps the best way to explain it is with an example:

  1. Alice creates topic branch A, and works on it
  2. Bob creates unrelated topic branch B, and works on it
  3. Alice does git checkout master && git pull. Master is already up to date.
  4. Bob does git checkout master && git pull. Master is already up to date.
  5. Alice does git merge topic-branch-A
  6. Bob does git merge topic-branch-B
  7. Bob does git push origin master before Alice
  8. Alice does git push origin master, which is rejected because it's not a fast-forward merge.
  9. Alice looks at origin/master's log, and sees that the commit is unrelated to hers.
  10. Alice does git pull --rebase origin master
  11. Alice's merge commit is unwound, Bob's commit is pulled, and Alice's commit is applied after Bob's commit.
  12. Alice does git push origin master, and everyone is happy they don't have to read a useless merge commit when they look at the logs in the future.

Note that the specific branch being merged into is irrelevant to the example. Master in this example could just as easily be a release branch or dev branch. The key point is that Alice & Bob are simultaneously merging their local branches to a shared remote branch.

Solution 4 - Git

I think you should use git pull --rebase when collaborating with others on the same branch. You are in your work → commit → work → commit cycle, and when you decide to push your work your push is rejected, because there's been parallel work on the same branch. At this point I always do a pull --rebase. I do not use squash (to flatten commits), but I rebase to avoid the extra merge commits.

As your Git knowledge increases you find yourself looking a lot more at history than with any other version control systems I've used. If you have a ton of small merge commits, it's easy to lose focus of the bigger picture that's happening in your history.

This is actually the only time I do rebasing(*), and the rest of my workflow is merge based. But as long as your most frequent committers do this, history looks a whole lot better in the end.

(*) While teaching a Git course, I had a student arrest me on this, since I also advocated rebasing feature branches in certain circumstances. And he had read this answer ;) Such rebasing is also possible, but it always has to be according to a pre-arranged/agreed system, and as such should not "always" be applied. And at that time I usually don't do pull --rebase either, which is what the question is about ;)

Solution 5 - Git

I don't think there's ever a reason not to use pull --rebase -- I added code to Git specifically to allow my git pull command to always rebase against upstream commits.

When looking through history, it is just never interesting to know when the guy/gal working on the feature stopped to synchronise up. It might be useful for the guy/gal while he/she is doing it, but that's what reflog is for. It's just adding noise for everyone else.

Solution 6 - Git

Just remember:

  • pull = fetch + merge
  • pull --rebase = fetch + rebase

So, choose the way what you want to handle your branch.

You'd better know the difference between merge and rebase :)

Solution 7 - Git

I think it boils down to a personal preference.

Do you want to hide your silly mistakes before pushing your changes? If so, git pull --rebase is perfect. It allows you to later squash your commits to a few (or one) commits. If you have merges in your (unpushed) history, it is not so easy to do a git rebase later one.

I personally don't mind publishing all my silly mistakes, so I tend to merge instead of rebase.

Solution 8 - Git

git pull --rebase may hide a history rewriting from a collaborator git push --force. I recommend to use git pull --rebase only if you know you forgot to push your commits before someone else does the same.

If you did not commit anything, but your working space is not clean, just git stash before to git pull. This way you won't silently rewrite your history (which could silently drop some of your work).

Solution 9 - Git

One practice case is when you are working with Bitbucket PR. Let's understand it with the below case:

There is PR open.

Then you decided to rebase the PR remote branch with the latest Master branch through BitBucket GUI. This action will change the commits' ids of your PR.

Since you have rebased the remote branch using GUI. first, you have to sync the local branch on your PC with the remote branch.

In this case git pull --rebase works like magic.

After git pull --rebase your local branch and remote branch have same history with the same commit ids.

Then now if you add a new commit/changes to the PR branch.

You can nicely push a new commit without using force or anything to remote branch/BitBucket PR.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJason BakerView Question on Stackoverflow
Solution 1 - GitscodeView Answer on Stackoverflow
Solution 2 - GitP ShvedView Answer on Stackoverflow
Solution 3 - GitCody PollView Answer on Stackoverflow
Solution 4 - GitkrosenvoldView Answer on Stackoverflow
Solution 5 - GitDustinView Answer on Stackoverflow
Solution 6 - GitleohxjView Answer on Stackoverflow
Solution 7 - GithasenView Answer on Stackoverflow
Solution 8 - GitHabaxView Answer on Stackoverflow
Solution 9 - GitDeepak SharmaView Answer on Stackoverflow