Git References and Namespaces
Updated
Understanding what branch you're on can be annoying. Understanding the syntax of Git references and namespaces should alleviate that pain.
The first thing to note is that a Git reference (or ref) is a name that normally points to a commit hash, sometimes indirectly through another symbolic ref. Refs are organized into namespaces using the forward slash: /.
Many loose references are stored as files under .git/refs/, but Git can also pack refs into .git/packed-refs, and some ref storage implementations do not use one file per ref. The name is the important part.
Every reference has a fully qualified name:
refs/heads/main -> local branch named main
refs/remotes/origin/main -> remote-tracking ref for main on origin
There are two important namespaces.
refs/heads/: local branches
These are local branches that you can check out and commit to directly.
refs/remotes/<remote>/: remote-tracking refs
These are the local cache of branch state learned from a remote.
Semantic distinction: main vs. origin/main
These are two independent refs that may point to different commits at any given time.
main (local branch)
- Fully qualified name:
refs/heads/main - Modified by local operations such as commit, merge, reset, and rebase
- Represents the user's local line of development
- Advances automatically when a new commit is made while it is checked out
origin/main (remote-tracking ref)
- Fully qualified name:
refs/remotes/origin/main - Usually updated by operations that communicate with the remote, including fetch, pull, clone, and a successful push to that branch
- Represents a local snapshot of what Git last learned about the remote's
main - Not a normal local branch you commit to directly
- May be stale relative to the actual remote until the next network operation