A Branch Is a Sticky Note on One Commit
A branch is a file containing a forty-character hash, which is why creating one is instant and why deleting one deletes almost nothing. Build a history one commit at a time and watch the labels move.
Worth reading first: The Working Tree, the Index, and the Repository
A branch is a file containing a forty-character hash, which is why creating one is instant and why deleting one deletes almost nothing. Build a history one commit at a time and watch the labels move.
A branch is a file containing one hash
Most people picture a branch as a copy of the project, or a line on a diagram, or a folder somewhere. It is none of those. Look at it directly:
$ cat .git/refs/heads/main# 9f3c1a2e8b4d7f0192c5e6a8b3d4f5c6e7a8b9c0 $ ls .git/refs/heads/# main fix/login feature/searchOne file per branch, each containing one commit hash and a newline. Forty-one bytes. That is the entire implementation.
Everything else follows from this. Creating a branch writes forty-one bytes, so it is instant regardless of how big your project is. Deleting a branch deletes forty-one bytes; the commits it pointed at are untouched. And committing on a branch simply overwrites those forty-one bytes with the new commit's hash — which is what "the branch moves forward" actually means.
HEAD is a pointer to a pointer
If a branch says which commit, HEAD says which branch. It is also a file, and it is also readable.
$ cat .git/HEAD# ref: refs/heads/mainSo there are two levels. HEAD points at a branch; the branch points at a commit. That indirection is what makes git commit work without you naming anything: Git reads HEAD to find the current branch, and moves that branch to the new commit.
$ git commit (twice)
Two commits on main. Each one points at the one before it — that backwards arrow is the entire structure of a Git history.
Step two of that sequence is the one worth staring at. git switch -c feature created a second label on the same commit and moved HEAD to it. No files changed. No commits were copied. The only difference between main and feature at that instant is which one HEAD is looking at.
Switching branches rewrites your working tree
Switching does change files — it has to. Moving to a branch means making your working tree match that branch's commit, so files appear, disappear, and change content.
$ git switch fix/login # move to an existing branch$ git switch -c fix/login # create it at the current commit, and move there$ git switch - # back to the previous branch, like cd -$ git branch # list local branches, * marks the current one$ git branch -d fix/login # delete it — refuses if it is not merged$ git branch -D fix/login # delete it anywayGit protects you from losing work here. If you have uncommitted changes that switching would overwrite, it refuses and says so rather than silently discarding them.
error: Your local changes to the following files would be overwritten by checkout: src/auth/redirect.tsPlease commit your changes or stash them before you switch branches.AbortingIf the work is coherent. It is your branch; a rough commit can be tidied up later.
git stash push -m "…" if it is half-finished. Switch, do the other thing, come back, git stash pop.
If the changes do not conflict with either branch, Git carries them across untouched. This is often what you actually wanted.
Detached HEAD is a state, not an error
Check out a commit hash rather than a branch name and Git prints an alarming paragraph about being in "detached HEAD state". Nothing is broken. HEAD is simply pointing straight at a commit rather than at a branch.
$ git switch --detach 2c7a91f# HEAD is now at 2c7a91f Fix the redirect when next is empty $ cat .git/HEAD# 2c7a91f... <- a hash, not "ref: refs/heads/..."This is genuinely useful: it is how you look at the project as it was, run the tests against an old commit, or check whether a bug existed in March. Get out by switching back to a branch.
The one real hazard is committing while detached. Those commits are real, but no branch points at them, so the moment you switch away nothing refers to them and they become eligible for garbage collection. Git warns you clearly. If you did want to keep them:
# While still detached, give the work a name$ git switch -c experiment/faster-parser # Or, if you already switched away, find it in the reflog$ git reflog$ git switch -c rescued 4b8e0d7Branch names are cheap, so make them say something
Branch names show up in pull request titles, in merge commit messages, and in every teammate's branch list. The near-universal convention is a category, a slash, and a short description in hyphens.
fix/login-redirectfeat/csv-exportdocs/contributing-guiderefactor/extract-user-servicechore/bump-eslint482-empty-next-param # some teams lead with the issue numberSlashes are allowed and are just part of the name, though several tools display them as folders, which is pleasant. Spaces are not allowed. Avoid a name that is only a number, and avoid one that already exists as a tag — both make Git ask you to disambiguate later.
Habits that make branches useful rather than administrative
- →One branch, one purpose. A branch that fixes a bug and adds a feature cannot be reviewed or reverted cleanly.
- →Branch from an up-to-date main. Starting from a two-week-old main means merging two weeks of divergence later.
- →Keep them short-lived. Days, not weeks. The longer a branch lives, the more it costs to merge.
- →Delete after merging. git branch -d refuses if it is unmerged, which makes it a safe habit rather than a risky one.
- →Push early, even when unfinished. A branch only on your laptop is not backed up and is invisible to everybody.
Key takeaways
- A branch is a file in .git/refs/heads containing one commit hash. Forty-one bytes.
- Creating a branch copies nothing, so it is instant on a project of any size.
- HEAD is a file naming the current branch; the branch names the current commit. Committing moves the branch, and HEAD follows.
- Switching branches rewrites your working tree to match that branch's commit.
- Git refuses to switch if it would overwrite uncommitted changes. Commit, stash, or note that it often carries them across.
- Use switch for branches and restore for files; checkout does both jobs and that ambiguity destroyed work.
- Detached HEAD means HEAD points at a commit rather than a branch. It is useful, and commits made there need a branch to survive.
- Name branches category/short-description. They appear in pull requests and merge commits.
- One branch one purpose, branched from an up-to-date main, short-lived, pushed early, deleted after merge.
Quick check
Answer these to unlock the next chapter — 3 of 4 to pass. You can retake it anytime.
Answer every question to check.
Make a free account to read on
Every chapter is free — an account is how your progress, XP, and streak follow you from your laptop to your phone, and how you show up on the leaderboard. No payment, no trial.