Merge and rebase
If you’ve already started working with a team on a project manage by GIT, you’ve probably already fallen on a commit like this one.
Merge branch ‘master’ of github.com:lyonrb/lyonrb
The question everybody can be asking is “WTF? We’re on master, we’ve merged from master. What’s that commit doing here ?”.
Why merges on the same branch ?
If this phrase doesn’t means anything, it’s, first of all … Because it’s not the same branch. What happened in that commit is the following :
- Franck has committed on the repository. Then he pushed to github and left to drink a beer.
- I pulled his modifications; committed on the repository; pushed on github and left to drink a beer.
- When Franck came back, he forgot to pull. So he did it only after committing on his local repo.
When Franck did a
git pull to get my modifications, it has generated this commit.
What you need to know is that from the GIT point of view, we have two different branches : master and origin/master. The first one is our local branch, the one on which we’re committing. The second one is the github branch, the one which allows ut to share our work with other developers.
When you do a
git push or a
git pull, internally, GIT merges those two branches together. As they’ve diverges, a new commit is created in order to apply those modifications.
What are branches ?
GIT is great in the facilities it provides when it’s about dealing with branches. Notably compared to SVN. A branch allows us to continue to work on our application. But without changing what we were doing.
So at any moment, you can go back to the main branch and don’t have the previous modification we did.
It’s highly recommended to work on a new branch every time you’re working on something consequent (which will take more than 30 minutes). Whether it’s a bug fix or a new feature.
Using that way, when you’re working on your new thing, if a bug occurs and has to be fixed right now, you can [stash(http://www.kernel.org/pub/software/scm/git/docs/git-stash.html) your modifications; go back to the master branch and fix you bug without having the modifications you were working on.
You can redeploy your application without your users seeing that new design you were working on.
Merge VS. Rebase
Of course, when you’ve finished working on your branch, you’ll have to merge the modifications with the main part of your code. That’s what merge and rebase do.
Let’s be clear right away though : merge is, in 80% of the cases, to be used instead of rebase.
Merge, what’s that ?
The two images above represents a repository with a feature branch. And this same feature after it’s been merged.
As you can see, GIT creates a new commit which brings those two branches back together. We can see in the log that at some point in history, those two parts of code were splitted. i ### Rebase, what’s that ?
Here, we’ve taken the exact same repository. But instead of merging, we’ve rebased. As you can wee, we don’t see the branch wich previously existed anymore.
Indeed, when we rebase, GIT does the following :
- It keeps all the commits done in the branch to rebase (here master) and cancel them.
- It applies all the commits done on the second branch as patches on our master branch.
- It reapplies all the commits done on master
By replaying the history, it’s just like if we never had any branch. We don’t have a commit saying “hey you’ve merge here”.
Let’s go back to our original problem
If I haven’t lost you yet, you must be wondering “ok, but his article introduction is out of context”.
Of course not ! Because I haven’t told you the only moment (in my opinion) where you should rebase and not merge.
Indeed, if you create a new branch for a new feature, it’s important to keep it’s modifications. And seeing in your repository’s history “from which date to which date, this feature was in development and not deployed”. With rebase it’s not possible.
However, when someoned does modifications on the master branch of the repository and you too, it’s not a different branch. It’s only two different persons. We don’t care to see an history. Moreover, if you push regularly, you’ll have as many merge commits as normal commits. It then becomes impossible to read your commits log.
That’s why I never do any
git pull !
Instead, I use
git pull --rebase.
With this option, instead of merging my distant branch with the local one, GIT will rebase it. And I don’t have any merge commits. I just need to push and everything is clean.
You can even configure your repository so that every time you do
git pull, it’s not a merge but a rebase which is done.
In the .git/config file, add the following line to your branch’s configuration :
[branch "master"] rebase = true
You have to do it for all branches. But like that, git will automatically do rebases instead of merges when you’ll pull.
And if there is a conflit ?
Oh yeah, you’ve already fallen on the case of the merge where GIT finds a conflict it can’t solve by itself.
When you’re merging, it’s simple. You fix the conflict and commit manually. The merge is done on the commit you’re doing then.
For you, rebase is just that simple. When there’s a conflict, you’ll see that GIT leaves you outside of any branch.
Fix your conflict; do a “git add”. But don’t commit (ou couldn’t anyway as you’re not in a branch).
git rebase --continue. GIT will then now how to interpret the modifications and will be able to continue the rebase by itself. You won’t see anything anymore once it’s finished.
As you’ve seen in this article, working with branches (and merge them when you’ve finished) is particularly simple.
So why not enjoy them ? Let’s use and abuse them.
If you don’t yet see how, I invite you to take a look at [git flow]http://nvie.com/posts/a-successful-git-branching-model/), which will give you a very good workflow example for using branches with GIT.