Quick ref
git cat-file -p <oid> pretty-print any objectgit rev-parse HEAD resolve a revision to its OIDgit reflog recover "lost" commitsgit switch -c name create + move to a branchgit restore --staged . unstage everythinggit fsck --lost-found find dangling objectsgit push origin HEAD:main explicit refspec pushThe Object Model — immutable, content-addressed
Every value in a repo is one of four object types, named by the hash of its contents. Identical content yields one object; rewriting content yields a new object and never mutates the old.
blobRaw file bytes — no name, no mode, no history.
treeA directory: list of (mode, name, oid) pointing at blobs/trees.
commitA snapshot: one root tree, zero+ parents, author/committer, message.
tagAnnotated tag object: target oid, tagger, message, optional signature.
| Concept | Meaning |
|---|---|
OID | SHA-1 (or SHA-256) of type + size + \0 + content |
| Loose object | One zlib-deflated file under .git/objects/ab/cdef… |
| Packfile | Many objects in one .pack, delta-compressed, with a .idx |
| Commit DAG | Directed acyclic graph formed by parent links |
| Reachability | An object lives if a ref can reach it through the DAG |
Note Commits store full snapshots, not diffs. The "diff" you see is computed on demand by comparing two trees; delta compression in packfiles is a storage detail, unrelated to commit semantics.
Plumbing — building objects by hand
Porcelain commands are scripts over these primitives. Knowing them demystifies everything else.
git hash-object -w fileWrite a blob from a file, print its OID.
git cat-file -t/-s/-p <oid>Show an object's type / size / contents.
git update-index --add fileStage a path into the index by hand.
git write-treeSnapshot the current index into a tree object.
git commit-tree <tree> -p <parent> -m msgForge a commit pointing at a tree; prints new OID.
git update-ref refs/heads/x <oid>Point a ref at a commit — the move that "publishes" work.
blob=$(git hash-object -w hello.txt)
git update-index --add --cacheinfo 100644,$blob,hello.txt
tree=$(git write-tree)
commit=$(git commit-tree $tree -m "by hand")
git update-ref refs/heads/main $commit
Tip The whole of
git commit is just these five steps. Creating objects and moving refs are separate acts — that separation is the key to recovery.The Three Trees — HEAD, index, working tree
What each is
HEAD is the last committed tree (usually via a branch). The index is the staged next commit. The working tree is your editable files.
Modern verbs
switch changes branches; restore moves file content between the three trees. They split the old overloaded checkout.
| Command | HEAD | Index | Worktree |
|---|---|---|---|
git reset --soft <c> | moves | — | — |
git reset --mixed <c> | moves | reset | — |
git reset --hard <c> | moves | reset | reset |
git restore --staged f | — | reset | — |
git restore f | — | — | reset |
git checkout <c> -- f | — | set | set |
git commit --amendReplace the tip commit with a new object — old one becomes unreferenced.
git stash push -uShelve worktree + index (incl. untracked) as hidden commits.
git clean -fdxDelete untracked files/dirs, including ignored — irreversible.
git switch -c feat origin/mainNew branch tracking a remote start point.
Warning
reset --hard and clean -fdx overwrite uncommitted work that was never turned into objects. Only committed/stashed state is recoverable via reflog.Refs, Reflogs & Reachability
Refs are mutable pointers into the immutable graph: a file under .git/refs/ or a line in packed-refs holding one OID. HEAD is usually a symbolic ref pointing at a branch.
git for-each-ref --sort=-committerdateScript-friendly listing of all refs and their targets.
git symbolic-ref HEADShow what branch HEAD points to (detached if not a ref).
git reflog show mainLocal history of where a ref has pointed — your undo