Git glossary

30 terms in plain English — the vocabulary Git’s error messages assume you already know. Worth skimming once: most confusing errors become obvious the moment these click.

Jump to a term

HEAD~1 vs HEAD^

HEAD~1 means the first parent, one generation back. HEAD^ means the same thing for an ordinary commit, but on a merge commit HEAD^2 selects the second parent. Use ~ to walk backwards in time and ^ to choose between a merge's parents.

Index (staging area)

The commit you're composing. git add copies file contents into it, git commit turns it into a permanent snapshot. It's why you can edit a file after staging and commit the older version.

Working tree

The actual files on your disk. Changes here exist nowhere else until you stage or commit them, which is why they're the only thing Git genuinely cannot recover.

Blob / tree / commit

The three object types. A blob is a file's contents, a tree is a directory listing pointing at blobs and other trees, and a commit points at one tree plus its parent commits.

Dangling / unreachable object

An object no reference points to any more — a dropped stash, a deleted branch's commits, or a file staged but never committed. git fsck finds them, and garbage collection eventually deletes them.

Reflog

A local journal of every position HEAD and each branch has held, kept for about 90 days. It's the reason a bad reset, rebase or branch deletion is almost always reversible.

Fast-forward

A merge or push where the target simply moves forward along existing history because nothing diverged. A push that isn't a fast-forward gets rejected, because completing it would orphan commits.

Merge base

The most recent common ancestor of two branches. Every merge and every three-dot diff is computed relative to it, which is why 'unrelated histories' — no shared ancestor — stops a merge dead.

Upstream / tracking branch

The remote branch your local branch is paired with. It's what makes bare git push and git pull know where to go, and what 'ahead 2, behind 3' is measured against.

origin vs upstream

Just naming conventions for remotes. origin is normally where you cloned from; in a fork workflow origin is your fork and upstream is the original project. Git attaches no special meaning to either.

Detached HEAD

HEAD points at a commit rather than a branch, which happens when you check out a hash or tag. Commits made here belong to no branch and become unreachable once you switch away.

Fetch vs pull

Fetch downloads new commits and updates origin/* without touching your files — always safe. Pull is a fetch plus an immediate merge or rebase into your branch, which is why it can surprise you.

Rebase

Replaying your commits onto a new base, creating new commits with new hashes. Produces linear history, and must never be done to commits others have already pulled.

Cherry-pick

Copying the change from one commit into a new commit on your branch. The result is a duplicate change with a different hash, not a link to the original.

Force-with-lease

A force push that first checks the remote is still where you last saw it, and aborts if someone else pushed. Always prefer it over --force, which overwrites unconditionally.

Bare repository

A repository with no working files — just the object database and refs. It's what a server hosts, and what git clone --bare or --mirror produces for backups.

Stash

Uncommitted work parked on a stack as real commit objects. Because they're ordinary commits, a stash you dropped by accident can usually still be recovered with git fsck.

Refspec

The src:dst mapping that tells fetch or push which refs move where. It's why git push origin :branch deletes a branch — you're pushing nothing into it.

Porcelain vs plumbing

Porcelain commands (log, commit, merge) are the friendly interface. Plumbing commands (rev-parse, cat-file, ls-tree) are the stable, scriptable internals the porcelain is built from.

ORIG_HEAD

A ref Git writes before any operation that moves HEAD dramatically — merge, rebase, reset, pull. It holds the position you were at immediately before, which makes git reset --hard ORIG_HEAD the standard one-step undo for those commands.

MERGE_HEAD

A file in .git naming the commit currently being merged in. Its presence is what makes the next commit a merge commit, and what blocks pull, checkout and rebase until you finish or abort. CHERRY_PICK_HEAD and REVERT_HEAD work the same way.

Unborn branch

The state right after git init: HEAD names a branch that has no commit behind it yet. It's why a fresh repository reports being on main while git branch prints nothing, and why the first push fails with 'src refspec main does not match any'.

Packfile

A compressed bundle of many objects, stored with deltas between similar versions. Git packs loose objects during gc and transfers history as a single packfile, which is why an interrupted clone loses the whole transfer rather than part of it.

Shallow clone

A clone truncated to a set number of recent commits (--depth). Far smaller and faster, but blame, bisect and merge-base see only the truncated history. git fetch --unshallow fills in the rest afterwards.

Clean / smudge filter

A pair of programs Git can run on a file as it enters the index (clean) and as it's written to your working tree (smudge). Git LFS is built entirely on them: clean replaces a big file with a pointer, smudge swaps the pointer back for real content.

Worktree

An additional working directory attached to the same repository, created with git worktree add. Each has its own HEAD, index and files while sharing objects, refs and stashes — so you can have two branches checked out at once without a second clone.

safe.directory

The allow-list Git checks before operating in a repository owned by another user. Introduced for CVE-2022-24765, because a repository's own config can name commands Git will execute. It produces the 'detected dubious ownership' error.

Sideband

The secondary channel that carries progress messages alongside a packfile during fetch and push. 'Unexpected disconnect while reading sideband packet' simply means the connection died mid-transfer — it says nothing about the repository being damaged.

How Git actually works

Git is a distributed version control system: it records the full state of your project every time you commit, and every clone carries the entire history rather than just the latest files. Created by Linus Torvalds in 2005 to manage Linux kernel development, it is now the default way software is tracked, shared and shipped. The practical consequence is that almost nothing you commit can be permanently lost — which is why this page exists.

Commits are snapshots, not diffs

Most people picture Git storing a list of changes. It doesn't — each commit records a complete picture of every tracked file, plus a pointer to its parent. Identical files are stored once and shared between commits, so this is far cheaper than it sounds, and it's why checking out any commit in history is instant.

Three places your work can live

The working directory is your actual files. The index (or staging area) is the commit you're composing. The repository is permanent history. Nearly every confusing Git error makes sense once you ask which of these three a command touches — and it's exactly what separates git reset --soft, --mixed and --hard.

Everything is content-addressed

Git hashes the contents of every file, tree and commit into a SHA identifier. Change one byte and you get a different hash, which is what makes history tamper-evident. It's also why staging a file makes it recoverable: the content is written into .git/objects at that moment and never modified again.

Branches are just pointers

A branch is a file containing a single commit hash. That's the whole implementation. Creating one is instant regardless of project size, deleting one throws away a pointer rather than any commits, and 'moving work between branches' really means pointing a different name at the same commits.

The reflog remembers everything

Git keeps a private journal of every position each reference has held — including states that no branch points to any more. This is the safety net beneath resets, rebases and deleted branches, and it's kept for 90 days by default. It's local only, so a fresh clone starts with an empty one.

Every clone is a full backup

Because clones contain the complete history, there is no single point of failure. A colleague force-pushing over your branch destroys one pointer on one server while the commits themselves survive in every clone that had fetched them. Distribution is what makes most Git disasters recoverable.