Git/Sourcetree basic branching and merging Git/Sourcetree basic branching and merging git git

Git/Sourcetree basic branching and merging


In the second picture there are branches. Locally you have 2 branches, master & develop. Both branches are resting at the same commit though. If you want to 'see branches' as in the first picture you can make a commit on develop, however the graph will still apear to be linear. You'll be able to merge develop into master at that point if you want.

If you want to see the graph diverge, try putting a commit on master as well. Then you will start to see something more like the first picture.

To get an idea of how git works with a visualization program like this, I suggest you do actions like I suggested above, and take a look at the graph at each intermediate step.


There's a few things going on here. First, it's useful to understand that branches in Git are really just "labels" that are stuck to a particular commit, and that will be moved automatically when you commit to the the branch; Git will create the new commit, with a new commit hash, and update the branch/label to point to the new commit. (You might ask, how is this different from tags, then? A tag is stuck to the same commit, and will not get updates when you call git commit.)

When you create a new branch, all that happens is that Git creates a new label, pointing to the same commit you were on. Only when you create a new commit while this new branch is checked out, will you see the new branch diverge from the other branch.

The real confusion starts when you start merging branches again, and this is largely due to a weird thing Git calls "fast forward merging", which it does by default. Let's take your second example and imagine that your master and develop are where originally origin/master and origin/develop were:

Simple linear branching example

When you ask Git to merge one branch into another, Git will go and figure out what it needs to do to get the difference between those branches into the target branch. Let's say you want to merge the changes you made to develop into master, so you tell git:

$ git checkout master$ git merge develop

Git will look at the branches, and see that develop is just ahead of master by a few commits, but there's nothing more complicated going on than that. So, it will do a "fast forward" merge, by simply taking the master label and sticking it to the commit where develop is pointing. Mission accomplished, changes that were only in develop before are now also in master.

Should each branch have extra commits, like in your first example right before merging master into develop, "something more complicated" is going on. You made a commit on master, then did a git checkout develop, made a commit there, and then asked Git to merge master back into develop. Git can now no longer "cheat" by just moving branch-labels around. It will need to figure out how to unify the changes from the two branches into a single state of the files under its control (let's assume, for now, it is always able to do that, which is not that far from the truth; its quite good at it. If it can't, you have a merge conflict, which is really not as bad as it sounds).

The new content, after the merge, will neither be the last state of the first branch, nor will it be the state of the second branch. So, it needs to be represented with a brand new commit, which is what you see at the top of your first example; Git created what it calls a "merge commit" to represent the new state with the changes from each branch merged into a single state.

Lastly, you can force Git to always create a merge commit, eventhough it is strictly, technically, not needed. In the command line, you can do this with the flag --no-ff, for no fast forward. Graphical clients will have a checkbox that will accomplish the same thing (in SourceTree, it is currently labeled "Create a commit even if merge resolved via fast-forward"). Many (including myself) actually recommend to just merge with --no-ff, because that way the act of merging is always recorded in history, regardless of technicallities like whether it would technically be possible to just move branch pointers around.


I just ran into this same problem and found that there's a setting in SourceTree to "Do not fast-forward when merging, always create commit". Make sure that's checked and you'll see the branch structure from them on.

This setting is found on the Git tab in preferences.