Skip to content

References

Name tags for commits: References are like name tags stuck on specific commits — without them, commits are just anonymous blobs of data identified only by hash. References give you human-friendly names like main, HEAD, and v1.0 to navigate the commit graph.

Why it matters: Without references, you would need to remember 40-character SHA-1 hashes to do anything in Git. References make the history navigable and enable workflows like feature branches and releases.

The key insight: HEAD is a special reference that points to the currently checked-out commit — when you make a new commit, HEAD moves forward. Understanding this explains why detached HEAD states feel weird and why git reset moves HEAD.

A reference (or “ref”) is a named pointer to a Git object — almost always a commit. References are What make Git’s object graph navigable. Without them, commits would exist as isolated objects with No way to find them (except by hash).

References are stored as plain text files under .git/refs/Each containing a 40-character SHA-1 Hash:

.git/refs/
├── heads/
│ ├── main # contains: a3f2b1c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6
│ ├── feature # contains: b7e9d4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1
│ └── hotfix # contains: c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0
├── tags/
│ ├── v1.0 # contains: a3f2b1c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6
│ └── v2.0 # contains: e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4
└── remotes/
└── origin/
├── main
└── feature

A branch is a reference that moves forward as you make commits. It is stored at .git/refs/heads/<branch-name>.

Terminal window
## Create a branch
$ git branch feature-login
## Equivalent to: echo $(git rev-parse HEAD) > .git/refs/heads/feature-login
# Switch to a branch
$ git switch feature-login
# Equivalent to: echo feature-login > .git/HEAD
# List all branches
$ git branch -a

Design decision: Branches in Git are extremely lightweight — they are a single file containing 41 bytes. This is why Git encourages branching freely, unlike CVS or SVN where branching involves Copying the entire directory tree. The cost of creating a branch is O(1)O(1); the cost of merging Depends on the divergence between branches.

HEAD is a special reference that indicates which branch you are currently on (or which commit, In detached HEAD mode). It is stored at .git/HEAD:

# Attached HEAD (normal state)
ref: refs/heads/main
# Detached HEAD
a3f2b1c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6
stateDiagram-v2
    AttachedHead: Attached HEAD
    DetachedHead: Detached HEAD

    [*] --> AttachedHead
    AttachedHead --> DetachedHead: git checkout <commit-hash>
    AttachedHead --> DetachedHead: git checkout --detach
    DetachedHead --> AttachedHead: git switch <branch>
    DetachedHead --> AttachedHead: git checkout <branch>

    state AttachedHead {
        [*] --> Normal: HEAD → branch ref → commit
    }

    state DetachedHead {
        [*] --> Detached: HEAD → commit (no branch)
    }

When HEAD points directly to a commit (rather than a branch reference), you are in detached HEAD state. This means commits you create will not belong to any branch and will eventually be Garbage-collected unless you create a branch pointing to them.

gitGraph
    commit id: "A"
    commit id: "B"
    commit id: "C"
    branch feature
    checkout feature
    commit id: "D"
    checkout main
    checkout C
    commit id: "E"
    commit id: "F"

In the graph above, after checking out commit C (detached HEAD), commits E and F are orphaned — no branch points to them. To preserve them:

Terminal window
# While in detached HEAD at commit F
$ git branch recover-feature # Creates a branch pointing to F
  • Git Objects: Covers the underlying object model (commits, trees, blobs) that references point to.
  • The Three Trees: Explains the working directory, staging area, and repository lifecycle.
  • Branching: Branch creation and management that uses references to track commit history.