In the previous chapters, we saw how Git records your project's history as a series of snapshots, or commits, typically forming a linear sequence. Each commit builds upon the one before it. However, software development rarely proceeds in such a strictly linear fashion. You often need to work on different things simultaneously. Imagine you're developing a major new feature, but suddenly an urgent bug needs fixing in the code already released to users. You need a way to pause your feature work, fix the bug on the stable codebase, and then return to your feature development, without the two lines of work interfering with each other.
This is where Git branches come into play. Think of a branch not as a complete copy of your project files, but as a lightweight movable pointer to a specific commit. When you start working, Git automatically creates a default branch, typically named main
(or sometimes master
in older projects). This main
branch represents the primary line of development, often tracking the stable or production-ready code.
Every time you make a commit, this branch pointer automatically moves forward to the newest commit you just created. So, a simple history might look like this: the main
branch pointer points to the latest commit, which itself points back to its parent commit, and so on, forming the project's history.
A simple Git history. Commits (C1, C2, C3) form a sequence. The
main
branch points to the latest commit (C3), andHEAD
indicates thatmain
is the currently active branch.
Creating a new branch means creating a new pointer that starts at the same commit your current branch points to. Let's say you create a new branch called new-feature
while you are on the main
branch which points to commit C3
. Initially, both main
and new-feature
will point to C3
.
After creating the
new-feature
branch. Bothmain
andnew-feature
pointers reference the same commit,C3
.HEAD
still points tomain
.
Now, if you switch to the new-feature
branch (we'll cover how to do this shortly) and make a new commit, say C4
, something interesting happens. The new-feature
pointer moves forward to point to C4
, but the main
branch pointer stays exactly where it was, still pointing at C3
. Your HEAD
pointer now indicates you're working on the new-feature
branch.
After switching to
new-feature
and making commitC4
. Thenew-feature
branch pointer advances toC4
, whilemain
remains atC3
.HEAD
now points tonew-feature
.
This creates two independent lines of development diverging from commit C3
. You can continue working on your feature on the new-feature
branch without affecting the main
branch. If needed, you could switch back to main
, create another branch (e.g., bug-fix
), make commits there, and it wouldn't affect main
or new-feature
until you explicitly decide to combine them (which is called merging, covered later).
The key takeaway is that Git branches are incredibly lightweight. Creating a new branch doesn't involve copying files or directories; it just creates a small file containing the 40-character SHA-1 hash of the commit it points to. This efficiency makes branching a frequent and fundamental part of the Git workflow, unlike in some older version control systems where branching was a more "expensive" operation.
Using branches provides several significant advantages:
main
).main
branch clean, containing only stable, tested code, while development happens on other branches.Understanding this pointer concept is fundamental to effectively using Git's branching capabilities, which we will explore further in the upcoming sections.
© 2025 ApX Machine Learning