The Object Model — Immutable Memories

Life as a Git repositoryintermediate · standard · comprehensive | model: claude-opus-4-8 | 2026-06-19
Quick ref
git cat-file -p <oid> inspect any object
git rev-parse HEAD resolve a name to an OID
git reflog recover "lost" commits
git switch -c topic create & move to branch
git restore --staged f unstage without losing work
git fetch && git rebase integrate after transport
git fsck --lost-found find dangling objects

The Object Model — Immutable Memories

Every state Git records is a content-addressed object whose name is the SHA-1/SHA-256 of its contents; change anything and you get a new object. The four types form a Merkle DAG.

ObjectContainsInspect
blobraw file bytes (no name)git cat-file -p <oid>
treenames → modes → blob/tree OIDs (a directory)git cat-file -p HEAD^{tree}
committree + parents + author/committer + messagegit cat-file -p HEAD
tagannotated tag: target OID + tagger + messagegit cat-file -p v1.0
git hash-object -w file
Write a blob, return its OID — the lowest-level "save".
git cat-file -t / -s <oid>
Show an object's type and size.
git write-tree
Snapshot the index into a tree object.
git commit-tree <tree> -p <parent>
Forge a commit from a tree — porcelain's true core.
Note A commit points to a full tree, not a diff. Diffs are computed on demand between two trees; history is a chain of complete snapshots.

Refs, HEAD & the Reflog — Pointers Into the Past

Refs are mutable names holding an OID; they make the immutable graph navigable. HEAD is usually a symbolic ref pointing at your current branch.

git update-ref refs/heads/x <oid>
Move a ref directly — plumbing for branch movement.
git symbolic-ref HEAD refs/heads/main
Make HEAD point at a branch instead of an OID.
git for-each-ref --sort=-committerdate
Enumerate all refs with formatting.
git reflog show main
Local diary of where a ref has pointed.
git rev-parse --symbolic-full-name @{u}
Resolve the upstream of the current branch.
git pack-refs --all
Collapse loose refs into .git/packed-refs.
Tip Detached HEAD just means HEAD holds an OID directly. Your commits aren't lost — git reflog remembers them until they expire (default 90 days).

Working Tree, Index & State Transitions

Three trees: the working tree (files on disk), the index (staged next commit), and HEAD (last commit). Most commands move content between them.

Modern (intent-clear)

git switch <branch> changes branches; git restore <path> restores file contents. These split the overloaded checkout.

Classic & plumbing

git checkout still does both. git update-index --add is the plumbing behind staging.

CommandHEADIndexWorktree
reset --softmoves
reset --mixed (default)movesreset
reset --hardmovesresetreset
restore --stagedreset
restorereset
commit --amendreplaces tip
git stash push -u
Shelve tracked + untracked changes as hidden commits.
git clean -fdn
Dry-run removal of untracked files/dirs (drop n to execute).
Warning reset --hard and clean -f discard uncommitted work that no object references — the reflog cannot save what was never committed.

Revision Selection & Pathspecs

HEAD~3 / HEAD^2
Nth first-parent ancestor / second parent of a merge.
main@{2.days.ago}
Reflog-based time travel for a ref.
A..B / A...B
Reachable from B not A / symmetric difference.
:/fix typo
Newest commit whose message matches a regex.
HEAD:path/file
Blob at a path in a given revision.
-- ':(exclude)*.log'
Magic pathspec to exclude matches.
Note .gitignore controls untracked files; .gitattributes controls how tracked files behave (eol, diff, filter, merge, export-ignore). Both are policy, not part of the object graph's content rules.

Integration — Merge, Rebase, Cherry-pick

Integration is separate from transport: these commands only rearrange the local graph by creating new objects and moving refs.

git merge-base A B
Best common ancestor — the basis of a three-way merge.
git merge --no-ff topic