When I first started using Git, I didn't know anyone that actually knew what git was doing. I used commands that everyone else knew and used them the way they told me to use them. That works until you actually need to understand what your doing to avoid problems in the future. In this tutorial I'll explain some practical merging techniques and what I prefer. As a side note, I wanted to mention that the original title of this tutorial was Git merge strategies, but then I found out it's actually a related, but different topic of its own.
Regular ol' merging
Let's set up an example. I have a feature branch, new-login
, that I branched off of from my master
branch. In this example, I never work directly on the master branch. I always create a feature branch.
If I get lucky, once I finish working on my feature branch, there will be no commits made to master
, like the diagram below.
Once I've committed all my changes to new-login
, I can type the following to merge new-login
into master
:
$ git checkout master
$ git merge new-login
I now have a branch that looks like this:
I can also visualize it like this as well:
They're both the same. Before I merged this, I tested my changes on the new-login
branch and since master
had nothing new in it, then I knew that master
would work fine after the merge.
Glory merging
The examples shown in the Atlassian tutorial demonstrate what I'm calling glory merging, which is merging and assuming all will be well.
I can't wrong them for that, because they're just trying to describe the merge process, not all the precautions you should take when merging.
In a more likely scenario, master
will have progressed and have new commits after I branched off from it. I'll commit my changes to the new-login
branch and get the latest changes from master
. If I merge right away, then I'm performing a glory merge. This is how the commands will look like:
$ git checkout master
$ git pull
$ git merge new-login
This is a glory merge, because I didn't even pull in the changes from the master
branch into my new-login
branch to see how it might affect my new-login
branch. I assumed all would be well and went for the glory.
The following scenarios can result from doing this:
- The merge is fine and everyone is happy.
- My feature for some reason no longer works as expected, so the
master
branch has a bug in it now. - There's a merge conflict and I can't merge until I resolve it.
Merging before the merge
A safe approach would be to merge the master
branch into the new-login
feature branch.
$ git checkout master
$ git pull
$ git checkout new-login
$ git merge master
I could then test it locally and finally merge it back into master.
$ git checkout master
$ git merge new-login
new-login
is now merged into master
. The above diagram shows an example of fast-forwarding. If I wanted to continue to have master only have merge commits, then I could merge with the no-ff
option. Assuming I am back at the point where I have already merged master
into new-login
, I could write the following commands to merge new-login
back into master with the no-ff
option.
$ git checkout master
$ git merge new-login --no-ff
This gives me a new merge commit in the master
branch as seen in the diagram above. By merging with the no-ff
option, another merge commit is created. The decision on which way to merge comes down to my own personal preference. When working alone, I generally prefer to fast-forward whenever I can, because it makes the branch look cleaner, but I am starting to like seeing the merge commits to indicate the merging of a feature or work that wasn't trivial.
Aside from that, the point of these examples was to demonstrate that it's good practice to merge in the latest changes from a main line of development back into a feature branch. Once that's done I should always test locally before merging back into the main line of development. In this example, the main line of development is the master
branch.
You can also follow the same principle of testing your latest work with rebasing. Rebasing can give you a cleaner history, depending on what your definition of clean is. I cover rebasing in another tutorial.