Git References and Branch Tips: Commits Are Objects, Branches Are Names
Build the reference model behind Git branches: commit objects stay immutable while branch references move between commits.
Intermediate
Start with the two different things Git is naming
A commit and a branch name are not the same kind of thing. A commit is an object in Git's object database. A branch is a line of development whose tip is identified by a branch head. Git's glossary defines a ref as a name that points to an object name or another ref, and the refs/heads/ namespace represents local branches. A branch name therefore gives you a movable name for a commit; it is not another copy of the commit.
git rev-parse HEAD
git rev-parse main
git rev-parse --symbolic-full-name main
git cat-file -t HEAD
git cat-file -t mainQuick check
Which statement matches Git's reference model?
A repository already has a commit at HEAD.The branch name and HEAD resolve to object names, while cat-file reports the resolved object type as commit.
A branch tip is a reference, not a new snapshot
The official branch documentation says that creating a branch creates a new branch head pointing at the current HEAD, or at a supplied start point, and does not switch the working tree to that branch. The important model is the pointer: two branch names may initially identify the same commit. No commit is required merely to create the second name.
git rev-parse main
git branch experiment
git rev-parse main
git rev-parse experiment
git branch --list --verboseQuick check
Immediately after `git branch experiment` with no start point, what should be true?
main and HEAD identify commit C.main and experiment both identify C; the current branch has not changed.
Quick check
Why can two branch names resolve to exactly the same commit ID?
main resolves to commit C.experiment can resolve to the same commit C without creating another C object.
Moving one branch reference leaves the other reference behind
Once two branch names point at the same commit, advancing one branch demonstrates what a movable reference means. A new commit changes the tip of the branch that is being developed. The other branch name remains at its previous commit until an operation explicitly moves that ref. The commit object that was already present is not rewritten by the mere movement of a branch name.
git branch experiment
git switch experiment
printf 'experiment\n' > experiment.txt
git add experiment.txt
git commit -m 'Experiment commit'
git rev-parse experiment
git rev-parse main
git rev-parse HEADQuick check
After committing on `experiment`, why does `main` still resolve to the earlier commit?
main and experiment both identify C.experiment identifies D while main still identifies C.
Prove the distinction with object IDs
The strongest laboratory evidence is to inspect the actual object names and object types before and after reference operations. `git rev-parse` resolves names to object IDs. `git cat-file -t` reports an object's type. For this lesson, compare the repository's object IDs before and after creating a branch: the new branch name should appear, but no new commit object should be required merely by creating that ref.
git cat-file --batch-all-objects --batch-check='%(objectname) %(objecttype)' | sort > /tmp/git-objects-before.txt
git branch audit-point
git cat-file --batch-all-objects --batch-check='%(objectname) %(objecttype)' | sort > /tmp/git-objects-after.txt
diff -u /tmp/git-objects-before.txt /tmp/git-objects-after.txtQuick check
What does an empty object-list diff demonstrate in this laboratory?
The repository's object IDs are recorded before branch creation.The same object IDs remain after the new branch ref is created; only the ref namespace has gained a name.
Resolve a branch name to its full ref name and commit
A short branch name such as `main` is a revision name that Git resolves to a ref. `git rev-parse --symbolic-full-name` can show the full ref name when the input is a ref, while ordinary `git rev-parse` resolves the revision to its object name. This gives you two complementary questions: which reference is this name, and which object does that reference currently identify?
git rev-parse --symbolic-full-name main
git rev-parse --verify main^{commit}
git rev-parse --verify refs/heads/main^{commit}Quick check
What is the useful distinction between these commands?
main is a local branch ref.Git can show its full refs/heads/main name and separately resolve it to the commit object ID.
Practice what you learned
Use the dedicated Git code-completion exercise for this lesson.
Boundary: branch management, HEAD, and detached HEAD come next
This lesson establishes the reference model only. It does not attempt to teach branch renaming, deletion, copying, forced branch movement, tracking configuration, or branch listing as a management topic; those belong to the dedicated branch-management lesson. It also avoids making HEAD the subject of this lesson and does not teach detached HEAD. Those states are separate curriculum ownership so that the learner first understands what a branch name points to before learning how Git chooses and changes the current branch.
Official-source boundary
This lesson uses only the official Git documentation: `git-branch`, `git-rev-parse`, the Git glossary, and the official user manual. The current official documentation baseline is Git 2.56.0. The local verification executable is Git 2.47.3; tests certify behavior actually observed on that executable and are not presented as proof of untested version-sensitive behavior.
Thanks for your feedback.
Mark this learning resource complete to track your learning progress.