Branches and HEAD are just names and pointers

Branches are movable labels

A branch is a lightweight reference (a name) that points to a commit—nothing more. When you make a new commit while on a branch, Git moves that branch name forward to point to the new commit.

HEAD: your current viewpoint

  • HEAD usually points to the current branch name (like main).
  • That branch name points to a commit.
  • In a detached HEAD state, HEAD points directly to a commit instead of a branch name.

This explains a lot:

  • Creating a branch is cheap: it’s just creating a new name pointing at an existing commit.
  • “Switching branches” mostly means moving HEAD so your working directory matches a different commit’s tree.

A branch doesn’t contain commits; it points to a commit, and commits point backward to parents.

You check out an old commit directly (detached HEAD) and make two new commits. Then you switch back to main without creating a branch. What’s the most accurate description of what happens to those two commits?

A common trap is thinking commits “belong” to whatever branch you later switch to. In detached HEAD, your new commits exist as real objects, but no branch name is moving to keep pointing at them. When you switch back to main, main still points where it did before, so your detached-HEAD commits can become unreachable from named refs unless you create a branch/tag pointing to them. The idea that Git auto-merges is tempting because Git is good at connecting histories, but it won’t change main without an explicit operation. The idea that HEAD ‘always follows newest commits’ confuses HEAD (a pointer) with a global timeline. And commits don’t turn into untracked changes—Git stores them as commit objects regardless of your checkout state.

Like this? Learn anything you want — for free. Sign Up Free