Merge vs Rebase: Part 2 - What is a merge?

Table of Contents:
- Part 1 - What is a commit hash?
- Part 2 - What is a merge?
- Part 3 - What is a rebase?
In part 1 we left off with a little demo repository. We had a feature branch called feature1
that was ready to be merged back into master
.

At this point we can choose to merge feature1
into master
or we can choose to rebase. We'll cover rebasing in part 3. For now let's see what happens if we do a merge. Merging branches together is pretty straight-forward. We first need to checkout the branch we want to merge into. Since we want to merge feature1
into master
we need to checkout master
.

I checked out the master
branch and then merged feature1
into it. Let's go over what exactly happened and why the graph generated by Source Tree looks the way it does.
Remember from part 1 how Commit 3
and Commit 4
ended up having the same previous commit? Commit 2
is the common ancestor for both of those commits because Commit 3
was made on another branch and Commit 4
was made to the master
branch, which didn't have knowledge of Commit 3
. In our feature1
branch we added a couple more commits. Commit 5
directly references Commit 3
because Commit 4
is only available on the master
branch. Commmit 6
references Commit 5
.
When we merged feature1
into master
, it didn't magically move those commits over to the master
branch somehow. It actually created a brand new commit that contains all of the changes from all of the commits on the feature1
branch. The commit that says Merge branch 'feature1'
looks like this:

If you have been paying attention to the commit diffs in the screenshots then you've seen the silly lines I've been adding to index.txt
. You may have noticed that those lines were all added piece by piece in separate commits to the feature1
branch. However, here you can see all of those changes in a single diff.
All Git did was smash all the diffs from all the commits to feature1
together into a single commit. This new commit has done something that we haven't discussed yet. If you look at the graph you'll notice that it has two ancestors. It has lines coming from Commit 4
and Commit 6
. Why is this? Commits can store references to more than one previous commit. I'm only just now bringing this up because I didn't want to cause confusion earlier.
When a commit is being created it can store references to a single previous commit hash, multiple commit hashes, or none. Usually only the very first commit to your repository has no previous commit references and merge commits are usually the only commits that store more than one previous commit reference.
If you remember from part 1, branches are really just pointers to specific commits.

You may notice that feature1
still points to Commit 6
while master
now points to the new merge commit. This is simply because we merged feature1
into master
. If we were to checkout feature1
and merge master
into it then all Git would do is another fast-forward merge that would bring the feature1
pointer up to point at the same commit.

If we now delete our feature1
branch entirely you might expect that pink branch line to disappear, but you'd be wrong.

Remember, Source Tree and any other Git GUIs generate the graph by walking over your commits and connecting them together using the referenced commit hashes. Branches are just pointers that point at specific commits. When you pull from a remote repository all Git does is:
- Download any commits that your local machine doesn't have.
- Merge the missing commits into your local repository, either via a merge commit, or via a fast-forward merge if you haven't made any changes since your last pull.
- Move your local branch pointer up to the latest commit.
If you've ever been confused about the master
and origin/master
pointers, now you know what those are. origin/master
is showing you what commit your origin
remote's master
branch is pointing to. If I add a remote repository named origin
to our demo repository and then make a commit to my local repository, the history would like like this:

You can see that master
is pointing to the latest commit while origin/master
is pointing at the previous merge commit. Source Tree is even letting us know that we have 1 commit to push to the remote repository. If we do a push then Git will upload the missing commit and update your remote branch pointer to show that origin/master
is now pointing at the same commit as your local master
branch.

Hopefully you now have a better understanding of how merging works in Git. Jump on over to part 3 and let's dive into rebasing and see how it compares to merging.