Skip to content
Foxipa

Suggest an edit

Tell us what should be corrected, clarified, or improved. Submission will be connected to Foxipa’s contribution service later.

No information is sent anywhere yet. Your suggestion is only prepared in your browser.

Learning

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.

Levels: Intermediate ~35 min read

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.

bash
git rev-parse HEAD
git rev-parse main
git rev-parse --symbolic-full-name main
git cat-file -t HEAD
git cat-file -t main

Quick 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.

bash
git rev-parse main
git branch experiment
git rev-parse main
git rev-parse experiment
git branch --list --verbose

Quick 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.

bash
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 HEAD

Quick 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.

bash
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.txt

Quick 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?

bash
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.

Was this page helpful?

Mark this learning resource complete to track your learning progress.