git initCreate a new empty git repository in the current directory.
⚠ Common pitfall: Running inside an existing repo creates a nested .git that confuses tooling. Run `git status` first.
git init
git init my-project
Git command cheat sheet — searchable, with explanations, common mistakes, and real examples.
git initCreate a new empty git repository in the current directory.
⚠ Common pitfall: Running inside an existing repo creates a nested .git that confuses tooling. Run `git status` first.
git init
git init my-project
git clone <url>Download a remote repository into a new local directory, with full history.
⚠ Common pitfall: For huge repos use --depth=1 (shallow) to skip history; you cannot push amends from a shallow clone without --unshallow.
git clone https://github.com/user/repo.git
git clone --depth=1 https://github.com/user/repo.git
git statusShow changed, staged and untracked files in the working tree.
git status
git status -s
git add <file>Stage a file (or all files with .) for the next commit.
⚠ Common pitfall: `git add .` from a subdirectory only adds that subtree; `git add -A` stages everything in the repo including deletions.
git add src/index.ts
git add .
git add -A
git add -p
git commit -m "msg"Record staged changes as a new commit with the given message.
⚠ Common pitfall: Forgetting to stage first creates an empty commit error; -am only stages tracked files (not new files).
git commit -m "fix: handle null user"
git commit -am "wip"
git commit --amendReplace the last commit with a new one (message and/or content).
⚠ Common pitfall: Amending a pushed commit rewrites history — collaborators need to force-pull or face conflicts.
git commit --amend
git commit --amend --no-edit
git commit --amend -m "better message"
git pushUpload local commits on the current branch to the tracked remote.
git push
git push origin main
git push -u origin <branch>Push a new local branch to the remote and set it as the upstream tracking branch.
⚠ Common pitfall: Without -u, future `git push` on this branch will keep asking for the remote/branch.
git push -u origin feature/login
git pullFetch changes from the tracked remote branch and merge them into the current branch.
⚠ Common pitfall: Default pull = fetch + merge, which creates merge commits. Many teams prefer `git pull --rebase`.
git pull
git pull --rebase
git fetchDownload new commits, refs and objects from a remote, but do NOT merge anything into your branches.
git fetch
git fetch origin
git fetch --all --prune
git clone --depth=1 <url>Shallow clone with only the latest commit (no history). Much faster for CI builds.
⚠ Common pitfall: Cannot push or rebase from a shallow clone until you run `git fetch --unshallow`.
git clone --depth=1 https://github.com/torvalds/linux.git
git mv <src> <dst>Rename or move a file and stage the change in one step.
git mv old-name.ts new-name.ts
git log -n 5Show only the last 5 commits (any number works).
git log -n 5
git log -3 --oneline
git tag <name>Create a lightweight tag on the current commit. Use -a for an annotated tag with message + tagger.
⚠ Common pitfall: Annotated tags (`git tag -a v1.0 -m "..."`) are recommended for releases — lightweight tags do not store metadata.
git tag v1.0.0
git tag -a v1.0.0 -m "first stable release"
git tag -d <name>Delete a local tag. To delete the remote tag too: `git push --delete origin <name>`.
git tag -d v1.0.0
git push --delete origin v1.0.0
git rm <file>Remove a file from the working tree AND stage the deletion.
⚠ Common pitfall: Use `git rm --cached <file>` to stop tracking without deleting from disk (e.g. for files newly added to .gitignore).
git rm secret.env
git rm --cached config.local.json
git commitCommit staged changes, opening the configured editor to write the message.
⚠ Common pitfall: Leaving the editor with an empty message aborts the commit. Save a non-empty body to proceed.
git commit
git commit -v
git add -pInteractively stage changes hunk by hunk, choosing which parts of a file to commit.
⚠ Common pitfall: A hunk too large to split shows up whole. Press `e` to hand-edit it, or `s` earlier to split.
git add -p
git add -p src/index.ts
git restore --source=<ref> <file>Restore a file to its state at a specific commit, branch or tag.
git restore --source=HEAD~2 src/index.ts
git restore --source=main config.json
git rm -r --cached <dir>Stop tracking a whole directory without deleting it from disk. Common after editing .gitignore.
git rm -r --cached node_modules
git rm -r --cached dist && git commit -m "chore: ignore dist"
git commit --allow-emptyCreate a commit with no changes. Useful to trigger CI or mark a milestone.
git commit --allow-empty -m "ci: trigger rebuild"
git tag -l <pattern>List tags, optionally filtered by a glob pattern.
git tag -l
git tag -l "v1.*"
git tag -l --sort=-version:refname
git show <tag>Show an annotated tag, its message, tagger, and the commit it points to.
git show v1.0.0
git describeProduce a human-readable name for the current commit based on the nearest tag (e.g. v1.0-14-g2414721).
⚠ Common pitfall: Fails with "no names found" if no annotated tag is reachable. Add `--tags` to include lightweight tags.
git describe
git describe --tags
git describe --tags --dirty
git archiveExport the tree of a commit as a tar or zip, without the .git directory.
git archive --format=zip --output=release.zip HEAD
git archive main | tar -x -C /tmp/snapshot
git branchList local branches; * marks the current branch.
git branch
git branch -a
git branch -vv
git branch <name>Create a new branch from the current HEAD, but do not switch to it.
git branch feature/login
git branch -d <name>Delete a local branch (safely — fails if it has unmerged commits).
⚠ Common pitfall: Use -D (capital) to force-delete unmerged branches — irreversible without reflog.
git branch -d feature/done
git branch -D feature/wip
git branch -m <new>Rename the current branch.
git branch -m main
git branch -m old-name new-name
git checkout <branch>Switch to an existing branch (legacy command — git switch is the modern replacement).
⚠ Common pitfall: `git checkout <file>` and `git checkout <branch>` are different commands sharing one name — confusing. Use `git switch` and `git restore`.
git checkout main
git checkout -
git checkout -b <new>Create a new branch from current HEAD and switch to it in one step.
git checkout -b feature/login
git checkout -b hotfix origin/main
git switch <branch>Switch to an existing branch. Modern replacement for `git checkout <branch>`.
git switch main
git switch -
git switch -c <new>Create and switch to a new branch. Modern replacement for `git checkout -b`.
git switch -c feature/login
git switch -c hotfix origin/main
git merge <branch>Merge the named branch into the current branch.
⚠ Common pitfall: Default merge creates a merge commit even when fast-forward is possible. Use `--ff-only` to refuse non-FF merges or `--no-ff` to always make a merge commit.
git merge feature/login
git merge --no-ff feature/login
git merge --ff-only origin/main
git merge --abortCancel an in-progress merge and restore the pre-merge state.
git merge --abort
git rebase <branch>Replay commits from current branch on top of <branch>. Linear history, but rewrites commit IDs.
⚠ Common pitfall: Never rebase commits already pushed to a shared branch — collaborators will get conflicts on every pull.
git rebase main
git rebase origin/main
git rebase --abortCancel an in-progress rebase and restore the pre-rebase state.
git rebase --abort
git rebase --continueAfter resolving conflicts during rebase, continue replaying remaining commits.
git add resolved-file.ts && git rebase --continue
git cherry-pick <sha>Apply the changes from a specific commit onto the current branch as a new commit.
⚠ Common pitfall: The cherry-picked commit gets a NEW SHA. Cherry-picking the same change twice creates duplicate logic.
git cherry-pick a1b2c3d
git cherry-pick a1b2c3d..f4e5d6c
git cherry-pick -x a1b2c3d
git branch -aList ALL branches (local + remote-tracking).
git branch -a
git branch --mergedList local branches fully merged into the current branch — safe to delete.
git branch --merged main
git branch --merged | grep -v "\*" | xargs git branch -d
git switch -Switch back to the previously checked-out branch (like `cd -` for branches).
git switch -
git checkout -
git switch --detach <ref>Check out a commit or tag in detached HEAD on purpose, e.g. to test an old release.
git switch --detach v1.0.0
git switch --detach HEAD~3
git branch -f <name> <ref>Move an existing branch pointer to another commit without checking it out.
⚠ Common pitfall: Cannot force-move the branch you are currently on. Switch away first, or use `git reset` instead.
git branch -f staging main
git branch -f release HEAD~2
git branch --no-mergedList branches NOT yet merged into the current branch — the ones still holding unique work.
git branch --no-merged
git branch --no-merged main
git branch --show-currentPrint just the name of the current branch (empty in detached HEAD). Script-friendly.
git branch --show-current
BR=$(git branch --show-current)
git merge --no-commit <branch>Merge but stop before committing, so you can inspect or tweak the result first.
git merge --no-commit --no-ff feature/login
git rebase --onto <newbase> <upstream> <branch>Replay only the commits in <upstream>..<branch> onto <newbase>. Surgically move a branch.
⚠ Common pitfall: Getting the three refs in the wrong order silently drops or duplicates commits. Verify with `git log --oneline` after.
git rebase --onto main feature-base feature/login
git rebase --skipSkip the current commit during a rebase (e.g. when its changes already exist upstream).
⚠ Common pitfall: Skipping drops the commit entirely. Only skip when you are sure the change is already present.
git rebase --skip
git merge-base <a> <b>Print the best common ancestor of two commits — the point where two branches diverged.
git merge-base main feature/login
git merge-base HEAD origin/main
git cherry-pick --continueAfter resolving conflicts during a cherry-pick, finish applying the commit.
git add resolved.ts && git cherry-pick --continue
git cherry-pick --abort
git cherry-pick -n <sha>Apply a commit's changes to the working tree and index but do NOT commit, so you can combine several.
git cherry-pick -n a1b2c3d
git cherry-pick --no-commit a1b2c3d f4e5d6c
git reset HEAD <file>Unstage a file (keep changes in the working tree).
git reset HEAD src/index.ts
git reset HEAD .
git reset --soft HEAD~1Undo the last commit but keep changes staged. The most "non-destructive" reset.
git reset --soft HEAD~1
git reset --mixed HEAD~1Undo the last commit and unstage everything, but keep working tree changes. This is the default.
git reset HEAD~1
git reset --mixed HEAD~1
git reset --hard HEAD~1Throw away the last commit AND wipe matching working tree changes. Destructive.
⚠ Common pitfall: Anything not committed AND not in reflog is gone. Run `git stash` first if you might want it back.
git reset --hard HEAD~1
git reset --hard origin/main
git revert <sha>Create a new commit that undoes the changes of <sha>. Safe on shared branches — does NOT rewrite history.
git revert a1b2c3d
git revert HEAD
git revert -m 1 <merge-sha>
git restore <file>Discard unstaged changes in a file (modern replacement for `git checkout -- <file>`).
git restore src/broken.ts
git restore .
git restore --staged <file>Unstage a file but keep working tree changes (modern replacement for `git reset HEAD <file>`).
git restore --staged src/index.ts
git stashSave uncommitted changes (staged + unstaged) onto a stack and reset the working tree.
⚠ Common pitfall: By default `git stash` does NOT include untracked files; use `git stash -u` to include them.
git stash
git stash -u
git stash push -m "WIP login form"
git stash popRe-apply the most recent stash AND remove it from the stash stack.
⚠ Common pitfall: If pop has conflicts the stash stays on the stack — fix conflicts then `git stash drop`.
git stash pop
git stash pop stash@{2}git stash listList all stashes with their indexes and messages.
git stash list
git stash dropDelete a single stash without applying it.
git stash drop
git stash drop stash@{1}git reflogShow local history of HEAD movements. Lifesaver for recovering lost commits / branches.
⚠ Common pitfall: Reflog is LOCAL ONLY — pushing/cloning does not copy it. Default expiry is 90 days.
git reflog
git reset --hard HEAD@{1}git clean -fdDelete untracked files (-f) and untracked directories (-d) from the working tree.
⚠ Common pitfall: Irreversible. Always `git clean -nfd` (dry-run) first to see what will be deleted.
git clean -nfd
git clean -fd
git clean -fdx
git restore --staged --worktree <file>Discard a file's changes in BOTH the index and the working tree, resetting it to HEAD.
⚠ Common pitfall: This is destructive for unstaged edits — there is no working-tree reflog to undo it.
git restore --staged --worktree src/broken.ts
git stash applyRe-apply a stash but KEEP it on the stack (unlike pop). Good for applying one stash to many branches.
git stash apply
git stash apply stash@{1}git stash branch <name>Create a new branch from the commit a stash was based on and apply the stash there. Best fix for "stash won't apply cleanly".
git stash branch wip-login stash@{0}git stash show -pShow the full diff of a stash before deciding to apply or drop it.
git stash show -p
git stash show -p stash@{1}git stash clearDelete ALL stashes at once. There is no confirmation.
⚠ Common pitfall: Cleared stashes are not in normal reflog views; recovery via `git fsck --unreachable` is painful. Be sure.
git stash clear
git reset --hard <sha>Move the current branch to <sha> and make the working tree match it exactly, discarding everything after.
⚠ Common pitfall: Uncommitted work is destroyed. The branch's old position survives in `git reflog` for ~90 days.
git reset --hard a1b2c3d
git reset --hard origin/main
git revert --no-commit <sha>Stage the inverse of a commit without committing, so you can revert several commits as one.
git revert --no-commit a1b2c3d
git revert -n HEAD~3..HEAD && git commit -m "revert last 3"
git revert --abortCancel an in-progress revert (e.g. a multi-commit revert that hit a conflict).
git revert --abort
git revert --continue
git clean -iInteractively choose which untracked files to delete, instead of nuking them all with -f.
git clean -i
git clean -id
git checkout <sha> -- <file>Pull a single file from an old commit into the working tree (and index) without touching anything else.
git checkout HEAD~3 -- src/config.ts
git checkout v1.0 -- README.md
git reset --mergeReset like --hard but keep working-tree changes that differ from the index — safer after a bad merge.
git reset --merge
git reset --merge ORIG_HEAD
git remote -vList all remotes with their fetch and push URLs.
git remote -v
git remote add <name> <url>Add a new remote under the given short name (usually `origin` or `upstream`).
git remote add origin https://github.com/me/repo.git
git remote add upstream https://github.com/orig/repo.git
git remote set-url <name> <url>Change the URL of an existing remote (e.g. switching from HTTPS to SSH).
git remote set-url origin git@github.com:me/repo.git
git remote rename <old> <new>Rename a remote.
git remote rename origin github
git remote remove <name>Remove a remote entirely (does NOT delete the remote repo itself).
git remote remove old-upstream
git fetch --pruneFetch from remote AND delete local remote-tracking branches whose remote counterparts are gone.
git fetch --prune
git fetch -p origin
git pull --rebaseFetch from remote and rebase local commits on top — keeps history linear, avoids merge commits.
⚠ Common pitfall: If you have unrelated remote changes and rebase fails, run `git rebase --abort` to back out.
git pull --rebase
git config --global pull.rebase true
git push --tagsPush local tags to the remote (regular push does not include them).
git push --tags
git push origin v1.2.0
git push --delete origin <branch>Delete a branch on the remote.
git push --delete origin feature/old
git push origin :feature/old
git ls-remote <url>List refs (branches, tags) on a remote WITHOUT cloning. Handy for inspecting a repo before downloading.
git ls-remote https://github.com/torvalds/linux.git
git ls-remote --heads origin
git push origin HEADPush the current branch to a remote branch of the same name without typing the name twice.
git push origin HEAD
git push -u origin HEAD
git push --set-upstream origin HEADPush the current branch and set its upstream in one shot, even on first push of a new branch.
git push --set-upstream origin HEAD
git branch --set-upstream-to=<remote>/<branch>Set or change which remote branch the current local branch tracks, without pushing.
git branch --set-upstream-to=origin/main
git branch -u origin/develop
git remote show <name>Show detailed info about a remote: URL, tracked branches, and which are up to date or stale.
git remote show origin
git remote prune <name>Delete local remote-tracking refs that no longer exist on the remote, without fetching new commits.
git remote prune origin
git remote prune origin --dry-run
git fetch <remote> <branch>Fetch only a specific branch from a remote into FETCH_HEAD.
git fetch origin main
git fetch upstream release/2.0
git fetch <remote> <pr-ref>Fetch a GitHub pull request branch directly by its refs/pull ref, then check it out.
git fetch origin pull/42/head:pr-42
git switch pr-42
git push --force-with-lease=<ref>:<expected>Force-push but only if the remote ref still points at the exact SHA you expect. The strictest safe force.
git push --force-with-lease=main:a1b2c3d origin main
git push --allPush all local branches to the remote in one command.
⚠ Common pitfall: This pushes even half-baked experimental branches. Prefer pushing branches explicitly.
git push --all origin
git remote get-url <name>Print the URL of a remote (script-friendly alternative to parsing `git remote -v`).
git remote get-url origin
git remote get-url --push origin
git push --force-with-leaseForce-push, but ONLY if the remote tip is what you last saw. The safe force-push.
⚠ Common pitfall: Plain --force overwrites teammates work silently. Always use --force-with-lease on shared branches.
git push --force-with-lease
git push --force-with-lease origin feature/login
git rebase -i HEAD~NInteractively rewrite the last N commits: reorder, squash, fixup, reword, drop.
⚠ Common pitfall: Rebasing pushed commits = history rewrite. Only do it on your own branches before PR.
git rebase -i HEAD~5
git rebase -i main
git commit --fixup=<sha>Create a fixup commit targeting <sha>. With `git rebase -i --autosquash` it auto-squashes into the right spot.
git commit --fixup=a1b2c3d
git rebase -i --autosquash main
git merge --squash <branch>Squash all commits of <branch> into one staged change without committing — you then write one summary commit.
git merge --squash feature/login
git commit -m "feat: login flow"
git format-patch <branch>Generate .patch files for each commit since <branch>. Used to mail patches to mailing lists (Linux kernel style).
git format-patch main
git format-patch -1 HEAD
git am <patch>Apply a mailbox-style patch (created by format-patch) as one or more commits.
git am 0001-fix-bug.patch
git request-pull <start> <url>Generate a summary of changes for asking an upstream maintainer to pull from you (pre-GitHub workflow).
git request-pull v1.0 https://github.com/me/repo feature-x
git pull --rebase --autostashAuto-stash dirty working tree, pull --rebase, then unstash. Great alias for the daily pull.
git pull --rebase --autostash
git config --global rebase.autoStash true
git worktree add <path> <branch>Check out an additional branch into a separate working directory — work on two branches without stashing.
⚠ Common pitfall: Worktrees share the same .git, so reflog / index ops still affect each other. List with `git worktree list`.
git worktree add ../hotfix hotfix/login
git worktree list
git worktree remove ../hotfix
git commit -sAppend a `Signed-off-by` trailer to the commit message — required by many open-source projects (DCO).
git commit -s -m "fix: null guard"
git commit --signoff --amend
git commit -SGPG-sign the commit so its authorship can be cryptographically verified (the "Verified" badge).
⚠ Common pitfall: Needs `user.signingkey` and `gpg`/`ssh` set up first, or the commit fails with "gpg failed to sign".
git commit -S -m "release: v2.0"
git config --global commit.gpgsign true
git rebase -i --autosquash <base>Interactive rebase that auto-orders fixup!/squash! commits next to their targets.
git rebase -i --autosquash main
git config --global rebase.autoSquash true
git commit --squash=<sha>Like --fixup but keeps your message so you can edit the combined message during autosquash.
git commit --squash=a1b2c3d -m "more detail"
git apply <patch>Apply a plain diff/patch to the working tree WITHOUT creating a commit (unlike `git am`).
⚠ Common pitfall: If the patch does not apply cleanly, add `--3way` to fall back to a 3-way merge using blob info.
git apply fix.patch
git apply --3way fix.patch
git apply --check fix.patch
git diff > <file>.patchSave current unstaged changes as a patch file to share or apply elsewhere.
git diff > my-change.patch
git diff --staged > staged.patch
git range-diff <a>...<b>Compare two versions of a patch series (e.g. before and after a rebase) commit by commit.
git range-diff main...feature@{1} main...featuregit range-diff origin/feature...feature
git worktree remove <path>Remove a linked worktree once you are done with it, cleaning up the .git bookkeeping.
⚠ Common pitfall: Fails if the worktree has uncommitted changes. Commit/stash first, or add `--force` if you really want to discard.
git worktree remove ../hotfix
git worktree prune
git notes add -m "<text>"Attach a note to a commit without changing its SHA — useful for review metadata or CI results.
⚠ Common pitfall: Notes are not pushed by default. Add a refspec or push `refs/notes/commits` explicitly to share them.
git notes add -m "reviewed by Alice" a1b2c3d
git push origin refs/notes/commits
git bundle create <file> <refs>Pack commits into a single file you can move over USB/email when there is no network, then clone/fetch from it.
git bundle create repo.bundle --all
git clone repo.bundle restored-repo
git config --global user.name "Name"Set your global git author name (applies to all repos).
git config --global user.name "Alice Wang"
git config --global user.email "you@example.com"Set your global git author email.
⚠ Common pitfall: Use a per-repo `git config user.email` inside work repos to keep personal/work commit attribution separate.
git config --global user.email "alice@company.com"
git config user.email "alice@personal.com"
git config --listShow every effective config setting (system + global + local), in evaluation order.
git config --list
git config --list --show-origin
git config --global alias.<name> <cmd>Create a custom git alias. Common ones: co=checkout, br=branch, st=status, lg="log --oneline --graph".
git config --global alias.co checkout
git config --global alias.lg "log --oneline --graph --all"
git config --global core.editor "code --wait"Set the editor git opens for commit messages, interactive rebase, etc.
git config --global core.editor "code --wait"
git config --global core.editor "vim"
git config --global init.defaultBranch mainMake `git init` create `main` as the default branch instead of `master`.
git config --global init.defaultBranch main
git config --global pull.rebase trueMake `git pull` always rebase by default (no more accidental merge commits).
git config --global pull.rebase true
git config --global core.autocrlf inputConvert CRLF to LF on commit but not on checkout. Recommended on macOS/Linux working with cross-platform repos.
⚠ Common pitfall: On Windows the recommended value is `true` (CRLF on checkout, LF on commit). Mixing them creates phantom diffs.
git config --global core.autocrlf input
git config --unset <key>Remove a single git config entry.
git config --global --unset user.email
git config --unset alias.co
git config --global core.excludesFile <path>Set a global ignore file applied to every repo (for editor/OS junk like .DS_Store).
git config --global core.excludesFile ~/.gitignore_global
git config --global rerere.enabled trueTurn on "reuse recorded resolution" so git replays your past conflict resolutions automatically.
git config --global rerere.enabled true
git config --global merge.conflictstyle zdiff3Show the common ancestor in conflict markers, making it far easier to see what each side changed.
git config --global merge.conflictstyle zdiff3
git config --global fetch.prune trueMake every fetch automatically prune deleted remote-tracking branches.
git config --global fetch.prune true
git config --global push.autoSetupRemote trueAuto-set the upstream on first push, so `git push` works without `-u` on new branches.
git config --global push.autoSetupRemote true
git config --global rebase.autoStash trueAutomatically stash and re-apply dirty changes around a rebase/pull --rebase.
git config --global rebase.autoStash true
git config --global diff.colorMoved zebraColor moved lines differently from added/removed ones, so refactors read clearly in diffs.
git config --global diff.colorMoved zebra
git config --global url.<base>.insteadOf <other>Rewrite remote URLs on the fly, e.g. force all GitHub HTTPS URLs to use SSH.
git config --global url."git@github.com:".insteadOf "https://github.com/"
git config --get-regexp <pattern>Print config keys/values whose names match a regex (e.g. all aliases).
git config --get-regexp alias
git config --get-regexp "^remote\."
git config --global credential.helper <helper>Choose how git caches/stores credentials (e.g. osxkeychain on macOS, cache with a timeout).
⚠ Common pitfall: The plain `store` helper writes the token in cleartext to ~/.git-credentials. Prefer the OS keychain.
git config --global credential.helper osxkeychain
git config --global credential.helper "cache --timeout=3600"
git logShow commit history for the current branch.
git log
git log -n 10
git log --author="Alice"
git log --oneline --graph --allCompact, one-line-per-commit graph of every branch — the most-used git log incantation.
git log --oneline --graph --all
git log --oneline --graph --all --decorate
git log -pShow commit history WITH the full diff of each commit.
git log -p
git log -p src/index.ts
git log --statShow commit history with file-change statistics (which files, how many lines).
git log --stat
git log --stat -n 5
git diffShow unstaged changes (working tree vs index).
git diff
git diff src/index.ts
git diff --stagedShow staged changes (index vs last commit) — what `git commit` would record.
git diff --staged
git diff --cached
git diff <branch1>..<branch2>Show the diff between the tips of two branches.
git diff main..feature/login
git diff origin/main..HEAD
git diff <branch1>...<branch2>Show changes on <branch2> since it diverged from <branch1> (uses merge base). Common for PR previews.
⚠ Common pitfall: Two dots vs three dots produce different diffs — three-dot is what PRs actually show.
git diff main...feature/login
git blame <file>Show, for every line of a file, the commit and author that last changed it.
⚠ Common pitfall: Whitespace-only / formatting commits hide real authors. Use `git blame -w --ignore-rev <fmt-sha>` to skip them.
git blame src/index.ts
git blame -L 10,30 src/index.ts
git blame -w src/index.ts
git show <sha>Show metadata and diff of a single commit.
git show a1b2c3d
git show HEAD
git show HEAD:src/index.ts
git shortlog -snSummarize commits per author with counts (sorted, numbered). Great for changelogs / credits.
git shortlog -sn
git shortlog -sn --since="1 month ago"
git bisectBinary-search through commits to find the one that introduced a bug.
git bisect start
git bisect bad
git bisect good v1.0
git bisect reset
git log -S "<text>"Find every commit that ADDED or REMOVED the given text — invaluable for "when did this string appear?".
git log -S "TODO" --source --all
git log -S "DEBUG_FLAG"
git grep <pattern>Search tracked files for a regex pattern (faster and ignore-aware vs plain grep).
git grep "TODO"
git grep -n "TODO" -- "*.ts"
git diff --name-onlyList ONLY the file names that changed, no diff body. Useful for piping to other commands.
git diff --name-only
git diff --name-only origin/main...HEAD | xargs eslint
git log --since/--untilFilter commits by date range. Accepts natural language like "2 weeks ago" or ISO dates.
git log --since="2 weeks ago"
git log --since=2026-01-01 --until=2026-02-01
git log --follow <file>Show a file's history across renames, so you keep its story even after `git mv`.
git log --follow src/renamed.ts
git log --follow -p src/renamed.ts
git log <a>..<b>List commits reachable from <b> but not from <a> — e.g. "what is on the branch but not on main".
git log main..feature/login
git log origin/main..HEAD
git log --first-parentFollow only the first parent of merges, giving a clean mainline view without feature-branch noise.
git log --first-parent --oneline
git log --first-parent main
git log --mergesShow only merge commits — handy for reviewing what was integrated and when.
git log --merges --oneline
git log --no-merges
git log --grep=<pattern>Search commit MESSAGES for a regex. Combine with -i for case-insensitive.
git log --grep="fix" -i
git log --grep="JIRA-123"
git log --pretty=format:"<fmt>"Customize log output with placeholders like %h (short sha), %an (author), %ar (relative date), %s (subject).
git log --pretty=format:"%h %an %ar — %s"
git log --pretty=format:"%C(yellow)%h%Creset %s"
git show <ref>:<path>Print the contents of a file as it existed at a given commit/branch, without checking it out.
git show HEAD~3:package.json
git show main:src/config.ts
git diff --word-diffShow diffs word by word instead of line by line — great for prose, docs, and config files.
git diff --word-diff
git diff --word-diff=color README.md
git diff --checkDetect whitespace errors and leftover conflict markers before you commit.
git diff --check
git diff --staged --check
git blame -L <start>,<end> <file>Blame only a line range of a file, instead of the whole thing.
git blame -L 40,80 src/index.ts
git blame -L :functionName src/index.ts
git rev-parse <ref>Resolve a ref (branch/tag/HEAD~3) to its full 40-char SHA. The Swiss-army knife of scripting.
git rev-parse HEAD
git rev-parse --short HEAD
git rev-parse --abbrev-ref HEAD
git rev-list --count <ref>Count commits reachable from a ref — e.g. how many commits are on a branch.
git rev-list --count HEAD
git rev-list --count main..feature
git cherry -v <upstream>List your commits not yet in <upstream>; a + means unmerged, a - means already applied.
git cherry -v main
git cherry -v origin/main feature
git whatchangedLike git log but always shows which files changed in each commit (older, file-focused log).
git whatchanged
git whatchanged --since="1 week ago"
git count-objects -vHReport how much disk the repo objects use, in human-readable units. Spot bloat before `git gc`.
git count-objects -vH
git submodule add <url> <path>Add another git repo as a submodule at the given path.
⚠ Common pitfall: Submodules pin a specific commit, not a branch. New clones need `git submodule update --init --recursive` or the dir will be empty.
git submodule add https://github.com/user/lib.git vendor/lib
git submodule initRegister submodules listed in .gitmodules into local .git/config.
git submodule init
git submodule update --init --recursiveInitialize, fetch and check out all submodules (and submodules-of-submodules) to their pinned commits.
git submodule update --init --recursive
git clone --recurse-submodules <url>
git submodule update --remoteMove each submodule to the latest commit of its tracked remote branch (then commit in the parent).
git submodule update --remote
git submodule update --remote vendor/lib
git submodule foreach <cmd>Run a shell command inside every submodule. Useful for batch git operations.
git submodule foreach git pull
git submodule foreach "git checkout main && git pull"
git submodule deinit <path>Remove a submodule cleanly: unregister it, then `git rm <path>` and commit.
⚠ Common pitfall: Just deleting the directory leaves stale .gitmodules / .git/config entries. Always deinit + rm.
git submodule deinit vendor/lib
git rm vendor/lib && rm -rf .git/modules/vendor/lib
git submodule statusShow each submodule's pinned commit and whether it is checked out, modified, or out of sync.
git submodule status
git submodule status --recursive
git submodule syncUpdate each submodule's recorded URL in .git/config to match .gitmodules after the URL changed.
git submodule sync
git submodule sync --recursive
git submodule set-branch --branch <branch> <path>Record which branch a submodule should track for `git submodule update --remote`.
git submodule set-branch --branch main vendor/lib
git clone --recurse-submodules <url>Clone a repo and check out all its submodules in one step — no separate init/update needed.
git clone --recurse-submodules https://github.com/user/repo.git
git -c submodule.recurse=true pullPull the superproject AND update submodules to their newly pinned commits in one command.
git -c submodule.recurse=true pull
git config --global submodule.recurse true
git checkout -- <file> (LEGACY — destructive)Discard ALL unstaged changes in <file>. Same as `git restore <file>`. Cannot be undone — there is no reflog for working-tree state.
⚠ Common pitfall: No prompt, no confirmation, no backup. Use `git stash` first if unsure.
git checkout -- broken.ts
git restore broken.ts
detached HEAD recoveryYou checked out a commit/tag directly (e.g. `git checkout v1.0`). Any commits you make here will be lost unless you create a branch.
⚠ Common pitfall: If you accidentally left detached HEAD with new commits, find them in `git reflog` and `git branch save-me <sha>` immediately.
git switch -c new-branch
git reflog
git branch save-me HEAD@{0}merge conflict resolutionWhen git stops mid-merge with conflicts: edit the <<<<<<< / ======= / >>>>>>> markers in each file, `git add` each resolved file, then `git commit` (or `git merge --continue`).
⚠ Common pitfall: Forgetting to `git add` the resolved file leaves the merge incomplete — commit will fail with "you have unmerged paths".
git status
git add resolved.ts
git commit
git merge --abort
recover lost commits with reflogAfter a botched reset/rebase/branch-delete, `git reflog` lists every HEAD movement. Find the SHA you want and `git reset --hard <sha>` or `git branch rescue <sha>`.
⚠ Common pitfall: Reflog entries expire (default 90 days for reachable, 30 days for unreachable). Recover sooner rather than later.
git reflog
git branch rescue HEAD@{3}git reset --hard HEAD@{5}undo `git push --force`If you force-pushed and overwrote teammates work: ask them to share their reflog (their local copy still has the old commits) and force-push that SHA back.
⚠ Common pitfall: GitHub keeps "lost" commits on its dangling-objects GC for ~14 days — you can sometimes recover via the API. ALWAYS use --force-with-lease.
# on a teammate's machine still holding the old SHAs:
git push --force-with-lease origin <sha>:main
remove a file from git historyA secret got committed. `git rm` only removes it going forward. To purge ALL history, use `git filter-repo` (modern, preferred) or BFG Repo Cleaner.
⚠ Common pitfall: After purge, rotate the secret anyway — anyone who cloned still has it. Then force-push the cleaned history.
git filter-repo --invert-paths --path secrets/key.pem
git push --force-with-lease origin --all
"fatal: refusing to merge unrelated histories"You tried to merge/pull two repos that have no common ancestor (e.g. cloned and re-inited). Add `--allow-unrelated-histories` if you really want to merge them.
git pull origin main --allow-unrelated-histories
"Your branch and origin/main have diverged"Both your branch and the remote gained commits. Decide: `git pull --rebase` to replay yours on top, or `git merge` to weave them. Never blindly `reset --hard`.
⚠ Common pitfall: A bare `git pull` here makes a noisy merge commit. Rebase keeps history linear if your commits are not yet shared.
git pull --rebase
git log --oneline --graph HEAD origin/main
"error: failed to push some refs"The remote has commits you do not have locally. Fetch and integrate first (`git pull --rebase`), then push again. Do NOT reach for --force.
⚠ Common pitfall: Force-pushing here silently deletes the remote commits you never saw. Only force after you have integrated them.
git fetch origin
git rebase origin/main
git push
accidentally committed to main instead of a branchCreate a branch at the current commit to save the work, then reset main back so it matches the remote.
⚠ Common pitfall: Do the branch step FIRST. If you `reset --hard` main before branching, the commits are only in reflog.
git branch feature/oops
git reset --hard origin/main
git switch feature/oops
.gitignore not ignoring an already-tracked filegitignore only affects untracked files. A file already committed keeps being tracked — untrack it with `git rm --cached`, then commit.
git rm --cached .env
echo ".env" >> .gitignore
git commit -m "chore: stop tracking .env"
wrong author on a commitFix the last commit with `git commit --amend --reset-author`; for older ones use interactive rebase with `--exec` or `git rebase -r`.
⚠ Common pitfall: Amending/rebasing rewrites SHAs. If already pushed to a shared branch, coordinate before force-pushing.
git commit --amend --reset-author --no-edit
git config user.email "right@example.com"
recover a deleted branchA deleted branch's tip lives in the reflog. Find its SHA with `git reflog` and recreate the branch there.
⚠ Common pitfall: reflog is local-only. If the deletion happened on a machine you no longer have, the tip may be unrecoverable.
git reflog
git branch recovered a1b2c3d
git switch -c recovered HEAD@{5}abort a half-finished interactive rebaseIf an interactive rebase went sideways, `git rebase --abort` returns you to exactly where you started.
⚠ Common pitfall: Abort works only while the rebase is in progress. Once finished, undo via `git reset --hard ORIG_HEAD` instead.
git rebase --abort
git reset --hard ORIG_HEAD
CRLF / LF "whole file changed" diffA diff showing every line changed is usually a line-ending mismatch. Normalize with a .gitattributes `* text=auto` rule and renormalize.
echo "* text=auto" >> .gitattributes
git add --renormalize .
git commit -m "chore: normalize line endings"
Searchable git command cheat sheet covering 100+ commands you actually type at the terminal. Every entry has the full syntax, a plain-English and Chinese explanation, the common pitfall people hit with it, and one or two real examples you can copy. Nine categories: basic (init, clone, status, add, commit, push, pull, fetch, tag, mv, rm), branch (branch, checkout, switch, merge, rebase, cherry-pick), undo & recovery (reset --soft / --mixed / --hard, revert, restore, stash, reflog, clean), remote (remote, fetch --prune, push -u, push --tags), collab (rebase -i, --autosquash, merge --squash, --force-with-lease, worktree), config & aliases, inspect & history (log, diff, blame, show, bisect, grep, log -S), submodules (add, init, update --remote, foreach, deinit), and common mistakes (detached HEAD recovery, merge conflict workflow, lost-commit recovery via reflog, undoing --force-push, purging secrets with filter-repo). Type any word and it filters live across commands, descriptions, pitfalls and examples; tap a category chip to scope. Bilingual EN/ZH, fully client-side, no tracking, no ads. Pair with our Regex Cheatsheet for the other "I always forget this syntax" reference, or Crontab Helper for the third thing every developer Googles weekly.
Paste or drop your content into the tool panel.
Click the button. All processing is local in your browser.
Copy the result or download to disk in one click.
Use it in the small gaps between coding, reviewing, debugging, and shipping.
These links move the current task into a more complete workflow.
A colleague force-pushed and wiped three of your commits from the shared feature branch. You filter the cheatsheet to "reflog", copy `git reflog`, find the SHA from before the overwrite, then run `git branch rescue HEAD@{6}` and force-push it back. The pitfall line reminds you reflog is local-only, so you do it on the machine where the commits last lived before garbage collection runs.
A new hire freezes at the terminal. You point them to the "Basic" category chip, which scopes the list to seven commands: init, clone, status, add, commit, push, pull. They work top to bottom in 20 minutes, and the pitfall on `git stash` ("does not include untracked files by default") saves them from losing a new file on day three.
A reviewer flags your `git checkout main` as outdated. You search "switch", read the entry explaining that Git 2.23 split checkout into `git switch` for branches and `git restore` for files, and copy the two-line rationale into the PR thread. The discussion ends in 30 seconds instead of a back-and-forth across three comments.
You committed a `.env` with a live token and pushed it. You search "secret", land on the `git filter-repo` entry, follow the example to strip the file from every commit, then force-push and rotate the key. The pitfall line warns that filter-repo rewrites SHAs, so you tell the two other contributors to re-clone instead of pulling.
Treating `git stash` as a safe backup. It skips untracked files unless you pass `-u`, so a brand-new file you never staged just gets left behind. Search "stash" and read the pitfall before you rely on it.
Typing `git push -f` out of habit. It silently erases a teammate's newer commit. Use `git push --force-with-lease`, which refuses unless the remote ref is exactly what you last saw.
Assuming `git checkout -- file` is reversible. Discarded working-tree changes were never committed, so reflog cannot bring them back. Stash or commit first, then discard.
Everything runs in your browser. The command list is a static in-memory array, and your search text is matched locally with zero network requests, so no query, command, or filter choice ever leaves the tab. Nothing is written to the URL, so the page is safe to use behind a corporate proxy or fully offline.
Folks in your role tend to reach for these alongside this tool.