Understanding branches in Git
In this article we will take a deep dive into Git branches. We’ll see how simple yet powerful the concept of branching in Git is. This article is part of a series of articles that will also be part of our book Rebase which you can and should follow it’s progress on Leanpup.
In our last Git article we took a detailed look on the anatomy of a commit. Now that we know how commits work in Git let’s expand on our knowledge and understand branches. It’s important to first grok the concept of branching in Git before we go into merging.
Starting with a simple scenario
Let’s start by looking at a simple commit history.
Let’s assume our entire repository history is made up only from those three commits. There’s a pointer called master pointing at commit a5c3eb. That’s all what branches are: they are movable pointers. Let’s create a branch called feature.
git branch featureSeen that? We just created another pointer called feature pointing at the exact same commit. Basically, all Git does it creates a file called feature with the contents being a 40 char string, the SHA-1 revision name of the commit.
But wait! Now that we have two different branches pointing to the same commit. How does Git know which branch is currently checked out? This is where the HEAD pointer comes into play!
The HEAD is a special pointer that simply points to the currently checked out branch or commit. And again, it’s a simple file inside the .git folder called HEAD which in our case currently contains the string master.
Ok then, what happens if we switch to our feature branch?
git checkout featureExactly, all what happened is that HEAD is now pointing to feature instead of master. Switching between master and feature at this point boils down to Git replacing the string master with feature in the HEAD file. Super cheap!
But what happens if we now create or modify some files and make another commit? Let’s find out.
vim file.txt
git add file.txt
git commit -m "yay, that's fun!"We created a new commit c57e22 and the feature pointer moved on to it. That’s because branches are simply movable pointers to commits. But why did feature move and master did not? Because feature is the currently checked out branch. And how does Git know? Because HEAD points to feature! Simple isn’t it?
Let’s switch back to master.
git checkout masterWhat happened now is that the HEAD pointer changed to master and the state of the entire working directory was changed to what it was at a5c3eb.
Let’s modify a file and create another commit.
vim anotherFile.txt
git add anotherFile.txt
git commit -m "yay, more fun!"A new commit 3aa2ff appeared and master moved on to it. At this point our history has diverged. And this is the whole point of branches. They enable us to have parallel evolution of a code base.
At this point you may be wondering how to merge both ends back together. This is exactly what we will look at in our next Git episode. Stay tuned!
Detached HEAD
Ever came across a detached HEAD? Now that we know how Git handles branches, it’s the perfect time to demystify the detached HEAD. You’ll be suprised how simple it is. In fact, you may have spotted a hint in the text above.
The
HEADis a special pointer that simply points to the currently checked out branch or commit
Not only can we check out branches, we can also checkout any commit revision explicitly.
git checkout 339aa3You see? What happened now is that HEAD points to 339aa3 explicitly and the entire working directory was changed to what it looked like at that commit.
When
HEADpoints to a commit hash explicitly (rather than to a branch) it’s in a detached state.
What happens if we create new commits from here? Let’s find out!
vim someFile.txt
git add someFile.txt
git commit -m "detached HEAD fun"Let’s add one more!
vim someFile.txt
git add someFile.txt
git commit -m "more detached HEAD fun"We can go on like that. Does that mean, we don’t actually need branches? Yes and no. What we just did is kinda like having a branch without a branch name. It works but there are two problems:
- How do you remember the SHA-1 key without a simple branch name?
- Commits that are not reachable by any branch or tag will be garbage collected and removed from the repository after 30 days.
No need to worry though. We can simply create a new branch right here!
git checkout -b bugfixBottom line: If in doubt, just branch. Branches are too lightweight to even think twice about them.