Git Quick Reference
The four places a change can live, then the commands that move it between them, with the gotcha for each. Commands were run on Git 2.43 in a scratch repository.
Mental Model
Almost every Git command moves changes between four places. When a command surprises you, ask which two places it connects.
Daily Commands
Checked on Git 2.43 in a scratch repository.
| Command | What it does | Gotcha |
|---|---|---|
git status -s | Short status: staged and unstaged changes | Two letters: first = index, second = working tree |
git add -p | Stage hunk by hunk | The best way to keep commits focused |
git add -A | Stage everything including deletions | Will stage secrets and build output if not ignored |
git commit -m "msg" | Commit the staged changes | -a stages tracked files only; it ignores new files |
git commit --amend --no-edit | Fold staged changes into the last commit | Rewrites the commit; do not do it after pushing shared work. With nothing changed it refuses unless --allow-empty |
git diff | Working tree vs index | Shows nothing for staged changes: use git diff --staged |
git diff --staged | Index vs last commit | Also called --cached |
git diff A..B / A...B | Two dots: A to B. Three dots: B since the common ancestor | Three dots is what a pull request shows |
git diff --name-only HEAD~1 | List changed files since the previous commit | Add --stat for sizes |
git log --oneline --graph --decorate --all | Compact history of every branch | Define it as an alias |
git log -p -- path | History of one file with patches | Add --follow to continue across renames (single file) |
git show <rev>:path | Print a file as it was at a revision | Works with main:a, HEAD~2:a, v1:a |
git blame -L 10,20 file | Who last changed lines 10 to 20 | -w ignores whitespace, -C follows moved lines |
git rm --cached file | Stop tracking a file but keep it on disk | Also add it to .gitignore; .gitignore does not affect tracked files |
git clean -n / -fd | Preview / delete untracked files | Always run with -n first; -x also removes ignored files |
git mv old new | Rename and stage | Git detects renames; there is no real rename record |
Branches and Switching
switch (branches) and restore (files) split the old overloaded checkout.
| Command | What it does | Gotcha |
|---|---|---|
git switch name | Move to a branch | Fails if local changes would be overwritten |
git switch -c name [start] | Create and switch (optionally from a start point) | git switch -c x HEAD~1 branches from the previous commit |
git switch - | Back to the previous branch | Like cd - |
git switch --detach <rev> | Look at a commit without a branch | New commits here are lost unless you create a branch |
git branch -vv | List branches with upstream and last commit | Shows gone for branches deleted on the remote |
git branch --show-current | Print the current branch name | Empty when detached |
git branch -d name / -D name | Delete merged / delete regardless | -D can lose commits; they remain in the reflog for a while |
git branch -m new | Rename the current branch | Update the remote and upstream yourself |
git branch --merged main | Branches already merged into main | Good for cleanup |
git merge name | Merge into the current branch | --no-ff always creates a merge commit; --ff-only refuses otherwise |
git merge --squash name | Stage the combined changes without committing | Loses the individual commits and the merge link; commit yourself |
git merge --abort | Back out of a conflicted merge | Only while the merge is in progress |
git cherry-pick -x <rev> | Copy a commit onto the current branch | -x records the original id; duplicate commits cause conflicts on later merges |
Restore, Reset, Revert, Reflog
Choose by what you want to undo and whether the commit is already shared.
| Goal | Command | Touches | Gotcha |
|---|---|---|---|
| Discard changes in a file | git restore file | Working tree | Cannot be undone: the changes were never saved |
| Unstage a file | git restore --staged file | Index | Working tree keeps your edits |
| Get a file from another revision | git restore --source=HEAD~1 file | Working tree | Add --staged to also stage it |
| Undo last commit, keep changes staged | git reset --soft HEAD~1 | Moves the branch only | Good for re-doing the commit message or splitting |
| Undo last commit, keep changes unstaged | git reset --mixed HEAD~1 (default) | Branch and index | New files stay untracked |
| Undo last commit, throw changes away | git reset --hard HEAD~1 | Branch, index, working tree | Uncommitted work is gone; committed work is recoverable via reflog |
| Undo a commit already pushed | git revert <rev> | Adds a new commit | Safe on shared branches; reverting a merge needs -m 1 |
| Find a "lost" commit | git reflog | Read only | Local only; entries expire (by default after weeks), and gc can then remove the commits |
| Recover a deleted branch | git switch -c name <sha from reflog> | New branch | Do it soon |
| Stop a bad rebase | git rebase --abort | Restores the pre-rebase state | Only before it finishes; afterwards use git reset --hard ORIG_HEAD or the reflog |
| Move a branch pointer | git reset --hard <rev> | Rewrites the branch | Never on commits others have pulled |
Combining Work
Both integrate branches. Merge records that a join happened; rebase replays your commits on a new base.
| Question | Merge | Rebase |
|---|---|---|
| History shape | Keeps true history with a merge commit | Linear history |
| Commit ids | Unchanged | Replayed commits get new ids |
| Safe on pushed branches | Yes | No, unless everyone agrees; push with --force-with-lease afterwards |
| Conflicts | Resolve once | May resolve per replayed commit (git rerere can remember) |
| Typical use | Land a feature into main | Update your own feature branch on top of main, tidy local commits |
| Command | git merge main | git rebase main |
| Rebase part of a branch | not applicable | git rebase --onto newbase oldbase branch |
| Tidy commits | not applicable | git rebase -i HEAD~5 (squash, reword, drop, reorder) |
| Auto-squash fixups | not applicable | git commit --fixup <rev> then git rebase -i --autosquash <base> |
| After rebasing pushed work | not applicable | git push --force-with-lease, which refuses if the remote moved |
Everything Else Local
Small tools that save big time.
| Command | What it does | Gotcha |
|---|---|---|
git stash push -m "wip" | Shelve tracked changes | Untracked files need -u; ignored need -a |
git stash list / pop / apply | List; restore and drop; restore and keep | pop with conflicts keeps the stash entry |
git stash show -p stash@{0} | See what is in a stash | Stash is a stack, index 0 is the newest |
git tag -a v1 -m "release" | Annotated tag (has author, date, message) | Prefer it over lightweight tags for releases |
git tag -l 'v*' | List tags matching a pattern | Quote the pattern |
git push origin v1 / --tags | Publish a tag / all tags | Tags are not pushed by plain git push |
git tag -d v1; git push origin --delete v1 | Delete locally; delete on the remote | Two steps |
git bisect start / bad / good <rev> | Binary search for the commit that broke something | Finish with git bisect reset |
git bisect run ./test.sh | Automate it | Script exit 0 = good, 1 to 127 except 125 = bad, 125 = skip |
git worktree add ../wt branch | Check out another branch in a second folder | A branch can be checked out in only one worktree |
git worktree list / remove ../wt | List; delete a worktree | Deleting the folder by hand needs git worktree prune |
git range-diff A..B C..D | Compare two versions of a rebased series | Useful in reviews of force-pushed branches |
Fetch, Pull, Push
Remote branches are local copies named origin/main, updated only when you fetch.
| Command | What it does | Gotcha |
|---|---|---|
git clone url | Copy a repository and set origin | --depth 1 makes a shallow clone; some history commands fail |
git remote -v | List remotes | Fetch and push URLs can differ |
git fetch --prune | Download new commits and drop deleted remote branches | Changes no local branch |
git pull --rebase | Fetch, then rebase local commits | Plain pull merges by default unless configured; set pull.rebase |
git pull --ff-only | Fetch and fast-forward only | Fails (safely) if histories diverged |
git push -u origin name | Push and set upstream | With push.autoSetupRemote plain git push does this on first push |
git push --force-with-lease | Force push only if the remote is where you last saw it | Plain --force can erase teammates' commits |
git push origin --delete name | Delete a remote branch | Teammates keep a stale origin/name until they fetch --prune |
git ls-remote --tags origin | List remote tags without fetching | Handy in CI |
git remote set-url origin url | Change a remote URL | Check HTTPS vs SSH and which account owns it |
Finding Things
Three different searches, easy to confuse.
| Command | What it does | Gotcha |
|---|---|---|
git log -S"text" | Commits that changed the number of occurrences of text (pickaxe) | Good for "when was this line added or removed" |
git log -G"regex" | Commits whose diff matches a regex | Slower, finds modifications too |
git log --grep="fix" | Search commit messages | -i for case-insensitive |
git log --author="name" | Filter by author | Matches a pattern, not an exact name |
git log --since="2 weeks ago" | Filter by date | Also --until |
git shortlog -sn | Commit counts per author | Add --no-merges for fairness |
git grep -n "text" | Search tracked files in the working tree | Add a revision to search history snapshots |
git rev-parse --abbrev-ref HEAD | Current branch name for scripts | Prints HEAD when detached |
Config and Aliases
Set these once per machine. Each was accepted by Git 2.43 in a scratch repository; check git help config for the minimum version of a key on your install (for example push.autoSetupRemote needs Git 2.37 or newer).
Git Mistakes
- **
git reset --hardwith uncommitted work.** It cannot be recovered; stash first. - Rebasing a branch others have pulled. Their history diverges; use merge, or agree and use
--force-with-lease. - **
git push --force.** Use--force-with-lease. - Committing secrets, then deleting them in a later commit. They stay in history; rotate the secret and rewrite or purge history.
- **
.gitignoreon an already tracked file.** It does nothing; rungit rm --cachedfirst. - Working on a detached HEAD and switching away. The commits become reachable only through the reflog; create a branch first.
- **Reverting a merge commit without
-m 1.** Git does not know which parent to keep. - **
git pullcreating surprise merge commits.** Setpull.rebaseor use--ff-only. - **
git add -Aat the repository root.** Look atgit statusfirst.
Long-form pages and what was checked
| Topic | Page |
|---|---|
| CI pipelines that run on push and pull requests | CI/CD Pipelines |
| Shell habits used with Git | Linux & Shell Essentials |
| Release and rollout strategies | Deployment Strategies |
| More cheat sheets | All cheat sheets |
Checked on 2026-10-31 on Git 2.43.0: every command shape in chapters 2 to 8 (switch, restore, reset soft and mixed and hard, revert, reflog, stash push and pop, annotated tags, bisect, worktree add and list and remove, rebase --onto, amend, cherry-pick, range-diff, pickaxe search, branch and config commands) was run in a throw-away repository; conflict-resolution flows and remote commands (push, force-with-lease, clone) were not exercised against a real server and are listed from the documented behaviour. Config keys were accepted by git config, which does not prove their semantics; the one-line meanings follow the Git documentation. There is no long-form Git page on this site yet.