Table of Contents:
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
At this point we can choose to merge
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
master we need to checkout
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
Commmit 6 references
When we merged
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
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
origin/master pointers, now you know what those are.
origin/master is showing you what commit your
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
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.