EduFlow
Git & GitHub
0%

Section 2 · Branching and Merging

Branches Are Pointers, HEAD Is You

15 min4 min readFill in the blanks

Lesson at a glance

Create, switch, rename and delete branches knowing that each is a movable pointer to a commit, and recover cleanly from a detached HEAD.

  1. 1A branch is a sticky note
  2. 2Making and moving between branches
  3. 3Housekeeping
  4. 4Borrowing one file from another branch
  5. 5Detached HEAD

No video here — just the real thing: a written lesson, runnable examples, a quiz and practice.

In older version control systems a branch was a full copy of the project, slow to make and painful to combine, so people avoided them. In Git a branch costs almost nothing. That changes how you work: every idea, fix or experiment on your portfolio can get its own branch, and throwing one away is as cheap as making it.

A branch is a sticky note

Look inside your repository:

Terminal
cat .git/refs/heads/main
Text
c39be1142d6f0a8e7b1c5d93e2f4a0b6c8d7e912

That’s the whole main branch: a file containing one commit ID. A branch is a named, movable pointer to a commit. The history behind it isn’t stored in the branch; it’s found by following parent links from that commit, as you did in the last lesson.

So how does Git know which branch you’re on? Another small file:

Terminal
cat .git/HEAD
Text
ref: refs/heads/main

HEAD is a pointer to a pointer. It normally names a branch, and that branch names a commit. When you commit, Git creates the new commit with the current one as its parent, then moves the branch HEAD names to the new commit. HEAD itself doesn’t change; it’s still “on main”, and main has moved forward.

You don’t need to read these files day to day (in older or busier repositories, branch IDs may be packed into .git/packed-refs instead), but seeing them once removes the mystery. Everything in this section is about moving these sticky notes around a graph.

Making and moving between branches

Your next portfolio change is a site footer. Give it a branch:

Terminal
git switch -c footer
Text
Switched to a new branch 'footer'

-c creates the branch at your current commit and switches to it. The two-step version is git branch footer followed by git switch footer. Now commit some work:

Terminal
git add index.html styles.css
git commit -m "Add site footer with contact links"
Before: commits a1c9, b2e0, c39b in a row; main and footer both point at c39b; HEAD points at footer. After committing: a new commit f1a3 follows c39b; footer and HEAD moved to f1a3; main stayed on c39b. Before a1c9 b2e0 c39b main footer HEAD After git commit a1c9 b2e0 c39b f1a3 main footer HEAD
Committing moves the branch that HEAD is attached to

main is untouched. Switch back and the footer disappears from your files; switch to footer again and it returns:

Terminal
git switch main      # working tree now matches main's snapshot
git switch footer    # and now footer's
git switch -         # back to whichever branch you were on before

Switching rewrites the files in your working tree to match the target snapshot. Uncommitted changes come along if they don’t clash with the target. If they would be overwritten, Git refuses to switch and tells you to commit or stash first. That refusal is protecting you; don’t look for a way around it. Commit the work, or wait for the stash lesson in section 4.

Housekeeping

Terminal
git branch                 # list local branches; * marks the current one
git branch -v              # with the commit each points to
git branch -m footer site-footer   # rename
git branch -d site-footer  # delete, only if its work is merged
git branch -D experiment   # force-delete, merged or not

-d refuses to delete a branch whose commits aren’t merged into your current branch (or into the branch’s upstream, once it has one), which is a useful safety net. -D skips the check. Use it only when you’re sure the work is unwanted.

Name branches for what they do: footer, fix-mobile-nav, projects-grid. Many teams add a prefix such as feat/ or fix/; slashes are allowed in branch names.

Borrowing one file from another branch

Sometimes you want one file from another branch without the rest of its work. git restore can read from any commit:

Terminal
git restore --source=dark-mode styles.css

That overwrites styles.css in your working tree with the version on dark-mode. Check it with git diff, then stage and commit it on your current branch. You’ll still see older tutorials use git checkout for both switching and restoring; Git 2.23 split those two jobs into git switch and git restore, which are harder to confuse.

Detached HEAD

You can point HEAD straight at a commit instead of a branch, to look at an old version of the site:

Terminal
git switch --detach a1c9d72

Git warns you’re in detached HEAD state. Looking around is perfectly safe. The risk is committing there: new commits belong to no branch, so when you switch away, nothing points at them and they quietly drop out of git log.

Your footer branch is ready and main hasn’t moved. Next you’ll bring the two together with a merge.

Key takeaways

  • A branch is a tiny file holding one commit ID; creating one copies nothing and takes milliseconds.
  • HEAD names the branch you’re on, and each new commit moves that branch forward while HEAD comes along.
  • git switch -c <name> creates a branch at the current commit and switches to it in one step.
  • A detached HEAD points straight at a commit; save any work made there with git switch -c <name> before leaving.
  • git restore --source=<branch> <file> copies one file from another branch without switching to it.

Further reading

Check your understanding

4 questions

Question 1 of 4

You’re on main at commit b2e0 and run git switch -c footer, then commit f1a3. Where do main and footer point now?

Question 2 of 4

What does the file .git/HEAD contain while you’re on the footer branch?

Question 3 of 4

You checked out an old commit to look around, made a quick fix and committed it. Git says you’re in “detached HEAD” state. How do you keep that commit?

Question 4 of 4

Your dark-mode branch has a finished styles.css you want on footer too, without merging the rest of dark-mode. You’re on footer. Which command does it?

Practice

Fill in the blanks

Branch for the footer

Fill in the blanks: create a footer branch and switch to it in one command, commit the footer, go back to main to confirm it hasn’t changed, then rename the branch to site-footer.

git switch footer # create the branch and move onto it git add index.html styles.css git commit -m "Add site footer with contact links" git switch # back to main to check it's untouched git branch -m footer # rename to site-footer