Lesson 6 of 30
A branch isn't a copy of your codebase — it's a 41-byte pointer to one commit. That's why creating one is instant, no matter how big the repo is.
12 min read
Every option explains itself — why the right one is right, and why each wrong one is wrong. Miss one and it comes back later on a spaced-repetition schedule.
This topic is about judgment and practical tradeoffs more than a single right answer — a mock interview is the better way to test yourself on it.
Be interviewed on this →Hints without spoilers, and a plain explanation of why a wrong answer was wrong — answered only from this lesson. Free account, no card.
Sign up freeWhat interviewers actually ask about this, and what a strong answer has to cover.
A strong answer covers
Likely follow-ups
If you learned Git through a GUI, you probably picture a branch as a separate folder holding its own copy of every file. That's how older tools like SVN or Perforce actually worked, and it's the wrong model for Git.
A Git branch is nothing more than a movable pointer to a single commit. Concretely, it's a small text file under .git/refs/heads/ that holds one 40-character (or 64, on SHA-256 repos) commit hash. main is a file. feature/login is a file. That's it — no duplicated files, no separate working copies baked in.
Because the object store underneath (blobs, trees, commits) is shared across every branch, creating a new branch never copies snapshot data. It just writes one new tiny file pointing at whatever commit you're currently on. That's why git branch completes instantly even in a repo with a hundred thousand commits — it isn't touching your codebase at all, just adding a pointer to it.
HEAD is the missing piece: it's a pointer to the branch you're currently on (usually), not directly to a commit. So when you commit, Git creates the new commit object, then moves your current branch's pointer forward to it — and because HEAD points at that branch, it looks like you moved forward too. Switch branches, and HEAD re-points at a different ref, and your working directory gets swapped to match whatever commit that ref names.
$ git switch -c feature/login
Switched to a new branch 'feature/login'
That command created one file. Look at it directly:
$ cat .git/refs/heads/feature/login
a1b2c3d4e5f6...
$ cat .git/refs/heads/main
a1b2c3d4e5f6...
Right after branching, both files hold the exact same hash — the branch didn't diverge yet, it's just a second name for the same commit. Now make a commit on the new branch:
$ echo "auth logic" > login.js
$ git add login.js
$ git commit -m "add login stub"
[feature/login 9f8e7d6] add login stub
1 file changed, 1 insertion(+)
$ cat .git/refs/heads/feature/login
9f8e7d6c5b4a...
$ cat .git/refs/heads/main
a1b2c3d4e5f6...
Only feature/login's file changed. main never moved. That's the entire mechanism — no files were copied, no working tree was duplicated on disk, one ref got rewritten to a new hash. And HEAD itself is just as simple:
$ cat .git/HEAD
ref: refs/heads/feature/login
HEAD doesn't hold a commit hash at all here — it holds the name of the branch you're on, one level of indirection that lets "where am I" and "where does main point" be two separate questions.
git branch -d feature/login removes the pointer file, not the commit objects. If nothing else references those commits, they become unreachable and get garbage-collected eventually — but not instantly, and reflog can often still find them.HEAD.This is the same lesson as the object-store idea from the Git mental model: everything durable lives in the content-addressable commit graph, and refs like branches are cheap, disposable labels pointing into it. Every later Git workflow — merging, rebasing, force-pushing — is really just "which ref points at which commit," which is exactly why understanding this now makes those commands far less mysterious.