build-git / lesson-34.md
Lesson 34 · Refs, HEAD, and log

Switching branches

Switching branches is retargeting HEAD to point at a different branch. Today you build checkout, then prove that committing afterwards advances the new branch and leaves the old one alone.

The goal

Switch HEAD to another branch so that new commits advance it, not the branch you left.

Start here - the target
TO DO
Scenario: Checkout retargets HEAD and diverges history
Giventhe repository with main and dev both at 9bae7f0a71d91d794187cf9de39901bfbfbfc7b6 and HEAD as ref: refs/heads/main
WhenCheckout(dev) rewrites HEAD, then a further file change is staged and committed
Thenafter Checkout, HEAD reads ref: refs/heads/dev and Resolve(HEAD) is 9bae7f0a71d91d794187cf9de39901bfbfbfc7b6
Andafter the new commit, refs/heads/dev has moved to it (with parent 9bae7f0a71d91d794187cf9de39901bfbfbfc7b6) while refs/heads/main is unchanged at 9bae7f0a71d91d794187cf9de39901bfbfbfc7b6
Background

Switching branches is almost anticlimactic: Checkout("dev") just rewrites HEAD to ref: refs/heads/dev. That is all “being on dev” means. We do not touch the working files (real Git would update them to match; ours retargets the pointer only, a limitation we will name in the caveats). The power is in what happens next.

Because commit takes its parent from HEAD and advances the branch HEAD names, a commit made after checkout extends dev and leaves main exactly where it was. The two branches, once identical, now diverge: dev has a new commit whose parent is the old shared tip, and main still points at that shared tip. That is the whole basis of branching in Git, built from nothing but small ref files and a symbolic HEAD. History is no longer a line; it is a graph, and you can grow either branch independently.

Make it work
// switching branches is just pointing HEAD at a different ref
func (r *Repo) Checkout(name string) error {
return r.SetHEAD("refs/heads/" + name)
}
// afterwards, Commit advances refs/heads/dev; main stays put
CheckpointDONE
You can switch branches and diverge history. Commit and stop here. The whole refs chapter now behaves like Git's branching.