04 · Branching Basics¶
A branch in Git is just a movable pointer to a commit. That's it — no separate copy of the files, no expensive operation. This is why Git branches are so cheap that the natural workflow is to make a new branch for every feature, bugfix, or experiment.
What main actually is¶
When you look at git log, you're really following a chain of commits,
each pointing to its parent. A branch name (like main) is a label that
always points at the most recent commit on that line of work. As you
commit, the branch pointer moves forward automatically.
Creating a branch¶
git branch <name> creates the branch but does not switch to it — the
* shows you're still on main. The new branch simply points at the same
commit main currently points at.
Switching branches¶
git checkout <branch> does the same thing and is the older, more
overloaded command — git switch (added in Git 2.23) was introduced
specifically to make branch switching unambiguous. You'll see both in the
wild; this course uses git switch for switching and git restore for
discarding file changes, keeping each command single-purpose.
Create and switch in one step:
(-c = "create". The older equivalent is git checkout -b feature/greeting.)
Committing on a branch¶
git switch -c feature/greeting
echo "feature work" > feature.txt
git add feature.txt
git commit -m "Add feature file"
git log --oneline --all --graph
* 71c4aec (HEAD -> feature/greeting) Add feature file
* 4752e7c (main) Add second line
* 07246b8 Add notes.txt
Notice main is still pointing at 4752e7c — commits on feature/greeting
don't touch main at all until you explicitly bring them together (that's
next module, on merging).
Listing and inspecting branches¶
git branch # local branches, current one marked with *
git branch -a # local + remote-tracking branches
git branch -v # each branch + its latest commit
git branch --merged # branches already merged into the current one
git branch --no-merged # branches NOT yet merged (careful before deleting these)
Renaming and deleting branches¶
git branch -m old-name new-name # rename a branch
git branch -d feature/greeting # delete (safe: refuses if unmerged)
git branch -D feature/greeting # force-delete, even if unmerged
Naming conventions¶
Git allows almost any branch name, but teams converge on conventions so intent is obvious at a glance:
| Pattern | Used for |
|---|---|
feature/short-description |
New functionality |
fix/short-description or bugfix/... |
Bug fixes |
chore/short-description |
Maintenance, config, tooling |
release/1.2.0 |
Preparing a release |
Slashes are literal characters to Git (no special meaning), but most tools
render feature/x as a nested folder in their branch list, which keeps
long lists organized.
Worked example¶
git switch main
git switch -c fix/typo-in-readme
echo "Fixed typo" >> README.md
git add README.md
git commit -m "Fix typo in README"
git switch main
git log --oneline --all --graph
* 9f1a2b3 (fix/typo-in-readme) Fix typo in README
* a1b2c3d (HEAD -> main) Add app.py
* 07246b8 Add README
main (with HEAD pointing at it, meaning "the branch you're currently
on") hasn't moved; fix/typo-in-readme has one extra commit ahead of it.
How It Actually Works¶
A branch has almost no structure of its own — which is exactly why creating one is instant and "cheap" isn't marketing:
refs/heads/mainandrefs/heads/fix/typo-in-readmeare each a plain text file containing nothing but a 40-character commit SHA.git branch fix/typo-in-readmeis implemented as: read the SHA thatHEADcurrently resolves to, write that SHA into a new file at.git/refs/heads/fix/typo-in-readme. That's the whole operation — no files are copied, no directories are duplicated.HEADitself is one more small text file,.git/HEAD, but it doesn't hold a commit SHA directly — it holdsref: refs/heads/<branch>, one level of indirection.git switch <branch>rewrites.git/HEADto point at the new branch's ref file, then updates every file in your working directory to match that branch tip commit's tree (adding/removing/ modifying files as needed) and rebuilds the index to match.- Committing while on a branch is what actually "moves" it: after
git commitwrites the new commit object, Git resolvesHEAD→refs/heads/main, and overwrites that file's contents with the new commit's SHA. The branch pointer advancing is a one-line file write, not a structural change to history. - This is also why two branches can share history for free:
fix/typoandmainboth point at commits that share the same ancestor chain — nothing is duplicated until a commit is made that only one of them should have, at which point the branches' single SHA pointers simply diverge to different commits. Deleting a branch (git branch -d ...) is just deleting that one ref file; the commits themselves stay in the object database until garbage-collected if nothing else reaches them.
Exercise¶
Starting from a repo with at least one commit on main, create and switch
to a branch called feature/colors. On that branch, create a file called
colors.txt listing three of your favorite colors, one per line, and
commit it. Switch back to main and run git log --oneline --all --graph
— confirm you can see both branches and that main does not include the
colors.txt commit.