How it works
The explanation, with examples you can run.
See the pointers
Make two commits and a second branch:
git init -q -b main demo && cd demoecho "hello" > greeting.txt && git add . && git commit -q -m "Add greeting"echo "bye" > farewell.txt && git add . && git commit -q -m "Add farewell"git branch featurecat .git/HEADgit rev-parse main featureref: refs/heads/main128af6f8019138b890d8453f93b6b40bdc3b0e51128af6f8019138b890d8453f93b6b40bdc3b0e51git branch feature wrote one pointer to the commit you are on. Both names now point at the same commit; nothing was copied. In a fresh repository a ref is a small file such as .git/refs/heads/feature; after git gc, many refs are packed into .git/packed-refs, and newer repositories can use the reftable format instead. Use git rev-parse or git show-ref rather than reading the files.
Committing moves only the current branch
git switch -q featureecho "more" >> greeting.txt && git commit -q -am "Extend greeting"cat .git/HEADgit log --oneline --graph --allref: refs/heads/feature* ee97a7b Extend greeting* 128af6f Add farewell* c15e99d Add greetingHEAD names feature, so the commit moved feature and left main where it was. git log --oneline --decorate would show the labels; the graph shows one line because main is simply an ancestor of feature. Neither branch "owns" a commit: 128af6f is on both, because both tips can reach it by following parents.
Detached HEAD
Check out a commit instead of a branch and HEAD holds the hash itself:
git switch -q --detach maincat .git/HEADgit symbolic-ref -q HEAD || echo "detached"git switch -q main128af6f8019138b890d8453f93b6b40bdc3b0e51detachedDetached HEAD is useful for looking at an old version or running a bisect. Commits made there are real, but no branch moves to follow them. When you switch away, Git warns that you are leaving commits behind; git switch -c rescue <hash> keeps them.
Names you can use
Anywhere Git wants a commit you can write a hash prefix, a branch or tag name, HEAD, or an expression: HEAD~2 (two parents back), main^2 (the second parent of a merge), feature@{yesterday} (where the branch pointed a day ago, from the reflog) or main..feature (commits reachable from feature but not main). Remote-tracking refs such as origin/main live under refs/remotes/ and are covered in the remotes topic.
git switch (for branches) and git restore (for files) arrived in Git 2.23 to split up the overloaded git checkout, which still works.
Check yourself
3 questions. Get them all right to finish this topic.
0 of 3 right so far. Get all three to finish this topic.