spider monkey on tree branch

How to use git branches

8 min read
Christopher Carfi

Branches are easily one of the most unique and powerful features that Git has to offer developers. Getting accustomed to frequent use of branching and merging can drastically improve your workflow, and this simple tutorial will give you the basics you need to get started with branches right away.

Properly understanding Git branches first requires knowledge of how Git stores and tracks commits throughout the repository. When creating a new commit in most other version control systems (VCSs), a copy of all file-based changes is generated for every modified file in the repository, making up the entirety of that commit. These file-based changes are commonly referred to as differences or diffs.

GoDaddy VPS and Dedicated servers

By contrast, Git stores data using snapshots of what the Git creators call a "mini file system" rather than differences. By using a snapshot to store information, Git commits do not need to replicate unnecessary information throughout commit histories, but can instead simply use references to existing files in the repository if no changes were made since the previous commit.

This effectively means that Git commits are significantly smaller, quicker, and easier to generate than most VCSs.

If your repository contains 1,000 files but the changes made between the previous commit and the current one only take place in five of those files, the latest Git commit simply stores references (in the form of 40-character SHA-1 hash strings) to the other 995 unmodified files. Due to this referential snapshotting, all future commits (or branches or merges) have a simple, historical record of the exact state of the files at that particular moment for that particular commit. This feature is what makes branching within Git so powerful.

Using Git branches

You can use Git on our cPanel hosting, GoDaddy Managed WordPress, Virtual Private Servers and Dedicated Servers.

To begin we'll examine a basic project with two commits already made:


Throughout this tutorial, the blue boxes represent various commits: c1 is commit #1, c2 is commit #2, and so on, each listed with the first few characters of the hash (as Git refers to commits). The green boxes indicate various branches (referred by name).

When a new repository is generated (git init), a default branch named master is created. Additionally, when a new commit is added, Git will associate the most recent commit within that matching branch as the current "reference point" of that branch. Thus, in our example above with two commits so far, both in the default master branch, our master branch is currently referencing commit #2.

Additionally, Git remembers which branch you're currently working on with a pointer known as HEAD, indicated by the yellow box above. This is not the same use of "HEAD" as you might see in other VCSs; in Git, HEAD is a pointer to the current working local branch of your repository. When you make changes to your local files, you’re making changes to whichever branch HEAD is pointing to at the time.

Create a branch

The most powerful feature of Git branches is the freedom to quickly and easily create a branch for any minor task you wish to separate from your primary codebase. Once your work in a new branch is complete, you can easily merge the branch back into the codebase and continue on.

For example, if you want to create a new feature but develop it in a separate branch, you create that new branch with the git branch command:

$ git branch feature

Simply creating a new branch does not automatically move your HEAD to that branch. To move the HEAD to the new feature branch, use the checkout command:

$ git checkout feature

NOTE: It’s often simpler to use the checkout command with the -b flag, which accomplishes the same as the above two commands:

$ git checkout -b feature
Switched to branch 'feature'

This diagram illustrates the changes you’ve made:


You have created a new feature branch, but since no changes have been made yet, both the feature and master branches reference the same commit (#2). It's also important to note that by checking out the feature branch, you can now make changes that do not alter the primary codebase (now associated with master).

Modify and Commit to a branch

With your local HEAD set to a new feature branch, you can now make changes to your files as needed to implement the new feature you're working on.

$ cat > foobar.txt
Adding a new line.
$ git add foobar.txt
$ git commit -m "Adding foobar.txt"
[feature 54c6fe] Adding foobar.txt
 1 file changed, 1 insertion(+)
 create mode 100644 foobar.txt

Now that you’ve generated a new commit while your HEAD is referencing the feature branch, the structure of the repository starts to become interesting:


The feature branch now references your latest commit (#3) while the master branch was left alone and thus still references commit #2.

Switching between branches

While working in the new feature branch you might need to move back to the master branch, perhaps to fix a nasty bug in the primary codebase. Switching branches (and thus the local HEAD reference) is as easy as using the checkout command for the appropriate branch:

$ git checkout master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.

The repository structure looks nearly the same, except we've moved the HEAD to the now active master branch.

git4Branch from a branch

Now you might wish to create another branch to quickly fix the new bug that cropped up in the master branch codebase. We'll call this branch bug-fix for simplicity, though more descriptive names would certainly be used in practice.

$ git checkout -b bug-fix
Switched to a new branch 'bug-fix'

Now that you've checked out the new branch and moved your working HEAD to this new branch, you can safely make the changes and fix the issue:

$ nano index.html.erb
[fix performed]
$ git commit -a -m "Resolved the issue in index.html.erb"
[bug-fix bdc62e] Resolved the issue in index.html.erb
1 file changed, 1 deletion(-)
create mode 100644 index.html.erb

Now that you've created another commit (#4), referenced by your bug-fix branch (which is associated with the local HEAD), your repository structure looks like this:

git5Merging branches

Merging two branches is usually a simple matter of running the git merge command while your HEAD is currently set to the branch you’re bringing forward (that is, the child branch).

In this case, you're satisfied with the fix performed in commit #4 within the bug-fix branch, so you want to merge those changes in with the master branch, of which the bug-fix is an immediate parent. You can do so by first checking out the master branch, then issuing the merge command on the bug-fix branch you want to merge into:

$ git checkout master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.
$ git merge bug-fix
Updating fd67df..bdc62e
index.html.erb | 1 +
 1 file changed, 1 deletion(-)

Notice the output states this is a "fast-forward" merge. This means that Git simply moves the reference pointer for the master branch forward to commit #4, since the previous pointer (to commit #3) is directly upstream of the bug-fix branch you merged into.

Since the master branch now points to the latest committed snapshot (#4), you no longer need to keep the bug-fix branch, so let's delete it with the branch -d flag:

$ git branch -d bug-fix
Deleted branch bug-fix (was bdc62e).

The result is that master is the currently active HEAD branch and references the latest commit (#4) with our implemented bug fix, while the feature branch still references commit #3.

git6Merging from a common ancestor

Now you might wish to continue work on the feature branch and after checking it out -- and thus moving HEAD appropriately -- you've created a new commit (#5) that implements the new feature.

$ git checkout feature
Switched to branch 'feature'
$ nano index.html.erb
[feature implemented]
$ git commit -a -m "Added fantastic new feature"
[feature 642dc1] Added fantastic new feature
1 file changed, 1 insertion(+), 1 deletion(-)

Your repository structure now looks like this:


With the new feature implemented in the feature branch complete and committed to commit #5, you might wish to merge the divergent branches feature and master together.

$ git checkout master
$ git merge feature
Auto-merging foobar.txt
foobar.txt | 1 +
1 file changed, 1 insertions(+)

Since the merged branches are not direct ancestors of one another, Git must perform a three-way merge to complete the task. Git will combine the two snapshots of the merge source (commit #5) and merge target (commit #4) with the common ancestor (commit #2) as highlighted in red below.


Since Git cannot simply move the branch pointer forward as we saw in the previous merge example, in this case Git will create a new snapshot merge commit (#6) that is a parent to both the previous snapshots (commits #4 and #5):


Just as before, once you've merged a previous branch into the master branch (as we did here with the feature branch), you can remove the old branch if you wish:

$ git branch -d feature
Deleted branch feature (was 642dc1).

That's it!  You should now have a basic understanding of branching and merging within Git and the benefits that using branches can provide you. As always, for more information check out the official documentation for Git.