Skip to content

Must-Know Facts

Every topic's Must-Know Facts table in one place, for a fast revision pass. Tables are pulled in from the topic files, so this page never drifts from them. It grows as each module is added.


Foundations

What Is Git

Fact Value Verify with
Type Distributed VCS: every clone is a full repository with complete history git log works offline
Storage model Snapshots of the whole tree per commit, not per-file diffs git cat-file -p HEAD
Object id Content hash (SHA-1, SHA-256 for new repos); identical content, identical id git hash-object
A commit A tree plus parent(s), author, committer and message git cat-file -p HEAD
The three areas Working tree, index (staging area), repository git status
Integrity Every object is checksummed; corruption is detectable git fsck
Local first Commit, branch, diff and log need no network any command offline
Created Linus Torvalds, 2005, to host Linux kernel development history

Install and Config

Fact Value Verify with
System scope /etc/gitconfig, all users; git config --system git config --show-scope --list
Global scope ~/.gitconfig, one user; git config --global git config --global --list
Local scope .git/config, one repository; git config --local git config --local --list
Precedence Local overrides global overrides system git config --show-origin <key>
Identity user.name and user.email, stamped into every commit git config user.email
Default branch init.defaultBranch, main on current Git git config init.defaultBranch
Editor core.editor, for commit messages and rebases git config core.editor
Alias git config --global alias.<name> "<command>" git config --get-regexp alias
Per-directory includeIf "gitdir:~/work/" includes another config file git config --show-origin user.email
Read one value git config --get <key> the value

The Three Trees

Fact Value Verify with
Working tree The files on disk you edit ls, git status
Index (staging area) The proposed next commit, a full tree of entries git ls-files -s
HEAD A pointer to the last commit on the current branch git rev-parse HEAD
git add Copies working-tree content into the index git diff --cached
git commit Writes the index as a new commit, advances HEAD git log -1
git diff Working tree vs index (unstaged changes) git diff
git diff --cached Index vs HEAD (staged changes) git diff --cached
git restore <file> Index to working tree (discard unstaged edit) git status
git restore --staged HEAD to index (unstage) git status
reset --soft Moves HEAD only git status
reset --mixed Moves HEAD and index (default) git status
reset --hard Moves HEAD, index and working tree git status

Core Workflow

Staging and Committing

Fact Value Verify with
Stage a file git add <path> copies it into the index git status
Stage everything tracked git add -u (updates and deletions, no new files) git status
Stage all changes git add -A (or git add . for the current dir) git status
Stage part of a file git add -p chooses hunks interactively git diff --cached
Commit git commit -m "<msg>" records the index git log -1
Commit tracked changes git commit -am "<msg>" (adds tracked, not new files) git log -1
Amend last commit git commit --amend (edit message or add files) git log -1
Short status codes Column 1 = index, column 2 = working tree git status -s
?? Untracked; A added; M modified; D deleted git status -s
Empty commit git commit --allow-empty records no change git log -1

Inspecting History

Fact Value Verify with
Compact log git log --oneline (short SHA plus subject) git log --oneline
Branch shape git log --oneline --graph --all git log --graph
Custom format git log --pretty=format:'%h %ad %an %s' --date=short git log
First parent back HEAD~1 (or HEAD~n for n steps) git rev-parse HEAD~1
Nth parent HEAD^2 selects the second parent of a merge git rev-parse HEAD^2
Log range A..B = reachable from B, not from A git log A..B
Log symmetric A...B = commits on either side but not both git log --left-right A...B
Diff two-dot git diff A..B = tip-to-tip (A versus B) git diff A..B
Diff three-dot git diff A...B = B against the merge base of A and B git diff A...B
Upstream @{upstream} (or @{u}) is the tracked remote branch git log @{u}..HEAD
One commit git show <rev> shows its message and diff git show HEAD
Line authorship git blame <file> names the last commit per line git blame <file>

Ignoring and Attributes

Fact Value Verify with
Ignore a path A pattern line in .gitignore git status --ignored
Directory pattern Trailing slash, build/, matches a directory git check-ignore -v build/x
Negate !pattern re-includes a previously ignored path git check-ignore -v
Which rule matched git check-ignore -v <path> prints file:line:pattern git check-ignore -v
Already tracked .gitignore never untracks a committed file git status
Untrack, keep on disk git rm --cached <path> git status
Global ignore core.excludesFile, for editor and OS files git config core.excludesFile
Attributes file .gitattributes sets per-path behaviour git check-attr -a <path>
Normalise endings * text=auto stores LF, checks out native git check-attr eol <path>
Mark binary *.png binary disables text diff and merge git check-attr -a <path>

Undoing Changes

Fact Value Verify with
Discard unstaged edit git restore <file> (index to working tree) git status
Unstage git restore --staged <file> (HEAD to index) git status
Undo commit, keep staged git reset --soft HEAD~1 git status
Undo commit, keep unstaged git reset --mixed HEAD~1 (default) git status
Undo commit, discard all git reset --hard HEAD~1 (destructive) git log
Undo a pushed commit git revert <sha> (new inverse commit) git log
File from an old commit git restore --source=<rev> <file> git status
Remove untracked files git clean -fd (-n to preview) git clean -nd
Recover after reset git reflog still names the old tip git reflog
Rule of thumb revert shares safely; reset rewrites local only team workflow

Branching and Merging

Branches

Fact Value Verify with
A branch A file under refs/heads/ holding one 40-character commit SHA cat .git/refs/heads/main
HEAD A pointer to the current branch, or to a commit when detached cat .git/HEAD
Create only git branch <name> creates without switching git branch
Create and switch git switch -c <name> (older: git checkout -b) git branch --show-current
Switch git switch <name> (older: git checkout <name>) git branch --show-current
Previous branch git switch - returns to the last branch git branch --show-current
Rename git branch -m <old> <new> git branch
Delete merged git branch -d <name> refuses if commits are unmerged git branch
Delete forced git branch -D <name> deletes even unmerged commits git reflog
Upstream The remote branch a local branch tracks git branch -vv
Set upstream git push -u origin <name> or git branch --set-upstream-to git status -sb
Default name init.defaultBranch, main on current Git git config init.defaultBranch

Merging

Fact Value Verify with
Fast-forward Possible when the current branch has no commits the other lacks; Git moves the pointer git merge --ff-only <branch>
Three-way merge Used when both branches advanced; creates a merge commit with two parents git show --no-patch HEAD
Merge base The common ancestor of the two branch tips git merge-base A B
Default strategy ort (Ostensibly Recursive's Twin), since Git 2.34 git merge --no-edit output
Force a merge commit git merge --no-ff <branch> even when fast-forward is possible git log --graph
Squash git merge --squash <branch> stages the result with no merge parent git status -s
Abort git merge --abort restores the pre-merge state git status
No-op merge Already up to date when the branch is already an ancestor git merge <branch>
Parents First parent is the branch merged into; second is the merged branch git show --format=%p HEAD
Editor Non-fast-forward merges open a message editor unless --no-edit git config core.editor

Rebasing

Fact Value Verify with
Rebase Replays the current branch's commits onto a new base as new commits git rebase <base>
Result Linear history; every replayed commit gets a new SHA git log --oneline
Merge vs rebase Merge keeps history and adds a merge commit; rebase rewrites it linearly git log --graph
Golden rule Never rebase commits others have already pulled team policy
--onto git rebase --onto <newbase> <upstream> <branch> moves a commit range git log --graph
After a conflict git rebase --continue or git rebase --abort git status
Pull with rebase git pull --rebase replays local commits on top of fetched ones git config pull.rebase
Interactive git rebase -i <base> edits, squashes and reorders git rebase -i HEAD~3
Dirty tree git rebase --autostash stashes and restores uncommitted work git config rebase.autoStash
After rewriting A pushed branch needs git push --force-with-lease git push --force-with-lease

Interactive Rebase

Fact Value Verify with
Start git rebase -i <base> opens a todo list of the commits after <base> git rebase -i HEAD~3
pick Keep the commit unchanged the todo list
reword ® Keep the commit, edit its message the todo list
edit (e) Stop at the commit to amend its content the todo list
squash (s) Fold into the previous commit and combine messages the todo list
fixup (f) Fold into the previous commit and discard this message the todo list
drop (d) Remove the commit the todo list
Reorder Move a todo line to change commit order the todo list
Autosquash git commit --fixup=<sha> then git rebase -i --autosquash git config rebase.autoSquash
Effect Every commit from <base> forward gets a new SHA git log --oneline

Conflict Resolution

Fact Value Verify with
Conflict Both sides changed the same lines, so Git cannot merge them automatically git status
Markers <<<<<<< HEAD, =======, >>>>>>> <branch> wrap the two versions grep -n '^<<<<<<<' <file>
Ours The side above =======; HEAD during a merge git checkout --ours <file>
Theirs The side below =======; the merged-in branch during a merge git checkout --theirs <file>
Status code UU means both modified and unmerged git status -s
Index stages git ls-files -u lists stage 1 base, 2 ours, 3 theirs git ls-files -u
Mark resolved git add <file> after editing removes the conflict git status
Finish git commit for a merge, git rebase --continue for a rebase git log --graph
Abort git merge --abort or git rebase --abort git status
Reuse git config rerere.enabled true records and replays resolutions git rerere status

Cherry-Pick

Fact Value Verify with
Cherry-pick Applies one commit's diff onto the current branch as a new commit git cherry-pick <sha>
New identity Same change and message, new SHA and committer git log -1
Record source -x appends (cherry picked from commit <sha>) git log -1 --format=%b
Range git cherry-pick A..B copies commits after A through B git log --oneline
Author date Preserved from the original; committer date is now git show --format=fuller
Apply only -n (--no-commit) stages the change without committing git status
Conflict Resolve, git add, then git cherry-pick --continue git status
Abort git cherry-pick --abort restores the pre-pick state git status
Skip git cherry-pick --skip drops the current commit in a range git status
Main use Backporting a fix to a maintenance or release branch team workflow

Remotes and Collaboration

Remotes

Fact Value Verify with
Remote A named URL for another repository git remote -v
origin The default name for the clone source git remote
Remote-tracking branch origin/main, a local cache of the remote's main git branch -r
git fetch Updates remote-tracking refs only; no working change git branch -r
git pull git fetch then integrate (merge or rebase) git status -sb
Add git remote add <name> <url> git remote -v
Rename git remote rename <old> <new> git remote
Change URL git remote set-url <name> <url> git remote -v
Inspect git remote show <name> the output
Prune stale git remote prune <name> or git fetch --prune git branch -r
Ahead/behind git status -sb against the upstream git status -sb

Pushing and Pulling

Fact Value Verify with
Set upstream git push -u origin <branch> on the first push git status -sb
Push git push once an upstream is set git status -sb
Rejected push Remote moved: ! [rejected] ... (fetch first) the push output
Pull (merge) git pull (default) fetches then merges git log --graph
Pull (rebase) git pull --rebase replays local commits on top git log --oneline
Config the default pull.rebase=true, or pull.ff=only git config pull.rebase
Force (unsafe) git push --force overwrites whatever is there remote history
Force safely git push --force-with-lease refuses if the remote moved the push output
Delete remote branch git push origin --delete <branch> git branch -r
Push tags git push --tags or git push origin <tag> git ls-remote --tags

Tags and Releases

Fact Value Verify with
Lightweight tag A ref pointing at a commit, no metadata git cat-file -t <tag> shows commit
Annotated tag Its own object: tagger, date, message git cat-file -t <tag> shows tag
Create lightweight git tag <name> [<commit>] git tag
Create annotated git tag -a <name> -m "<msg>" git show <tag>
List git tag (add -l "<pattern>" to filter) git tag
Describe a build git describe = nearest annotated tag, distance, SHA git describe
Push one tag git push origin <tag> git ls-remote --tags
Push all tags git push --tags git ls-remote --tags
Delete local git tag -d <name> git tag
Delete remote git push origin --delete <tag> git ls-remote --tags
Signed tag git tag -s <name> (GPG or SSH) git tag -v <name>

Stashing

Fact Value Verify with
Stash changes git stash push -m "<msg>" git stash list
Include untracked git stash push -u (or --include-untracked) git stash show
Include ignored too git stash push -a (--all) git stash show
List git stash list (entries are stash@{n}) git stash list
Inspect git stash show -p stash@{0} the diff
Restore and remove git stash pop git stash list
Restore and keep git stash apply git stash list
Drop one git stash drop stash@{n} git stash list
Clear all git stash clear git stash list
Stash to a branch git stash branch <name> git branch
Storage A stash is a commit off refs/stash, not a file git log -g refs/stash

Forks and Pull Requests

Fact Value Verify with
Fork A server-side copy of a repo you can push to the hosting platform
origin Your fork (you have push access) git remote -v
upstream The original repository (usually read-only) git remote -v
Add upstream git remote add upstream <original-url> git remote -v
Sync a fork git fetch upstream, then update main from upstream/main git log
Fast-forward only git merge --ff-only upstream/main (no merge commit) git status -sb
Contribute Branch, push to origin, open a pull request the platform
PR review, CODEOWNERS Platform features, not Git itself delivery/github/
Keep main clean Work on branches, never commit to your fork's main git branch

Team Workflows

Branching Strategies

Fact Value Verify with
Trunk-based Short-lived branches, merge to main daily git log --graph
GitHub flow Branch, PR, review, merge to main, deploy team practice
Gitflow main, develop, feature/*, release/*, hotfix/* git branch -a
Release branch Stabilise a version while main/develop moves on git log --graph
Hotfix Branch from main, fix, merge back and forward git log --graph
Short-lived vs long Short branches minimise divergence and conflicts conflict frequency
Squash merge Collapse a branch to one commit on main git log --oneline
Feature flags Ship unfinished work behind a toggle, not a branch code
Protected branch Server-side rule; main takes no direct pushes the host
Fits CD Trunk-based; gitflow suits scheduled releases team goal

Commit Conventions

Fact Value Verify with
Conventional Commit type(scope): subject git log --oneline
Common types feat, fix, docs, refactor, test, chore the convention
Subject style Imperative mood, no trailing period, about 50 chars git log
Body Blank line, then why and what, wrapped near 72 chars git show
Breaking change type!: and a BREAKING CHANGE: footer git show
Sign-off git commit -s adds Signed-off-by: (DCO) git show -s
Trailers Key: value lines at the end (Co-authored-by, Refs) git interpret-trailers
Atomic commit One logical change, builds and passes on its own code review
Fix a message git commit --amend (last) or interactive rebase git log -1
feat vs fix Drives minor vs patch version bumps release tooling

Code Review with Git

Fact Value Verify with
Branch commits git log <base>..<branch> git log
Net change git diff <base>...<branch> (three-dot, merge base) git diff
Per-commit review git log -p <base>..<branch> git log -p
Run it git switch <branch>, test, git switch - back git branch
Between review rounds git range-diff <base> <old-tip> <new-tip> git range-diff
range-diff markers = identical, ! changed, </> only one side the output
Respond to a note git commit --fixup=<sha> targeting the reviewed commit git log --oneline
Fold fixups git rebase -i --autosquash <base> git log
Review a PR branch git fetch origin <branch> then diff and run git branch -r

Release and Versioning

Fact Value Verify with
Semantic version MAJOR.MINOR.PATCH, for example 1.4.2 the tag
MAJOR Incompatible (breaking) change BREAKING CHANGE commits
MINOR Backward-compatible feature feat commits
PATCH Backward-compatible fix fix commits
Pre-release 1.4.0-rc.1, sorts before 1.4.0 the tag
Release tag Annotated (or signed) tag on the release commit git show <tag>
Changelog input git log <lasttag>..HEAD git log
Current build git describe names it from the last tag git describe
Release branch release/1.4 to stabilise while main moves on git branch
Bump source The commit types since the last release release tooling

History and Recovery

Reflog and Recovery

Fact Value Verify with
Reflog A local log of where HEAD (or a ref) has pointed git reflog
Entry syntax HEAD@{n} is the position n moves ago git reflog
Per-branch reflog git reflog show <branch> git reflog show main
Recover after reset git reset --hard HEAD@{1} (the pre-reset tip) git log
ORIG_HEAD The tip before the last reset, merge or rebase git rev-parse ORIG_HEAD
Recover a commit git branch <name> <sha> at the lost SHA git log <name>
Deleted branch git branch -D prints the tip SHA; recreate from it git reflog
Local only The reflog is per-clone, never pushed or fetched it stays local
Expiry Unreachable entries expire (default 30/90 days), then gc prunes git config gc.reflogExpire
Last resort git fsck --lost-found finds dangling commits git fsck

Bisect

Fact Value Verify with
Purpose Find the first commit that introduced a regression git bisect
Method Binary search: about log2(n) tests for n commits the step counts
Start git bisect start <bad> <good> Git checks out a midpoint
Mark manually git bisect good / git bisect bad per checkout the next midpoint
Automate git bisect run <cmd> (exit 0 good, 125 skip, else bad) the result
Skip untestable git bisect skip (build broken at that commit) the next midpoint
Result <sha> is the first bad commit the output
Finish git bisect reset returns to where you started git status
Exit 125 Reserved: tells run the commit is untestable (skip) the script

Rewriting History

Fact Value Verify with
Rewrite = new SHAs A changed commit and all its descendants get new ids git log --oneline
Amend git commit --amend rewrites the last commit git log -1
Reset git reset moves the branch, dropping commits git reflog
Interactive rebase git rebase -i squashes, reorders, rewords, drops git log
Whole history git filter-repo rewrites every commit (paths, content) git log
Golden rule Never rewrite commits others have pulled team history
Safe scope Local, unpushed commits, or a branch that is yours alone git log @{u}..HEAD
After rewriting a pushed branch git push --force-with-lease the push output
Old commits survive In the reflog until gc prunes them git reflog
filter-branch The old, slow, error-prone tool; prefer filter-repo Git docs

Filter-Repo and Secrets

Fact Value Verify with
First response Rotate the secret; assume it is already leaked the provider
Tool git filter-repo (separate install, not built in) git filter-repo --version
Remove a file git filter-repo --path <file> --invert-paths git log -- <file>
Scrub a string git filter-repo --replace-text <rules> git log -p
Replacement rule secret==>REDACTED per line in the rules file the file
Rewrites everything Every affected commit gets a new SHA git log --oneline
Old tool git filter-branch is slow and error-prone; avoid Git docs
Alternative BFG Repo-Cleaner, fast for blobs and strings BFG docs
After rewrite Force-push, and every clone must re-clone or reset team coordination
Not a substitute Rewriting does not un-leak; rotation does incident process

Internals

Object Model

Fact Value Verify with
Blob File content, no name or metadata git cat-file -p <blob>
Tree A directory: names, modes, and blob/tree SHAs git cat-file -p <tree>
Commit A tree plus parent(s), author, committer, message git cat-file -p HEAD
Tag object An annotated tag: target, tagger, message git cat-file -t <tag>
Object id Hash of type + size + content git hash-object
Content addressed Identical content, identical SHA (dedup) git ls-tree HEAD
Type of an object git cat-file -t <sha> git cat-file -t HEAD
Size of an object git cat-file -s <sha> git cat-file -s HEAD
Snapshot Each commit points at a full tree, not a diff git cat-file -p HEAD
Immutability Changing content changes the SHA, so a commit is fixed git hash-object

Refs and HEAD

Fact Value Verify with
Ref A name pointing at an object, usually a commit git for-each-ref
Branch ref refs/heads/<name>, a file with one SHA cat .git/refs/heads/main
Tag ref refs/tags/<name> git rev-parse <tag>
Remote ref refs/remotes/origin/<name> git branch -r
HEAD A symbolic ref to the current branch cat .git/HEAD
Detached HEAD HEAD holds a raw SHA, not a ref: cat .git/HEAD
Symbolic ref A ref pointing at another ref git symbolic-ref HEAD
Loose ref A file under .git/refs/ ls .git/refs/heads
Packed ref Collected into .git/packed-refs cat .git/packed-refs
Peeled tag An annotated tag ref dereferenced to its commit git rev-parse <tag>^{commit}

How Merge and Rebase Work

Fact Value Verify with
Merge base The common ancestor of two commits git merge-base A B
Three-way merge Combines base, ours and theirs into one tree git merge
Merge commit Has two (or more) parents git cat-file -p <merge>
ort strategy The default merge algorithm since Git 2.34 git merge -s ort
Fast-forward No merge commit; the ref moves up git log --graph
Rebase Replays each commit as a patch onto a new base git rebase <base>
Rebase result New SHAs, one parent each, linear history git log --oneline
Rebase conflict Per-commit, resolved then --continue git status
Why SHAs change New parent (and time) means a new commit hash git log
Merge preserves DAG Rebase rewrites it into a line git log --graph

Packfiles and GC

Fact Value Verify with
Loose object One zlib-compressed file under .git/objects/ git count-objects -v
Packfile Many objects in one delta-compressed .pack ls .git/objects/pack
git gc Packs objects, prunes unreachable, packs refs git count-objects -v
Delta compression Similar objects stored as diffs against a base git verify-pack
Auto gc Runs when loose objects pile up (gc.auto) git config gc.auto
Prune window Unreachable objects kept ~2 weeks by default git config gc.pruneExpire
Integrity check git fsck verifies objects and connectivity git fsck

Advanced Tooling

Hooks

Fact Value Verify with
Location .git/hooks/, one executable per hook name ls .git/hooks
Not committed .git/ is local, so hooks do not travel with a clone clone and check
Shared hooks Version a directory and point core.hooksPath at it git config core.hooksPath
Client hooks pre-commit, commit-msg, pre-push, post-checkout run locally
Server hooks pre-receive, update, post-receive run on the remote
Exit code Non-zero from a pre-* hook aborts the action the hook output
Bypass git commit --no-verify skips pre-commit/commit-msg the commit succeeds
Sample hooks .sample suffix means disabled; rename to enable ls .git/hooks
pre-commit framework A tool that manages hooks from a config file .pre-commit-config.yaml
Enforcement Local hooks are advisory; CI is the real gate team policy

Submodules

Fact Value Verify with
A submodule is a pointer The parent stores a commit SHA, not the files git ls-files --stage <path>
Gitlink mode 160000 marks a submodule entry in the tree git ls-files --stage
.gitmodules Tracked file mapping path to URL cat .gitmodules
Local config .git/config holds the resolved URL per clone git config --list
Add git submodule add <url> <path> git submodule status
Clone with them git clone --recurse-submodules <url> folder is populated
After a plain clone git submodule update --init --recursive folder is populated
Update to tracked tip git submodule update --remote new SHA checked out
Pointer move is a commit The parent must commit the new SHA git status
Remove git submodule deinit then git rm .gitmodules updated

Worktrees

Fact Value Verify with
Worktree An extra checkout sharing one .git object store git worktree list
Add git worktree add <path> <branch> (-b for a new branch) git worktree list
One branch, one worktree A branch cannot be checked out in two at once the error below
Linked .git In a linked worktree, .git is a file, not a directory cat <path>/.git
Remove and prune git worktree remove <path>; prune clears stale entries git worktree list

Large Repos

Fact Value Verify with
Shallow clone --depth N fetches only the last N commits git rev-list --count HEAD
Deepen later git fetch --deepen N adds more history commit count grows
Unshallow git fetch --unshallow fetches the rest --is-shallow-repository
Partial clone --filter=blob:none skips blobs until needed missing-object count
Promisor Absent blobs are fetched on demand from the remote --missing=print
Sparse-checkout Materialize only chosen paths in the working tree git sparse-checkout list
Cone mode Directory-based sparse patterns, the default and fast sparse-checkout set
Git LFS Stores large binaries out of band, a pointer in Git git lfs ls-files
Maintenance git maintenance start schedules background upkeep git config maintenance.strategy
History is intact Shallow/partial/sparse limit transfer, not the repo the remote is complete

Credentials and Signing

Fact Value Verify with
SSH auth Key pair; public key on the host, private key local ssh -T git@host
HTTPS auth A token via a credential helper, never a password git config credential.helper
Credential helper Caches or stores the token so it is not retyped git config credential.helper
macOS helper osxkeychain, built in git config credential.helper
Windows helper Git Credential Manager (manager) git config credential.helper
Commit signing gpg.format selects openpgp, ssh or x509 git config gpg.format
SSH signing Reuse an SSH key to sign commits (Git 2.34+) git log --show-signature
Sign a commit -S, or commit.gpgsign true for all git log --pretty=%G?
Verify Needs allowedSignersFile for SSH signatures git log --show-signature
Signature status %G? is G (good), B (bad), N (none) git log --pretty=%G?