Quick ref
git cat-file -p <oid> print any objectgit rev-parse HEAD resolve ref to OIDgit for-each-ref list all refsgit reflog recover lost commitsgit switch -c new create + move branchgit restore --staged . unstage everythinggit push -u origin HEAD push + set upstreamThe Immutable Object Model
Git is a content-addressed key/value store: every object's name is the hash of its contents, so identical content is stored once and any change creates a new object.
| Object | Contains | Points to |
|---|---|---|
blob | Raw file bytes (no name) | nothing |
tree | Mode + name + OID rows | blobs and subtrees |
commit | Tree OID, parents, author/committer, message | one tree + parent commits |
tag | Target OID, type, tagger, message | any object (usually a commit) |
git cat-file -t <oid>Show an object's type.
git cat-file -s <oid>Show its size in bytes.
git cat-file -p HEAD^{tree}Pretty-print the root tree of HEAD.
git cat-file --batch-all-objects --batch-checkEnumerate every object with type and size.
Note OIDs are SHA-1 by default; new repos can use SHA-256 via
git init --object-format=sha256. The model is identical, only the hash differs.Plumbing: Building Objects by Hand
Porcelain commands are choreographies over these primitives; learning them demystifies the entire system.
git hash-object -w fileWrite a blob from a file, print its OID.
echo hi | git hash-object -w --stdinHash arbitrary content into a blob.
git update-index --add fileStage a path into the index.
git write-treeSnapshot the index into a tree object.
git commit-tree <tree> -p <parent> -m msgBuild a commit pointing at a tree.
git update-ref refs/heads/main <oid>Move a branch to a commit.
# A commit, entirely by hand:
blob=$(echo "hello" | git hash-object -w --stdin)
git update-index --add --cacheinfo 100644 $blob hello.txt
tree=$(git write-tree)
commit=$(git commit-tree $tree -m "manual commit")
git update-ref refs/heads/main $commit
Tip
git commit = write-tree + commit-tree + update-ref, plus hooks and the reflog entry.Refs, HEAD & Reflogs
Refs are mutable pointers (just files holding an OID) layered over the immutable graph; moving them is how history "advances."
git symbolic-ref HEADShow which branch HEAD points at; detached when it holds an OID.
git for-each-ref --sort=-committerdate refs/headsList branches by recency with format control.
git rev-parse --abbrev-ref HEADPrint the current branch name.
git reflog show mainWhere a ref has been; the safety net for "lost" work.
git pack-refs --allCollapse loose refs into
.git/packed-refs.git update-ref -d refs/heads/oldDelete a ref directly.
Note Reflogs are local, per-ref, and time-limited (default 90/30 days); they're invisible to collaborators and the only record of where refs used to point.
The Three Trees: Working Tree, Index, HEAD
What they are
HEAD is the last committed snapshot, the index is the proposed next snapshot (staging area), and the working tree is your editable sandbox on disk.
How commands move them
add copies working tree → index; commit seals index → HEAD; reset and restore push data back the other way.
git reset --soft <c>Move HEAD only; index and working tree untouched.
git reset --mixed <c>Default: move HEAD and reset index, keep working tree.
git reset --hard <c>Move all three; discards working-tree changes.
git restore --staged --worktree fileRestore a path in both index and working tree.
git switch -c topicCreate and check out a branch (ref-focused checkout).
git status -sbCompact view of the three trees' divergence.
Warning
reset --hard and clean -fd destroy uncommitted work that has no object and no reflog — there is nothing to recover.