The object model
Commit
An immutable object holding one tree (a complete snapshot of every tracked file), zero or more parent hashes, an author, a committer, and a message — named by the hash of those bytes.
Avoid: change, changeset, diff, patch.
Snapshot
The complete state of every tracked file at one commit, stored as a tree. What a commit records.
Avoid: version, revision.
Blob
The contents of a single file, stored without its name or path, addressed by the hash of those contents.
Avoid: file object.
Tree
A directory listing that maps names to blobs and to other trees. The root tree of a commit is its snapshot.
Avoid: folder object, manifest.
Hash
An object’s name, computed from its own content. Because a commit’s content includes its parent’s hash, a hash encodes the object’s entire ancestry.
Avoid: ID, revision number, SHA as a standalone noun — say “the hash”.
Parent
The hash of the commit immediately preceding this one. Absent on a root commit; present twice on a merge commit.
Avoid: previous version, predecessor.
Ancestor / descendant
An ancestor is any commit reachable by following parents backwards. A descendant is any commit from which this one is reachable. Git can walk to ancestors directly; descendants must be searched for.
Avoid: earlier commit, later commit.
Reachable
A commit is reachable if some ref — branch, tag, HEAD, or reflog entry — leads to it by following parents backwards. Unreachable commits still exist on disk; they simply have no name pointing at them.
Avoid: lost, deleted, gone.
Rewriting history
Producing new commits that replace old ones, and moving a ref to the new chain. Git never edits a commit: rebase, --amend, squash and cherry-pick all work this way. The old commits are abandoned, not deleted.
Avoid: editing a commit, changing a commit.
Porcelain / plumbing
Porcelain is git’s human-facing layer (log, commit, status). Plumbing is the low-level, script-facing layer (cat-file, rev-parse, hash-object). Most git confusion lives in the gap between the two.
Avoid: high-level / low-level commands.
Refs and names
Ref
A name that points at a commit, stored as a file under .git/refs/. Branches, tags and remote-tracking names are all refs — the same mechanism in different directories.
Avoid: label, alias.
Branch
One file under .git/refs/heads/ containing a single commit hash — the tip. Not a series of commits: a branch reaches everything behind its tip by following parents. Git records no parent branch for any branch.
Avoid: a line of development, a series of commits, a copy.
`HEAD`
The file .git/HEAD, naming where you are. Normally it holds ref: refs/heads/<branch> — a pointer to a pointer — which is why git commit knows which branch file to move.
Avoid: the current commit, the tip, the latest.
Detached `HEAD`
HEAD holding a raw commit hash instead of a branch name. Nothing is broken; commits made here move no branch file, so they become unreachable once you leave.
Avoid: broken state, lost state, error.
The three trees
The three trees
HEAD, the index, and the working tree — the three places a version of a file can be at once. The framing that makes add, commit, status and reset predictable.
Avoid: areas, stages, zones.
Working tree
The files on disk, as your editor sees them. The only one of the three not backed by the object database — which is why it is the only place work can truly be destroyed.
Avoid: working directory (Pro Git’s term — recognise it, don’t write it), local files, workspace.
Index
A complete proposed next commit, stored in .git/index, holding one blob hash per tracked file. Not a queue and not a list of filenames: the same shape of thing as a commit, one step from becoming one.
Avoid: the staging area as a different thing — it is the same thing. Also: the cache, the queue.
Staged
Written into the index. Because the index holds a blob hash, staging writes the content into the object database immediately — so staged work survives even reset --hard.
Avoid: marked, selected, added to the commit.
Tracked / untracked
A file is tracked if it has an entry in the index. Untracked means git has no record of it anywhere — which is why ?? in git status --short appears in both columns at once.
Avoid: known / unknown, versioned / unversioned.
Reset depth
How far down the three trees git reset walks: --soft moves HEAD only, --mixed (the default) also resets the index, --hard also overwrites the working tree. One command, three stopping points.
Avoid: undo, revert — git revert is a different command entirely.
Merging
Merge base
The best common ancestor of two commits — the third input to every merge, printed by git merge-base A B. Not a branch and not a tip: a commit both sides reach. Where two branches diverged.
Avoid: the fork point, the branch point, the original.
Three-way merge
The operation git performs on three snapshots — the two tips and the merge base — to produce one new snapshot. It never replays the commits in between, which is why the number of commits on either side is irrelevant.
Avoid: combining branches, applying changes, merging in.
Fast-forward
What happens when the merge base equals the tip you are on: git writes the other branch’s hash into your branch file and updates the index and working tree. No commit is created, and it cannot conflict. The name describes the pointer, not the files.
Avoid: a simple merge, a clean merge — a merge commit can also be clean.
Merge commit
A commit with two parents, recording a new snapshot computed from three. The only kind of commit that names more than one parent, and therefore the only place the graph rejoins.
Avoid: “a merge” unqualified — say whether you mean the operation or the commit.
Conflict
Git’s refusal to guess. Raised when both sides changed the same region relative to the merge base, per hunk — not per file. Two branches editing different regions of one file merge silently.
Avoid: a merge failure, an error, a clash.
Conflicts in detail
Unmerged
The state of a path git could not resolve. For unmerged paths only, the two status --short columns mean ours and theirs; everywhere else they mean index and working tree. Reading a conflict code with the ordinary rule names the wrong side.
Avoid: conflicted file — correct in speech, but unmerged is what the commands and codes say.
Stages 1, 2, 3
The three versions of a conflicted path held in the index at once: 1 is the merge base, 2 is ours (HEAD), 3 is theirs (MERGE_HEAD). Readable as git show :1:<path>, listed by git ls-files -u.
Avoid: versions, copies, base/ours/theirs as file names.
Conflict kind
Which shape of disagreement a path is in, not how bad it is. content (UU), add/add (AA), modify/delete (UD or DU). They need different resolutions, and only the first has markers.
Avoid: type of conflict, conflict class, severity.
Missing stage
The absence that names the kind. No stage 1 means the file did not exist at the base — add/add. No stage 3 means the other side removed it — modify/delete. No porcelain command shows an absence.
Avoid: empty stage, null stage.
Conflict markers
The <<<<<<<, ======= and >>>>>>> lines git writes into the working tree. Ordinary text with no meaning to git: nothing stops you committing them. zdiff3 adds a ||||||| section holding the merge base.
Avoid: conflict syntax, git’s markup.
Resolving
Running git add on a conflicted path, which collapses its three stage entries into one ordinary staged entry. It is an assertion that the path is correct — git never inspects what you resolved it to.
Avoid: fixing the conflict, accepting a change.
Rerere
“Reuse recorded resolution.” Git stores the shape of a conflict when the merge fails, and your answer when you commit — not when you git add. Meeting the same shape again it writes the resolution into the working tree and leaves the index alone.
Avoid: auto-resolve, conflict cache, remembering merges.
Preimage / postimage
The two halves of a rerere record, in .git/rr-cache/<id>/. The preimage is the conflict as git produced it; the postimage is the file as you left it. A resolution staged but never committed writes no postimage and is never learned.
Avoid: before/after, the recording.
Rebasing
Rebase
Taking the commits on your branch, one at a time, and making a new commit for each on top of a different base. Not a move and not an edit: the originals are left in place, unreachable, and copies take their names.
Avoid: moving a branch, re-pointing, sliding onto main, updating from main.
Replay
One step of a rebase: a single commit’s change applied to a base it was not written against. Each replay is its own three-way merge, so a rebase of n commits can conflict n times — where the equivalent merge conflicts once.
Avoid: applying, copying over, re-committing.
The cascade
Why rewriting one commit rewrites every commit above it: a commit’s hash is computed from bytes that include its parent’s hash, so a new parent forces a new child, and so on to the tip.
Avoid: knock-on effect, ripple — fine in speech, say “the cascade” in writing.
`REBASE_HEAD`
The commit currently being replayed, readable whenever a rebase has stopped. HEAD is the new base it is landing on; REBASE_HEAD is your commit. Together they settle the ours/theirs question without interpreting a label.
Avoid: the conflicting commit, the current commit.
`ORIG_HEAD`
Where HEAD was before the last operation that moved it wholesale. git reset --hard ORIG_HEAD is the one-line undo for rebase, merge and reset alike — but it holds one step, not a history.
Avoid: the backup, the previous state, the checkpoint.
Author / committer
A commit’s two identities and two dates. A rebase preserves the author and overwrites the committer — which makes a divergence between the two dates the durable signature of replayed history, and the only thing in git log that can detect a rebase after the fact.
Avoid: “the date”, “the commit date” — say which one.
Force-with-lease
git push --force-with-lease: overwrite the remote branch, but refuse if it has moved since you last fetched. It checks against your remote-tracking ref — so the check is only as fresh as your last fetch, and after a blind git fetch it is no protection at all.
Avoid: “force push” unqualified — plain --force has no such check.
Remotes
Remote
A named URL another repository lives at, stored in .git/config. origin is a nickname git clone chose for you, not a reserved word — a repository can have several remotes, or none.
Avoid: the server, the central repo, upstream (which means something else).
Bare repository
A repository with no working tree — just the object database and refs. What a remote actually is. Nothing about it is special to servers; it is a normal repository with nobody editing files in it.
Avoid: the server, the central copy.
Remote-tracking branch
A ref under .git/refs/remotes/<remote>/, e.g. origin/main. A local file holding a cached answer to “where was the remote’s branch when I last asked?” — never live, and stale by default.
Avoid: the remote branch, the branch on GitHub, the server’s main.
Upstream / tracking
The pairing between a local branch and a remote-tracking one, set by git push -u or by clone. It is what lets git status print an “ahead / behind” line at all.
Avoid: the parent branch, the source branch.
Ahead / behind
Two commit counts, computed against the remote-tracking ref, not the remote. A statement about your disk, which makes no network request.
Avoid: in sync, up to date with the server — both imply a network check that never happened.
Fetch
Download objects and update remote-tracking refs. Touches no local branch, no index and no working tree — which is what makes it safe to run at any moment, including mid-merge and mid-rebase.
Avoid: getting the latest, syncing, downloading changes.
Pull
Two commands: fetch, then either merge or rebase. Since git 2.27 a diverged branch with no configured strategy is a fatal error rather than a merge. Read every pull failure by asking which half it came from.
Avoid: getting changes, updating, syncing — all hide that a merge is happening.
`MERGE_HEAD`
The commit being merged in, readable whenever a merge has stopped. During a merge HEAD is yours and MERGE_HEAD is theirs — the exact inverse of REBASE_HEAD’s situation.
Avoid: the incoming commit, their branch.
Three-dot diff
git diff a...b — the diff from the merge base of a and b to b. What the branch did since it left, and what a pull request shows. Two dots is tip against tip, and charges a stale branch for everything a gained while it was away.
Avoid: “the branch diff”, “the PR diff” — say which dots.
Pull request
A record held by a hosting service, naming two branches and proposing one be merged into the other. Not a git object and not a git command: the merge it performs is an ordinary git merge, run on their machine.
Avoid: a git feature. “Merge request” is correct on GitLab; say “pull request” for GitHub.
Merge methods
Merge method
Which of three ways a pull request is landed. A repository-level setting, not a per-PR judgement call. All three produce byte-identical files; they differ only in the history left behind.
Avoid: merge strategy — that means ort, resolve, octopus, a different layer entirely.
Squash-merge
Landing a branch as one new commit on the target, whose only parent is the target’s old tip. Because it does not name the branch tip, nothing in the graph records that the branch landed.
Avoid: “squashing” — that is interactive rebase, which rewrites the branch in place.
Rebase-merge
Landing a branch by replaying its commits onto the target and fast-forwarding. Every commit survives as its own entry — and each is rewritten, so the branch as reviewed no longer exists anywhere afterwards.
Avoid: “rebasing” — the local operation, which lands nothing. Also: linear merge.
Squash trap
After a squash-merge main has the branch’s content but no reachability to it. So --merged still calls it unmerged, and one more commit on that branch re-proposes all of them — then conflicts on lines already correct. A branch is dead the moment it lands.
Avoid: a stale branch, a bad merge — nothing went wrong; this is the method working as designed.
Reachable / `--merged`
git branch --merged X lists branches whose tips are reachable from X — a question about walking parent pointers, not about whether the content arrived. Every branch-cleanup tool asks the graph question.
Avoid: already merged, absorbed, included — all three blur graph and content.
First-parent history
git log --first-parent main — follow only parent 1 through every merge commit, so the log reads as one line per landed branch. The reading a merge-commit history buys you, and the thing neither squash nor rebase-merge can give back.
Avoid: the main history, the real history.
Merge queue
A hosting-layer queue that lands pull requests one combination at a time, so a busy branch cannot be broken by two changes that were each green alone. Queueing groups your PR with the base branch and every PR ahead of it, tests that combination, and ejects yours if it fails.
Avoid: auto-merge — a different feature, which merges as soon as checks pass with no grouping. Also: merge train.
Mainline (`-m`)
Which parent of a merge commit counts as “the branch we stayed on”, named as a number: git revert -m 1. Reverting a merge also declares you never want that branch’s changes, so re-merging it later brings in nothing.
Avoid: the main branch, the first branch — it is a parent slot on one commit, not a branch.
Parallel work
Worktree
One checked-out working tree with its own index and its own HEAD, backed by a repository’s object database. N worktrees over one object database, so a commit made in any of them is immediately visible in all the others with no fetch.
Avoid: a copy, a checkout, a clone, a branch directory.
Linked worktree
A worktree whose .git is a file, not a directory — one line reading gitdir: <path>, pointing back into .git/worktrees/<id>/. That indirection is the entire mechanism.
Avoid: secondary repo, sub-repo.
Shared / per-worktree
The only rule you need: pseudo refs are per-worktree, refs under refs/ are shared. So HEAD, the index and the working tree are yours alone, while every branch, tag, remote-tracking ref, the stash, and the config are common to all.
Avoid: local / global, private / public.
The branch lock
Git’s refusal to check one branch out in two worktrees at once. The guardrail that makes parallel agents safe — but a property of one repository, so two separate clones can both sit on one branch with no complaint.
Avoid: branch conflict, branch in use — both sound like a failure; this is a safeguard succeeding.
Collision surface
The set of files two branches both changed since their merge base. A screen, not a verdict: an empty intersection guarantees no conflict, a non-empty one only means a conflict is possible.
Avoid: conflicting files, “the overlap” — say which: files touched, or regions that actually clash.
`merge-tree`
git merge-tree --write-tree <a> <b> — the real three-way merge, performed entirely in the object database. Exits 0 clean / 1 conflicted, touches no index and no working tree, and uses the same machinery as git merge.
Avoid: dry-run merge, test merge, simulated merge — it is a real merge; only the destination differs.
Recovery
Reflog
The local, per-repository log of every position a ref has held. Every commit, checkout, merge, rebase, amend and reset appends a line. Never pushed, never fetched, never cloned: it is a fact about your disk and nobody else’s.
Avoid: history, the log, the undo stack — it records positions, not changes, and nothing pops off it.
`HEAD@{n}`
Where HEAD stood n moves ago — a revision like any other. Distinct from HEAD~n, which walks parent pointers rather than reflog entries: after a reset the two answer completely different questions.
Avoid: the previous commit, “HEAD minus n” — that is HEAD~n, and confusing them is the classic error.
Dangling
An object present in the database but never directly used — nothing, including a reflog entry, names it. A dangling blob is the interesting case: content that was git add-ed and never committed.
Avoid: orphaned, lost, deleted.
Unreachable vs dangling
The reason most recovery advice is backwards. fsck treats all reflogs as heads, so a commit you abandoned ten minutes ago is reachable via its reflog entry and --unreachable will not report it. --no-reflogs asks the other question.
Avoid: using the two words interchangeably — the gap between them is exactly where fsck looks useless and is not.
The recovery window
How long the reflog keeps an entry, and so how long a mistake stays undoable: 90 days by default, or 30 for entries not reachable from the tip — the harsher default applying to exactly the pre-amend and pre-rebase commits you want.
Avoid: garbage collection, “the grace period” — say which of the two, since they differ threefold.
`--lost-found`
The fsck mode that writes dangling objects out as files under .git/lost-found/, blobs written as their contents rather than their object name — so recovered content is readable without knowing a hash. The last resort, never the first.
Avoid: recovery mode, undelete.
The `add` line
Where recoverability actually begins, and it is not the commit. git add writes a blob immediately, so staged content survives reset --hard; content never staged has no object behind it. The one genuinely irreversible command is git clean -fd.
Avoid: the commit line, the safety line.
The readback
Readback
A short statement of what was done to a repository, made from the repository alone and defensible from it. Four claims make one: what landed and by which method, what is still outstanding, what is missing, and what is about to collide.
Avoid: audit — implies a checklist and a pass/fail. Also: summary, which implies the history already said it.
The six commands
What a readback costs, and why it is a habit rather than a project: the decorated graph; author against committer dates; branch --merged; the reflog; a three-dot --name-only per branch; and merge-tree --write-tree per pair. None of them writes anything.
Avoid: the procedure — they are six questions, and the order only matters between the last two.
Words that mean two things
ours is always whatever HEAD is on. During a merge that is your branch, so theirs is the branch coming in. During a rebase HEAD is on the new base, so ours is their work and theirs is your own commit. Same two words, opposite meanings, and nothing in the output warns you. The fix is not to interpret the words at all: run git log --oneline -1 HEAD and git log --oneline -1 REBASE_HEAD and read the commits.
- “Commit” is always the noun — the object. For the act, say make a commit, never “a commit” meaning the change you made.
- “Diff” always means something git computed by comparing two trees, never something git stored.
- “Branch” is the ref, not the work done on it. When you mean the commits, say “the commits
featurereaches”. - “Index” vs “staging area” — one thing, two names. Prefer index: it is what the commands and the file are called, and “staging area” hides that it is a full snapshot.
- “Merge” is the operation; “merge commit” is the object it sometimes creates. A fast-forward is a merge that creates none — so “did it merge?” and “is there a merge commit?” are different questions.
- “Tree” is overloaded, and both senses are worth holding: a tree object (a directory listing) and one of the three trees (
HEAD, index, working tree).git write-treeturns the second into the first, which is the point rather than a coincidence.
- Pro Git — the bookEvery definition here is compatible with the book’s, and where this page prefers a different word the note says which and why.
- gitglossary(7)Git’s own glossary. Complete and terse, and written for people who already know the model — this page is the subset the course actually uses.
- Confusing git terminology — Julia EvansA catalogue of git words that mean something other than what they sound like. The reason the Avoid lines exist.