Git Cheat Sheet

Every Git command worth knowing — 82 of them across 15 categories, each with its syntax, the flags you actually use, worked examples and a danger rating so you know what can bite. Includes 36 deep cuts — the plumbing, patch and maintenance commands most cheat sheets leave out.

82 commands

git configSafe

Read and write Git settings for one repo, your user, or the whole machine.

Git settings live in three layers: system (whole machine), global (your user), and local (this repository). The most specific layer wins, so a local setting overrides your global one. Your name and email are baked into every commit you make, so set them before your first commit or you'll be rewriting authorship later.

Syntax

git config
git config --global <key> <value>
git config --list --show-origin
git config <key>

Common options

  • --globalApply to your user account (~/.gitconfig) instead of just this repo.
  • --localApply to the current repository only (the default).
  • --listPrint every setting currently in effect.
  • --show-originShow which file each setting came from - the fastest way to debug a surprising value.
  • --unset <key>Remove a setting.
  • --editOpen the config file in your editor.

Examples

Set the identity stamped on every commit you make.

example
git config --global user.name "Your Name"
git config --global user.email "you@example.com"

Name the first branch main instead of master in new repos.

example
git config --global init.defaultBranch main

See every active setting and the exact file it came from.

example
git config --list --show-origin

A conditional include in ~/.gitconfig switches your email based on the folder.

example
# Use a different identity for work repos automatically
[includeIf "gitdir:~/work/"]
  path = ~/.gitconfig-work
git config --global alias.*Safe

Create your own short Git commands.

An alias maps a short name to any Git command and its flags, so a log incantation you can never remember becomes `git lg`. Prefixing the value with `!` runs an arbitrary shell command instead, which lets you build small tools that live with your config. Aliases are personal - they're never shared through the repository.

Syntax

git config --global alias.*
git config --global alias.<name> '<command>'
git config --get-regexp ^alias

Common options

  • alias.<name> '<cmd>'Define the alias.
  • '!<shell>'Leading ! runs a shell command instead of a Git subcommand.
  • --get-regexp ^aliasList every alias you've defined.

Examples

A solid starter set - then just run git lg, git st, git unstage <file>.

example
git config --global alias.lg "log --oneline --graph --all --decorate"
git config --global alias.st "status -sb"
git config --global alias.unstage "restore --staged"
git config --global alias.last "log -1 --stat"

Aliases for the two things you do most when interrupted.

example
git config --global alias.undo 'reset --soft HEAD~1'
git config --global alias.wip '!git add -A && git commit -m "wip"'
git credential / credential.helperSafe

Stop Git asking for your username and password on every push.

Git delegates authentication to a credential helper that stores your token in the OS keychain. GitHub removed password authentication for HTTPS in 2021, so the 'password' is now a personal access token - which is exactly why people suddenly get authentication failures on repos that worked for years. SSH keys avoid the whole problem.

Syntax

git credential / credential.helper
git config --global credential.helper <helper>
git credential-manager configure

Common options

  • managerGit Credential Manager - the cross-platform default, uses the OS keychain.
  • osxkeychainmacOS Keychain.
  • libsecretLinux, via the GNOME keyring.
  • cache --timeout=3600Keep credentials in memory for an hour. Never writes to disk.
  • storeWrite to a PLAINTEXT file. Convenient, and a genuine security risk.

Examples

Windows / cross-platform: use Git Credential Manager.

example
git config --global credential.helper manager

macOS: store credentials in the Keychain.

example
git config --global credential.helper osxkeychain

Clear a stale token after rotating it.

example
git credential-manager erase
# or clear one host:
git credential reject
protocol=https
host=github.com

git helpSafe

Open the full manual for any Git command.

Every Git command ships with a complete manual page. `git help <command>` opens it, and the `-h` short flag prints a quick usage summary in the terminal without leaving it. When you're unsure what a flag does, this is faster and more reliable than searching the web.

Syntax

git help
git help <command>
git <command> -h
git help --all

Common options

  • -hShort usage summary printed straight to the terminal.
  • --allList every available Git command.
  • -gList the internal guides (git help -g, then git help revisions).

Examples

Open the full manual for git reset.

example
git help reset

The guide explaining HEAD~3, HEAD^2, @{upstream} and every other way to name a commit.

example
git help revisions
git initSafe

Turn the current folder into a Git repository.

Creates a hidden `.git` directory that holds your entire history, configuration and object database. Nothing outside `.git` is touched, so running it on an existing project is safe - your files are simply now trackable. Deleting `.git` deletes all of your history, so never do that casually.

Syntax

git init
git init
git init <directory>
git init --bare <directory>

Common options

  • --bareCreate a repository with no working files - what a server hosting the repo uses.
  • -b <name>Name the initial branch (e.g. -b main).
  • --template=<dir>Seed .git/hooks and friends from your own template directory.

Examples

Start a new repository with main as the first branch.

example
git init -b main

Convert an existing project folder into a repo and record everything in it.

example
git init
git add .
git commit -m "Initial commit"
git cloneSafe

Copy a remote repository, its full history and its branches, onto your machine.

Clone downloads the entire object database - every commit, branch and tag - then checks out the default branch for you and wires up a remote named `origin`. Because you get the whole history, most Git operations afterwards are local and instant. Use `--depth` or `--filter` when you only need recent history and the repo is huge.

Syntax

git clone
git clone <url>
git clone <url> <directory>
git clone --depth 1 <url>

Common options

  • --depth <n>Shallow clone: only the last n commits. Much faster on huge repos.
  • --branch <name>Check out a specific branch or tag instead of the default.
  • --single-branchFetch only one branch's history.
  • --recurse-submodulesAlso clone and check out any submodules.
  • --filter=blob:nonePartial clone - fetch file contents lazily. The best option for very large repos.
  • --bare / --mirrorClone without a working tree; --mirror also copies every ref exactly (used for backups and migrations).

Examples

Standard clone into a folder named after the repo.

example
git clone https://github.com/user/repo.git

Grab only the newest commit on main - fast CI-style checkout.

example
git clone --depth 1 --branch main https://github.com/user/repo.git

Get all history but download file contents only when you actually touch them.

example
git clone --filter=blob:none https://github.com/user/huge-repo.git
git sparse-checkoutSafe

Check out only part of a huge repository.

Sparse checkout keeps the full history but materialises only the directories you name, so a monorepo with 40 packages can appear on disk as the three you actually work on. Combined with `--filter=blob:none` at clone time it turns an unusable 10 GB checkout into a fast one. Cone mode is the fast, directory-based variant and the one you want.

Syntax

git sparse-checkout
git sparse-checkout init --cone
git sparse-checkout set <dir>...
git sparse-checkout disable

Common options

  • init --coneEnable sparse checkout in the efficient directory-based mode.
  • set <dirs>Replace the list of directories to materialise.
  • add <dir>Add another directory to the working set.
  • listShow what's currently checked out.
  • disableGo back to a full checkout.

Examples

Clone a monorepo but only put two packages on disk.

example
git clone --filter=blob:none --no-checkout https://github.com/org/monorepo.git
cd monorepo
git sparse-checkout init --cone
git sparse-checkout set packages/web packages/shared
git checkout main
git statusSafe

Show what's changed, what's staged, and what Git is ignoring.

The command you should run more than any other. It tells you which branch you're on, whether you're ahead of or behind the remote, which files are staged for the next commit, which are modified but unstaged, and which are untracked. When something goes wrong, `git status` almost always names the command that fixes it.

Syntax

git status
git status
git status -s
git status -sb

Common options

  • -s, --shortCompact one-line-per-file output.
  • -b, --branchShow branch and tracking info even in short mode.
  • --ignoredAlso list files excluded by .gitignore.
  • -uallList individual untracked files instead of collapsing whole directories.

Examples

Compact status with the branch header - the everyday form.

example
git status -sb

Check whether .gitignore is actually excluding what you think it is.

example
git status --ignored
git addSafe

Stage changes so they go into your next commit.

Staging copies the current content of a file into the index - a holding area between your folder and history. This is why you can edit a file after staging it and end up committing the older version. Staging also writes the content into Git's object database, which is what makes some otherwise-lost work recoverable later.

Syntax

git add
git add <file>
git add .
git add -p

Common options

  • -A, --allStage every change in the repo, including deletions.
  • -p, --patchStep through each change and choose hunk by hunk what to stage.
  • -uStage modifications and deletions of already-tracked files, but not new files.
  • -n, --dry-runShow what would be staged without staging it.
  • -fForce-add a file that .gitignore excludes.

Examples

Stage everything under the current directory.

example
git add .

Interactively pick which hunks of one file to stage - the cleanest way to split a messy edit into focused commits.

example
git add -p src/app.ts
git commitSafe

Record everything currently staged as a permanent snapshot.

A commit stores a full snapshot of your tracked files plus a pointer to its parent commit, an author, a timestamp and a message. Once created it gets a unique SHA hash and becomes very hard to truly lose - even 'deleted' commits usually survive in the reflog for weeks. Write messages that explain why, not what; the diff already says what.

Syntax

git commit
git commit -m "message"
git commit
git commit --amend

Common options

  • -m <msg>Supply the message inline instead of opening an editor.
  • -aAuto-stage all tracked modified files first (does not include new files).
  • --amendReplace the previous commit instead of adding a new one.
  • --no-verifySkip pre-commit and commit-msg hooks.
  • --allow-emptyCreate a commit with no changes - sometimes needed to trigger CI.
  • --fixup <hash>Mark this as a fixup for an earlier commit, to be squashed by rebase --autosquash.
  • -SGPG-sign the commit.

Examples

Commit the staged changes with a message.

example
git commit -m "Fix crash when save file is empty"

Rewrite the last commit's message. Only safe if you haven't pushed it.

example
git commit --amend -m "Better message"

Record a fix against an old commit, then fold it in automatically.

example
git commit --fixup a1b2c3d
git rebase -i --autosquash a1b2c3d~1
git restoreCaution

Throw away working-directory changes or unstage files (the modern, clearer replacement for checkout).

Git 2.23 split the overloaded `git checkout` into two commands: `git switch` for branches and `git restore` for file contents. `git restore <file>` discards your edits; `git restore --staged <file>` unstages without touching your edits. Restoring a modified file is destructive - those edits were never in Git, so nothing can bring them back.

Syntax

git restore
git restore <file>
git restore --staged <file>
git restore --source=<commit> <file>

Common options

  • --stagedUnstage the file, leaving your working copy untouched.
  • --worktreeRestore the working copy (the default).
  • --source=<commit>Take the content from a specific commit instead of the index.
  • -pChoose hunk by hunk what to discard.

Examples

Unstage a file you added by mistake, keeping your edits.

example
git restore --staged src/app.ts

Permanently discard your uncommitted edits to that file.

example
git restore src/app.ts

Bring back the version of a file as it was three commits ago.

example
git restore --source=HEAD~3 -- src/app.ts
git mvSafe

Rename or move a file and stage the change in one step.

Git doesn't actually track renames - it infers them by comparing content between commits. `git mv` is therefore just a convenience for moving the file and running `git add` on both paths. It matters most on Windows and macOS, whose case-insensitive filesystems make a rename like `player.cs` to `Player.cs` invisible to a plain `mv`.

Syntax

git mv
git mv <source> <destination>
git mv -f <source> <destination>

Common options

  • -f, --forceOverwrite an existing destination.
  • -kSkip moves that would error instead of failing.
  • -n, --dry-runShow what would happen.

Examples

Rename a file and stage both the deletion and the addition.

example
git mv src/oldName.ts src/newName.ts

Fix a filename's capitalisation on a case-insensitive filesystem.

example
git mv --force player.cs Player.cs
git rmCaution

Delete a file from the repository - or just stop tracking it.

Plain `git rm` deletes the file from your disk and stages the deletion. `git rm --cached` removes it from Git's index only, leaving your local copy alone, which is the fix for a file that's already tracked and therefore immune to .gitignore. Neither form removes the file from history - earlier commits still contain it.

Syntax

git rm
git rm <file>
git rm --cached <file>
git rm -r --cached <dir>

Common options

  • --cachedUntrack the file but keep it on disk. The .gitignore fix.
  • -rRecurse into directories.
  • -fForce removal when the file has staged changes.
  • -n, --dry-runList what would be removed.

Examples

Untrack a file so .gitignore finally applies to it.

example
git rm --cached .env
echo ".env" >> .gitignore
git commit -m "Stop tracking local env file"

Untrack a whole directory that should never have been committed.

example
git rm -r --cached node_modules/
git branchCaution

List, create, rename and delete branches.

A branch is nothing more than a movable pointer to a commit, which is why creating one is instant and free no matter how big the repo is. Deleting a branch only removes the pointer - the commits it referenced stay in the object database and stay findable through the reflog, so a deleted branch is usually recoverable.

Syntax

git branch
git branch
git branch <name>
git branch -d <name>
git branch -m <old> <new>

Common options

  • -aList local and remote-tracking branches.
  • -dDelete a branch, refusing if it has unmerged commits.
  • -DForce delete even with unmerged commits.
  • -mRename a branch.
  • -vvShow each branch's upstream and how far ahead/behind it is.
  • --merged / --no-mergedFilter to branches already merged (safe to delete) or not.
  • --sort=-committerdateList by most recently worked on.

Examples

See every local branch with its upstream and ahead/behind counts.

example
git branch -vv

List branches fully merged into main - the ones that are safe to clean up.

example
git branch --merged main

Create a branch pointing at a specific commit - how you resurrect deleted work.

example
git branch feature-recovery a1b2c3d

Your ten most recently touched branches.

example
git branch --sort=-committerdate | head -10
git switchSafe

Move to another branch - the modern, safer half of git checkout.

`git switch` only changes branches, so it can't silently destroy a file the way a mistyped `git checkout` can. It refuses to move if you have uncommitted changes that would be overwritten, which is a feature. `git switch -` jumps back to the previous branch, like `cd -`.

Syntax

git switch
git switch <branch>
git switch -c <new-branch>
git switch -

Common options

  • -c <name>Create the branch and switch to it in one step.
  • -Switch back to the branch you were on before.
  • --detachDeliberately check out a commit without a branch.
  • -fForce the switch, discarding local changes. Destructive.
  • --orphan <name>Start a branch with no history at all.

Examples

Create a new branch off the current commit and move onto it.

example
git switch -c feature/save-system

Hop back to the branch you were just on.

example
git switch -

Move to main. Git refuses if uncommitted work would be lost.

example
git switch main
git checkoutCaution

The old all-in-one: switch branches, restore files, or detach HEAD.

Checkout does three unrelated jobs, which is exactly why it caused so many accidents and why Git split it into `switch` and `restore`. The dangerous form is `git checkout -- <file>`, which silently overwrites your uncommitted edits with no confirmation and no way back. You'll still see checkout everywhere in older guides, so it's worth knowing.

Syntax

git checkout
git checkout <branch>
git checkout -b <new-branch>
git checkout -- <file>
git checkout <commit> -- <file>

Common options

  • -b <name>Create and switch to a new branch.
  • -- <file>Discard uncommitted changes to a file. Irreversible.
  • <commit> -- <file>Pull one file's content out of another commit.
  • --ours / --theirsDuring a conflict, take one side of the merge wholesale.

Examples

Switch branches, old-style. Prefer git switch main.

example
git checkout main

Restore one file from an old commit without touching anything else.

example
git checkout a1b2c3d -- config/settings.json
git mergeCaution

Combine another branch's history into the current one.

Merge finds the common ancestor of the two branches and replays the differences, creating a merge commit with two parents unless it can fast-forward. It preserves the true shape of history, unlike rebase. If both sides changed the same lines, Git stops and asks you to resolve the conflict by hand.

Syntax

git merge
git merge <branch>
git merge --abort
git merge --continue

Common options

  • --no-ffAlways create a merge commit, even when a fast-forward is possible - keeps feature branches visible.
  • --ff-onlyRefuse unless it's a clean fast-forward.
  • --squashBring in the changes as one uncommitted lump instead of a merge.
  • --abortBail out of a conflicted merge and return to how things were.
  • --continueFinish the merge once you've resolved and staged the conflicts.
  • --allow-unrelated-historiesMerge two projects that share no common ancestor.

Examples

Merge a feature branch into main, keeping the branch visible in history.

example
git switch main
git merge --no-ff feature/save-system

Escape hatch when a merge goes wrong - restores the pre-merge state.

example
git merge --abort
git rebaseDestructive

Replay your commits on top of another branch to produce a straight, linear history.

Rebase takes each of your commits, sets them aside, moves your branch to the new base, and re-applies them one at a time. Because each replayed commit gets a brand new hash, you are creating new commits and abandoning the old ones - which is why rebasing anything you've already shared causes chaos for everyone else. The golden rule: never rebase public history.

Syntax

git rebase
git rebase <base>
git rebase -i HEAD~<n>
git rebase --abort
git rebase --continue

Common options

  • -i, --interactiveOpen an editor to reorder, squash, edit, drop or reword commits.
  • --onto <newbase>Move a range of commits onto a completely different base.
  • --abortCancel the rebase and restore the original branch.
  • --continue / --skipProceed after resolving a conflict, or skip the current commit.
  • --autostashStash uncommitted work before rebasing and reapply it after.
  • -r, --rebase-mergesPreserve the merge structure instead of flattening it.

Examples

Replay your branch's commits on top of the latest main.

example
git rebase main

Interactively clean up your last four commits before opening a PR.

example
git rebase -i HEAD~4

Move feature-b's commits off feature-a and onto main.

example
git rebase --onto main feature-a feature-b
git cherry-pickCaution

Copy one specific commit onto your current branch.

Cherry-pick applies the change introduced by a single commit as a new commit on your branch. It's the right tool for backporting a hotfix to a release branch, or for rescuing one good commit out of an abandoned branch. The result is a duplicate change with a different hash, so avoid cherry-picking commits you'll later merge anyway.

Syntax

git cherry-pick
git cherry-pick <commit>
git cherry-pick <start>..<end>
git cherry-pick --abort

Common options

  • -n, --no-commitApply the change but leave it staged so you can adjust it first.
  • -xAppend the original commit hash to the message - useful for backports.
  • -m <parent>Required when cherry-picking a merge commit.
  • --continue / --abort / --skipResume after resolving conflicts, cancel entirely, or skip this commit.

Examples

Bring one commit from another branch onto this one.

example
git cherry-pick a1b2c3d

Copy an inclusive range of commits.

example
git cherry-pick a1b2c3d^..f4e5d6c
git merge-baseSafe

Find the commit two branches diverged from.

The merge base is the most recent common ancestor of two branches, and it's what every merge and three-dot diff is computed against. Knowing it explicitly is invaluable in scripts and CI, where 'show me only what this pull request changed' means diffing against the merge base rather than the tip of main.

Syntax

git merge-base
git merge-base <a> <b>
git merge-base --is-ancestor <a> <b>
git merge-base --fork-point <branch>

Common options

  • --is-ancestor <a> <b>Exit 0 if a is an ancestor of b. Perfect for scripts.
  • --fork-pointUse the reflog to work out where a branch actually forked.
  • --allPrint every merge base when there is more than one.

Examples

Print the commit where the feature branch diverged from main.

example
git merge-base main feature

Show only what your branch changed, ignoring anything main added since.

example
git diff $(git merge-base main HEAD)..HEAD --stat
git mergetoolSafe

Open a visual three-way diff tool to resolve conflicts.

When conflict markers in a text editor get overwhelming, mergetool launches a configured GUI showing your version, their version and the common ancestor side by side. Most editors (VS Code, JetBrains, Meld, Beyond Compare) can register as the merge tool. Configure it once and conflicts become far less intimidating.

Syntax

git mergetool
git mergetool
git config --global merge.tool <tool>

Common options

  • --tool=<name>Use a specific tool for this run.
  • -ySkip the prompt before launching for each file.
  • merge.conflictStyle=zdiff3Config that adds the common ancestor into the conflict markers. Hugely clarifying.

Examples

Set VS Code as your merge tool, then resolve the current conflict in it.

example
git config --global merge.tool vscode
git config --global mergetool.vscode.cmd 'code --wait $MERGED'
git mergetool

Show what the code originally looked like inside every conflict block.

example
git config --global merge.conflictStyle zdiff3
git rerereSafe

Remember how you resolved a conflict and replay it automatically next time.

Short for 'reuse recorded resolution'. Once enabled, Git records the way you settled each conflict and silently reapplies the same fix if the identical conflict shows up again. It pays for itself the moment you rebase a long-lived branch repeatedly and keep hitting the same three conflicts.

Syntax

git rerere
git config --global rerere.enabled true
git rerere status
git rerere forget <path>

Common options

  • statusShow which paths have recorded resolutions in play.
  • diffShow what the recorded resolution changes.
  • forget <path>Discard a recorded resolution you got wrong.

Examples

Turn it on once, benefit forever.

example
git config --global rerere.enabled true

Drop a bad recorded resolution so you can redo it.

example
git rerere forget src/app.ts
git remoteSafe

Manage the named URLs your repository syncs with.

A remote is just a nickname for a URL. `origin` is the conventional name for where you cloned from, and `upstream` is the convention for the original repo when you're working from a fork. Renaming or re-pointing a remote is a local-only operation and affects nothing on the server.

Syntax

git remote
git remote -v
git remote add <name> <url>
git remote set-url origin <url>

Common options

  • -vShow remote names alongside their fetch and push URLs.
  • add <name> <url>Register a new remote.
  • set-url <name> <url>Point an existing remote somewhere else.
  • rename <old> <new>Rename a remote.
  • remove <name>Forget a remote.
  • prune <name>Delete local references to branches that no longer exist on the server.
  • show <name>Full detail: tracked branches, what's stale, what would be pushed.

Examples

Check exactly which server you're pushing to.

example
git remote -v

Track the original project after forking it.

example
git remote add upstream https://github.com/original/repo.git

Switch a repo from HTTPS to SSH.

example
git remote set-url origin git@github.com:user/repo.git
git fetchSafe

Download new commits from the remote without changing any of your files.

Fetch is the completely safe way to see what's happened on the server. It updates your remote-tracking branches (like `origin/main`) but leaves your own branches and working directory untouched, so you can inspect incoming changes before deciding to merge them. Every `git pull` is really a fetch followed by a merge.

Syntax

git fetch
git fetch
git fetch origin <branch>
git fetch --all --prune

Common options

  • --allFetch from every configured remote.
  • --pruneRemove tracking refs for branches deleted on the server.
  • --tagsAlso fetch tags.
  • --unshallowConvert a shallow clone into a full one.
  • --dry-runShow what would be fetched without doing it.

Examples

Refresh everything from all remotes and clear out deleted branches.

example
git fetch --all --prune

See exactly which commits are waiting for you before you pull.

example
git fetch origin
git log HEAD..origin/main --oneline
git pullCaution

Fetch from the remote and immediately integrate the changes into your branch.

Pull is `git fetch` plus `git merge` (or `git rebase` with `--rebase`). Because it changes your working branch automatically, it's the command most likely to drop you into an unexpected conflict. Many teams set `pull.rebase true` to keep history linear and avoid a merge commit every time someone syncs.

Syntax

git pull
git pull
git pull --rebase
git pull origin <branch>

Common options

  • --rebaseReplay your local commits on top of the fetched ones instead of merging.
  • --ff-onlyRefuse to pull if it would require a merge - a safe default.
  • --no-rebaseForce the merge behaviour for this pull.
  • --autostashStash local changes, pull, then reapply them.

Examples

Bring in the latest main and replay your work on top of it.

example
git pull --rebase origin main

Set sane defaults once so plain git pull never surprises you.

example
git config --global pull.rebase true
git config --global pull.ff only
git pushCaution

Upload your commits to the remote repository.

Push sends commits the server doesn't have and moves the remote branch pointer forward. Git refuses a push that would discard commits on the server, which is the safety net you should almost never override. When you genuinely must rewrite pushed history, use `--force-with-lease` rather than `--force` - it aborts if someone else pushed in the meantime.

Syntax

git push
git push
git push -u origin <branch>
git push --force-with-lease

Common options

  • -u, --set-upstreamLink the local branch to the remote one so plain git push works afterwards.
  • --force-with-leaseForce push, but abort if the remote has commits you haven't seen. Always prefer this over --force.
  • --forceOverwrite the remote branch unconditionally. Can destroy a colleague's work.
  • --tags / --follow-tagsPush tags too; --follow-tags sends only annotated tags reachable from what you're pushing.
  • --delete <branch>Delete a branch on the server.
  • --dry-runShow what would be pushed.

Examples

Publish a new branch and set it to track origin.

example
git push -u origin feature/save-system

Update a rewritten branch safely, refusing if someone else pushed first.

example
git push --force-with-lease

Delete a remote branch.

example
git push origin --delete old-feature
git ls-remoteSafe

List a remote's branches and tags without cloning it.

Queries the server directly and prints every ref with its hash, using no local repository at all. It's the quickest way to check whether a tag exists, whether your credentials work, or what a repo's default branch is - and it's a staple of CI scripts that need to test a URL before committing to a full clone.

Syntax

git ls-remote
git ls-remote <url>
git ls-remote --heads origin
git ls-remote --tags origin

Common options

  • --headsBranches only.
  • --tagsTags only.
  • --symrefAlso show what HEAD points to - i.e. the default branch.
  • --exit-codeExit non-zero when nothing matches. Handy in scripts.

Examples

Find a repository's default branch without cloning it.

example
git ls-remote --symref https://github.com/user/repo.git HEAD

Check which release tags exist on the server.

example
git ls-remote --tags origin | tail -5
git logSafe

Browse commit history with as much or as little detail as you want.

Log is the main window into your project's past, and its filters are what make it powerful: search by author, date range, file path, or even the content of the change itself. `-S` (the 'pickaxe') finds every commit that added or removed a given string, which is how you track down when a line of code appeared or vanished.

Syntax

git log
git log
git log --oneline --graph --all
git log -- <path>
git log -S <string>

Common options

  • --onelineOne compact line per commit.
  • --graphDraw the branch and merge structure as ASCII art.
  • -pShow the full diff introduced by each commit.
  • -S <string>Pickaxe: find commits where the number of occurrences of a string changed.
  • -G <regex>Like -S but matches the diff text against a regular expression.
  • --follow -- <file>Track a file's history across renames.
  • --all --full-history -- <path>Search every branch, including for files that have since been deleted.
  • --since / --untilLimit by date, e.g. --since='2 weeks ago'.
  • --author=<name>Filter by author.
  • --first-parentFollow only the mainline, hiding commits merged in from branches.
  • --format=<fmt>Custom output, e.g. --format='%h %an %ar %s'.

Examples

The classic visual overview of every branch.

example
git log --oneline --graph --all --decorate

Find every commit that added or removed a mention of AudioManager.

example
git log -S "AudioManager" --oneline

Find a file's history even if it was deleted long ago.

example
git log --all --full-history -- "**/PlayerController.cs"

See only the merges into main - a clean release-level history.

example
git log --first-parent main --oneline
git diffSafe

Show exactly what changed - between your files, the index, commits or branches.

With no arguments, diff shows unstaged changes; with `--staged` it shows what's about to be committed. The two-dot form compares endpoints, while the three-dot form compares against the common ancestor, which is usually what you want when reviewing a branch. `--word-diff` is invaluable for prose and config files.

Syntax

git diff
git diff
git diff --staged
git diff <branch1>..<branch2>
git diff <commit> -- <file>

Common options

  • --staged, --cachedCompare the index against the last commit - a preview of your next commit.
  • --statSummarise changes per file instead of printing the full diff.
  • --word-diffHighlight changes word by word rather than line by line.
  • main...featureThree-dot form: everything the branch added since it diverged.
  • --name-only / --name-statusJust the changed file names, optionally with their status letters.
  • -wIgnore whitespace changes.
  • --diff-filter=<letters>Limit by change type: A added, M modified, D deleted, R renamed.

Examples

Review precisely what you're about to commit.

example
git diff --staged

Summarise everything a feature branch adds relative to main.

example
git diff main...feature/save-system --stat

See how one file changed over the last three commits.

example
git diff HEAD~3 -- src/app.ts
git showSafe

Display a single commit, tag or file-at-a-commit in full.

Show prints the metadata and complete diff for any object you name. Its most useful trick is the `<commit>:<path>` syntax, which dumps the exact contents of a file as it existed at that commit without checking anything out - perfect for peeking at an old version before deciding to restore it.

Syntax

git show
git show <commit>
git show <commit>:<path>
git show --stat <commit>

Common options

  • --statShow the summary of changed files rather than the whole diff.
  • --name-onlyList only the affected file names.
  • <commit>:<path>Print a file exactly as it was at that commit.
  • -sSuppress the diff and show only the commit message.

Examples

Print an old version of a file without changing your working directory.

example
git show HEAD~2:src/config.json

Save a commit's full diff to a file.

example
git show a1b2c3d > patch.diff
git blameSafe

Show which commit and author last touched every line of a file.

Blame annotates each line with the commit, author and date that last modified it, which is how you find the context behind a baffling piece of code. Use `-w` to ignore whitespace-only changes and `-C` to follow lines that moved between files, otherwise a single reformat can make it look like one person wrote everything.

Syntax

git blame
git blame <file>
git blame -L <start>,<end> <file>

Common options

  • -L <start>,<end>Limit to a line range.
  • -wIgnore whitespace changes.
  • -CDetect lines moved or copied from other files.
  • --ignore-rev <rev>Skip a known noisy commit, like a project-wide reformat.
  • --ignore-revs-file <file>Skip every commit listed in a file (conventionally .git-blame-ignore-revs).

Examples

Find who really wrote lines 40-60, ignoring reformatting noise.

example
git blame -w -C -L 40,60 src/PlayerController.cs

Permanently hide a formatting commit from every future blame.

example
echo "a1b2c3d4e5f6  # repo-wide prettier run" >> .git-blame-ignore-revs
git config blame.ignoreRevsFile .git-blame-ignore-revs
git bisectSafe

Binary-search your history to find the exact commit that introduced a bug.

You tell Git one commit where things work and one where they don't; it checks out the midpoint and asks you to test. Each answer halves the search space, so even a thousand commits are narrowed down in about ten steps. With `git bisect run` you hand it a script and it finds the culprit completely unattended.

Syntax

git bisect
git bisect start
git bisect bad
git bisect good <commit>
git bisect reset

Common options

  • startBegin a bisect session.
  • bad / goodMark the current checkout as broken or working.
  • run <cmd>Automate: a non-zero exit means bad, zero means good.
  • resetEnd the session and return to where you were.
  • skipSkip a commit that can't be tested (e.g. it doesn't build).
  • log / replaySave and restore a bisect session.

Examples

Manually narrow down which commit between v1.2.0 and now broke things.

example
git bisect start
git bisect bad
git bisect good v1.2.0
# test, then mark each step:
git bisect good   # or: git bisect bad
git bisect reset

Fully automated hunt - Git runs your test suite at each step and names the guilty commit.

example
git bisect start HEAD v1.2.0
git bisect run npm test
git grepSafe

Search the contents of tracked files - at any point in history.

Much faster than a normal recursive grep because it only looks at tracked files and uses Git's index. Its real superpower is searching an arbitrary commit or tag, letting you ask 'was this function present in v1.0?' without checking anything out.

Syntax

git grep
git grep <pattern>
git grep <pattern> <commit>
git grep -n <pattern>

Common options

  • -nShow line numbers.
  • -iCase-insensitive.
  • -lList only the matching file names.
  • -C <n>Show n lines of context.
  • --all-matchRequire all specified patterns to match.

Examples

Find every TODO in tracked files with line numbers.

example
git grep -n "TODO"

Check whether a function existed at a given tag.

example
git grep "loadSave" v1.2.0

Search every commit in the entire history for a leaked key.

example
git grep -n "apiKey" $(git rev-list --all)
git shortlogSafe

Summarise commits grouped by author - the built-in contribution report.

Groups the log by author and prints their commit subjects, which makes it the fastest way to generate release notes or see who worked on what. `-sn` collapses it to a sorted count per person, which is the form almost everyone actually uses.

Syntax

git shortlog
git shortlog
git shortlog -sn
git shortlog -sn <range>

Common options

  • -sSummary: just the commit count per author.
  • -nSort by number of commits.
  • -eShow email addresses.
  • --no-mergesExclude merge commits.

Examples

Contributor leaderboard with emails, ignoring merges.

example
git shortlog -sne --no-merges

Draft release notes grouped by author, between two tags.

example
git shortlog v1.0.0..v1.1.0
git difftoolSafe

View diffs in a graphical diff viewer instead of the terminal.

Runs the same comparisons as `git diff` but opens each file in a configured GUI. Once set up it's the fastest way to review a large change, and unlike `git diff` it handles a side-by-side view of long files comfortably.

Syntax

git difftool
git difftool
git difftool <commit>..<commit>
git difftool --dir-diff

Common options

  • --dir-diff, -dOpen the whole changeset at once instead of file by file. The killer feature.
  • -yDon't prompt before launching.
  • --tool=<name>Pick a tool for this run.

Examples

Review an entire branch in VS Code's diff viewer in one go.

example
git config --global diff.tool vscode
git config --global difftool.vscode.cmd 'code --wait --diff $LOCAL $REMOTE'
git difftool -d main...HEAD
git range-diffSafe

Diff two versions of a branch - what changed between rebases.

Compares two ranges of commits and shows how each commit differs from its counterpart, which is exactly what you need when a reviewer asks 'what did you change since my last review?' after you rebased. Without it you're stuck comparing hashes that all changed for unrelated reasons.

Syntax

git range-diff
git range-diff <base>..<old> <base>..<new>
git range-diff <old>...<new>

Common options

  • --creation-factor=<n>Tune how eagerly it pairs up commits.
  • --no-dual-colorSimpler colouring.

Examples

See exactly how a branch changed across a force-push.

example
git range-diff main@{1}...main

Compare two revisions of the same feature branch, commit by commit.

example
git range-diff main..feature-v1 main..feature-v2
git cherrySafe

Find which of your commits haven't been applied upstream yet.

Compares two branches by the *content* of their changes rather than by hash, so a commit that was cherry-picked or rebased upstream is correctly recognised as already applied. It marks each commit with `+` (not upstream) or `-` (already there), which is the honest answer to 'has my patch landed?'.

Syntax

git cherry
git cherry <upstream>
git cherry -v <upstream> <head>

Common options

  • -vInclude the commit subject line.
  • <upstream> <head>Compare an explicit pair rather than the current branch.

Examples

List your branch's commits and whether each already exists on main.

example
git cherry -v main

Show only the work that genuinely hasn't landed upstream.

example
git cherry -v origin/main | grep '^+'
git resetDestructive

Move the current branch pointer, optionally rewriting the index and your files.

Reset has three modes and understanding them is most of understanding Git. `--soft` moves only the branch pointer, leaving everything staged. `--mixed` (the default) also clears the index but keeps your files. `--hard` additionally overwrites your working directory, permanently destroying uncommitted work - this is the single most dangerous everyday Git command.

Syntax

git reset
git reset --soft HEAD~1
git reset HEAD~1
git reset --hard HEAD~1
git reset <file>

Common options

  • --softMove the branch only. Changes stay staged, ready to recommit.
  • --mixedDefault. Move the branch and unstage, but keep your file edits.
  • --hardMove the branch and wipe the index and working directory. Destroys uncommitted work.
  • --keepLike --hard but refuses if it would overwrite local changes. A far safer default.
  • --mergeReset but try to preserve uncommitted changes that don't conflict.
  • <file>With a path, unstages that file rather than moving any branch.

Examples

Undo the last commit but keep every change staged - the safest way to redo a commit.

example
git reset --soft HEAD~1

Undo the last commit and unstage its changes, leaving your files as they are.

example
git reset HEAD~1

Like --hard, but aborts instead of silently destroying uncommitted work.

example
git reset --keep HEAD~1
git revertSafe

Create a new commit that undoes an earlier one, leaving history intact.

Revert is the safe way to undo something you've already pushed, because it adds history rather than rewriting it - nobody else has to do anything special. To revert a merge you must say which parent to treat as the mainline with `-m 1`. Use revert on shared branches and reset on private ones.

Syntax

git revert
git revert <commit>
git revert -m 1 <merge-commit>
git revert --no-commit <a>..<b>

Common options

  • -m <parent>Required for merge commits: which parent is the mainline (usually 1).
  • --no-commit, -nStage the reversal without committing, so you can batch several.
  • --continue / --abort / --skipResume, cancel, or skip after a conflict.

Examples

Safely undo a pushed commit by adding an inverse commit.

example
git revert a1b2c3d

Undo a merge commit, keeping the first parent as the mainline.

example
git revert -m 1 a1b2c3d

Undo a range of commits as one clean revert.

example
git revert --no-commit HEAD~3..HEAD
git commit -m "Revert the last three commits"
git cleanDestructive

Delete untracked files and directories from your working tree.

Clean removes files Git isn't tracking - build output, stray downloads, generated assets. Because those files were never in Git, deleting them is completely irreversible: no reflog, no object database, nothing. Always run it with `-n` first to see the list, and remember `-x` also removes ignored files like your `.env`.

Syntax

git clean
git clean -n
git clean -fd
git clean -fdx

Common options

  • -n, --dry-runList what would be deleted without deleting it. Always start here.
  • -f, --forceActually delete. Required, because Git refuses otherwise.
  • -dAlso remove untracked directories.
  • -xAlso remove ignored files - including .env files and local configs.
  • -XRemove ONLY ignored files, keeping other untracked ones.
  • -iInteractive mode: choose what to delete.

Examples

Preview exactly which untracked files and folders would be removed.

example
git clean -nd

Delete untracked files and directories, keeping ignored ones.

example
git clean -fd

Wipe build output and other ignored files while keeping new source files.

example
git clean -fX
git stashCaution

Park uncommitted work temporarily so you can do something else.

Stashing saves your modified tracked files onto a stack and returns your working directory to a clean state. Crucially, stashes are stored as real commit objects, which is why a stash you dropped by accident can usually still be dug out with `git fsck`. By default untracked files are left behind - use `-u` to include them.

Syntax

git stash
git stash
git stash push -m "message"
git stash pop
git stash list

Common options

  • push -m <msg>Stash with a description so you can tell entries apart later.
  • -u, --include-untrackedAlso stash untracked files.
  • -a, --allAlso stash ignored files.
  • -k, --keep-indexLeave already-staged changes in place.
  • popApply the newest stash and remove it from the stack.
  • applyApply a stash but keep it on the stack.
  • drop / clearDelete one stash, or all of them.
  • show -p stash@{0}View a stash's full diff before applying it.
  • branch <name>Create a branch from a stash - the clean fix for a stash that won't apply.

Examples

Stash everything including new files, with a label.

example
git stash push -u -m "half-done inventory UI"

Inspect a specific stash before restoring it.

example
git stash list
git stash show -p stash@{1}
git stash pop stash@{1}

Turn a stash that conflicts with your current branch into its own branch.

example
git stash branch recovered-work stash@{0}
git commit --amendCaution

Replace the most recent commit instead of stacking another one on top.

Amend combines whatever is currently staged with the previous commit and rewrites it, producing a new hash. It's the standard fix for a typo in a message or a file you forgot to include. Because the hash changes, amending something already pushed means you'll need `--force-with-lease` and a heads-up to your team.

Syntax

git commit --amend
git commit --amend -m "new message"
git commit --amend --no-edit
git commit --amend --author="Name <email>"

Common options

  • --no-editKeep the existing message - perfect for slipping in a forgotten file.
  • -m <msg>Replace the message.
  • --author=<author>Fix a wrong author on the last commit.
  • --reset-authorSet author to you and refresh the timestamp.
  • --date=<date>Override the author date.

Examples

Add a forgotten file to the last commit without changing its message.

example
git add forgotten-file.ts
git commit --amend --no-edit

Rewrite a bad commit message.

example
git commit --amend -m "Fix: clamp health to zero"
git rebase -iDestructive

Reorder, squash, split, reword or drop your recent commits.

Interactive rebase opens an editor listing your commits oldest-first, each prefixed with an action you can change: `pick`, `reword`, `edit`, `squash`, `fixup` or `drop`. Reordering the lines reorders the commits. It's the tool that turns a messy sequence of 'wip' commits into a clean, reviewable story before you open a pull request.

Syntax

git rebase -i
git rebase -i HEAD~<n>
git rebase -i <commit>
git rebase -i --root

Common options

  • pickKeep the commit as-is.
  • rewordKeep the changes, edit the message.
  • editStop at this commit so you can amend or split it.
  • squashMerge into the previous commit and combine messages.
  • fixupMerge into the previous commit and discard this message.
  • dropDelete the commit entirely.
  • exec <cmd>Run a command after that commit - e.g. run tests at every step.
  • --autosquashAutomatically order commits created with git commit --fixup.
  • --rootInclude the very first commit in the rebase.

Examples

Clean up the last five commits before pushing.

example
git rebase -i HEAD~5

Replay five commits, running the test suite after each one to find where it broke.

example
git rebase -i --exec 'npm test' HEAD~5
git filter-repoDestructive

Rewrite an entire repository's history - the supported way to purge a leaked secret or a huge file.

An external tool (install with `pip install git-filter-repo`) that officially replaces the slow and error-prone `git filter-branch`. It can strip a path from every commit that ever contained it, rewrite emails, or shrink a bloated repo. It rewrites every affected commit hash, so everyone must re-clone afterwards - and if you removed a secret, you must still rotate it, because the old commits may already be cached on the server.

Syntax

git filter-repo
git filter-repo --path <file> --invert-paths
git filter-repo --replace-text <file>

Common options

  • --path <p> --invert-pathsRemove that path from all of history.
  • --path <p>Keep ONLY that path - how you split a subdirectory into its own repo.
  • --replace-text <file>Replace matching strings everywhere, e.g. redact an API key.
  • --strip-blobs-bigger-than <size>Drop every blob over a size threshold, e.g. 50M.
  • --mailmap <file>Rewrite author and committer identities.
  • --forceRun against a repo that isn't a fresh clone.

Examples

Erase a committed .env from every commit, then republish. Rotate the leaked keys regardless.

example
pip install git-filter-repo
git filter-repo --path .env --invert-paths
git push --force --all

Extract one subdirectory into a standalone repository, keeping its history.

example
git filter-repo --path packages/ui/ --path-rename packages/ui/:
git replaceCaution

Swap one object for another without rewriting a single hash.

Creates a ref telling Git to substitute object B whenever object A is requested, so you can graft histories together or correct an ancient commit without changing any hashes. Nothing is rewritten and existing clones stay valid - but replacements are local until you explicitly push refs/replace, which makes them a specialist tool rather than an everyday one.

Syntax

git replace
git replace <object> <replacement>
git replace -l
git replace -d <object>

Common options

  • -l, --listList active replacements.
  • -d, --deleteRemove a replacement.
  • --graft <commit> <parent>Rewrite a commit's parents - how you stitch a truncated history back on.
  • --no-replace-objectsGlobal flag to ignore replacements for one command.

Examples

Reattach an archived history to a repo that was truncated by a shallow clone.

example
git replace --graft <oldest-commit> <tip-of-archived-history>
git filter-repo --force   # make it permanent
git reflogSafe

The undo history for everything - the single most important recovery command.

The reflog records every position HEAD and your branches have pointed to, including states no branch references any more. That means a commit destroyed by `reset --hard`, a rebase that mangled your work, or a branch you deleted are all still listed here for about 90 days by default. If you have lost commits, start here before trying anything else.

Syntax

git reflog
git reflog
git reflog show <branch>
git reset --hard HEAD@{n}

Common options

  • show <ref>Show the reflog for a specific branch or remote-tracking ref.
  • --date=isoPrint real timestamps rather than relative ones.
  • HEAD@{n}Refer to where HEAD was n moves ago.
  • HEAD@{2.days.ago}Refer to where HEAD was at a point in time.
  • expirePrune old entries (this is what eventually makes recovery impossible).

Examples

List recent HEAD positions - find the hash from just before the disaster.

example
git reflog

Undo a bad reset by jumping back to the previous HEAD position.

example
git reflog
git reset --hard HEAD@{1}

See what the remote branch pointed at before someone force-pushed.

example
git reflog show origin/main
git fsckSafe

Scan the object database for orphaned commits and blobs the reflog no longer lists.

When even the reflog can't help - a dropped stash, a file that was staged but never committed, work lost in a botched rebase - fsck checks every object in `.git/objects` and reports the ones nothing points to. Dangling blobs are file contents, dangling commits are whole snapshots. This is the deepest recovery layer Git has, and it also detects genuine repository corruption.

Syntax

git fsck
git fsck --lost-found
git fsck --unreachable
git fsck --dangling --no-reflogs

Common options

  • --lost-foundWrite recoverable objects into .git/lost-found for easy browsing.
  • --unreachableList objects no reference can reach.
  • --danglingList objects nothing at all points to.
  • --no-reflogsTreat reflog entries as not counting, exposing more candidates.
  • --fullCheck packed objects and alternates too.

Examples

Recover orphaned objects into .git/lost-found/ so you can inspect them.

example
git fsck --lost-found

List orphaned commits - how you find a stash you dropped.

example
git fsck --unreachable | grep commit
git cat-fileSafe

Print the raw contents or type of any object by its hash.

Once fsck hands you a list of dangling hashes, cat-file is how you look inside them to work out which one you actually want. `-t` tells you whether a hash is a blob, tree, commit or tag; `-p` pretty-prints its contents. Redirect the output to a file and your lost work is back.

Syntax

git cat-file
git cat-file -t <hash>
git cat-file -p <hash>
git cat-file -p <hash> > file.txt

Common options

  • -tPrint the object's type.
  • -pPretty-print the object's contents.
  • -sPrint the object's size in bytes.
  • --batch-checkRead many hashes on stdin and report type and size - the basis of every 'find big files' script.

Examples

Dump the contents of a recovered blob to the terminal.

example
git cat-file -p a1b2c3d

Write a recovered blob straight back to disk.

example
git cat-file -p a1b2c3d > recovered-file.ts
git tagSafe

Mark a specific commit as a release.

Tags are permanent labels on a commit, unlike branches which move. Prefer annotated tags (`-a`), which are real objects carrying an author, date and message, over lightweight ones. Tags are not pushed by default - you have to send them explicitly, which is a common source of 'why isn't my release showing up'.

Syntax

git tag
git tag -a v1.0.0 -m "Release 1.0.0"
git tag
git push origin v1.0.0

Common options

  • -a <name> -m <msg>Create an annotated tag with a message.
  • -l <pattern>List tags matching a pattern.
  • -d <name>Delete a local tag.
  • -fMove an existing tag to a new commit.
  • -sCreate a GPG-signed tag.
  • --sort=-v:refnameList tags in proper version order, newest first.

Examples

Create an annotated release tag and publish it.

example
git tag -a v1.0.0 -m "First public release"
git push origin v1.0.0

Show the five most recent version tags.

example
git tag --sort=-v:refname | head -5

Remove a tag locally and on the server.

example
git tag -d v1.0.0
git push origin --delete v1.0.0
git describeSafe

Generate a human-readable version string from the nearest tag.

Produces something like `v1.2.0-14-ga1b2c3d`, meaning fourteen commits after tag v1.2.0 at commit a1b2c3d. It's the standard way to stamp a build with a meaningful version number automatically, and it's used constantly in CI pipelines and game build numbers.

Syntax

git describe
git describe
git describe --tags --always --dirty

Common options

  • --tagsConsider lightweight tags too, not just annotated ones.
  • --alwaysFall back to a bare commit hash if no tag exists.
  • --dirtyAppend -dirty if the working tree has uncommitted changes.
  • --abbrev=<n>Control how many hash characters are shown.

Examples

Get a build-stamp version string that always produces something.

example
git describe --tags --always --dirty
git notesSafe

Attach extra information to a commit without changing its hash.

Notes let you annotate a commit after the fact - review links, CI results, release metadata - and the commit's hash never changes, so nothing is rewritten. The catch is that notes live in their own ref and aren't fetched or pushed by default, which is why they're powerful in automation and almost invisible in day-to-day use.

Syntax

git notes
git notes add -m "note" <commit>
git notes show <commit>
git log --show-notes

Common options

  • add -m <msg>Attach a note.
  • append -m <msg>Add to an existing note.
  • show <commit>Print a commit's note.
  • remove <commit>Delete a note.
  • --ref <name>Use a separate namespace, e.g. --ref=ci for build results.

Examples

Annotate a commit and see the note in the log.

example
git notes add -m "Reviewed by: Alex. Ship blocker resolved." a1b2c3d
git log --show-notes

Notes need explicit push and fetch refspecs to be shared.

example
git push origin refs/notes/*
git fetch origin 'refs/notes/*:refs/notes/*'
git format-patchSafe

Export commits as .patch files you can email or archive.

Turns each commit in a range into a standalone file containing the diff plus the full author, date and message. It's how the Linux kernel and most mailing-list projects still accept contributions, and it's the cleanest way to move work between two repositories that share no remote.

Syntax

git format-patch
git format-patch <base>
git format-patch -1 <commit>
git format-patch main..feature

Common options

  • -<n>Export the last n commits, e.g. -3.
  • --stdoutWrite one combined mbox to stdout instead of numbered files.
  • -o <dir>Write the files into a directory.
  • --cover-letterGenerate a summary letter for the series.
  • -v2Mark this as version 2 of a patch series.

Examples

Export your last three commits as numbered .patch files.

example
git format-patch -3 -o /tmp/patches

Bundle a whole branch into one file to send elsewhere.

example
git format-patch main..feature --stdout > feature.mbox
git amCaution

Apply .patch files as real commits, preserving author and message.

The counterpart to format-patch: it replays each patch as a commit with its original author, date and message intact. This is the difference between `git am` and `git apply` - apply only changes files, while am reconstructs history. If a patch doesn't apply cleanly you get a normal conflict to resolve.

Syntax

git am
git am <patch-file>
git am --abort
git am --continue

Common options

  • -3Fall back to a three-way merge when the patch doesn't apply cleanly. Almost always worth adding.
  • --abortCancel and restore the original branch.
  • --continue / --skipProceed after resolving a conflict, or skip this patch.
  • --signoffAdd a Signed-off-by line.

Examples

Apply a whole patch series as commits, with three-way fallback.

example
git am -3 /tmp/patches/*.patch

Back out of a patch series that won't apply.

example
git am --abort
git applyCaution

Apply a diff to your working tree without creating a commit.

Applies patch text as plain file changes, leaving you to stage and commit however you like. Because it makes no commit and records no authorship, it's the right choice for applying a diff someone pasted at you, or for testing whether a patch still applies with `--check`.

Syntax

git apply
git apply <patch>
git apply --check <patch>
git apply --3way <patch>

Common options

  • --checkTest whether the patch would apply, changing nothing.
  • --3way, -3Use a three-way merge on conflict instead of failing outright.
  • --reverse, -RUn-apply a patch.
  • --statSummarise what the patch would change.
  • --exclude=<path>Skip parts of the patch.

Examples

Verify a patch applies, then apply it.

example
git apply --check fix.patch && git apply fix.patch

Park work in a file instead of a stash, then bring it back.

example
git diff > /tmp/wip.patch
git checkout .
# ... later ...
git apply /tmp/wip.patch
git send-emailSafe

Email a patch series directly from Git.

Sends the output of format-patch as properly threaded plain-text email, which is still how the kernel, Git itself and many long-running open-source projects accept contributions. It handles the threading and In-Reply-To headers that make a patch series readable in a mail client.

Syntax

git send-email
git send-email <patch-dir>
git send-email --to=<addr> HEAD~3..HEAD

Common options

  • --to / --ccRecipients.
  • --annotateOpen each message in your editor before sending.
  • --dry-runShow what would be sent.
  • --composeWrite a cover letter interactively.

Examples

Send a reviewed patch series to a maintainer.

example
git send-email --to=maintainer@project.org --annotate /tmp/patches/*.patch
git request-pullSafe

Generate a pull request summary for a maintainer, without a hosting platform.

Produces the plain-text summary that GitHub's pull request UI replaced: what changed, by whom, and where to fetch it from. It predates and outlives any particular forge, and it's still the standard way to propose a merge on a mailing list.

Syntax

git request-pull
git request-pull <start> <url> [<end>]

Common options

  • <start>The commit the maintainer already has.
  • <url>Where they should fetch from.
  • <end>Your branch or tag; defaults to HEAD.

Examples

Produce a summary asking a maintainer to pull your branch.

example
git request-pull v1.2.0 https://github.com/you/repo.git feature/save-system
git bundleSafe

Pack a repository (or part of it) into one file you can clone from.

Creates a single file containing real Git objects that you can clone or fetch from exactly like a remote. It's the answer to moving a repository across an air gap, onto a USB stick, or through a system that only accepts file attachments - and unlike a zip of the folder, it preserves everything Git needs.

Syntax

git bundle
git bundle create <file> <refs>
git clone <file> <dir>
git bundle verify <file>

Common options

  • create <file> --allBundle every ref.
  • create <file> <since>..<until>Bundle only a range - an incremental update.
  • verify <file>Check a bundle is valid and see what it requires.
  • list-heads <file>Show which refs a bundle contains.

Examples

Move a full repository, history included, as one file.

example
git bundle create repo.bundle --all
# copy repo.bundle to the other machine
git clone repo.bundle myrepo

Create a small incremental bundle with just the last ten commits.

example
git bundle create update.bundle main~10..main
git archiveSafe

Export a clean zip or tarball of your project at any commit.

Produces an archive of the tracked files at a given commit, with no `.git` directory and none of your untracked junk. It's the correct way to build a release artifact or hand someone a snapshot, and it respects `export-ignore` rules in `.gitattributes` so you can exclude test fixtures from shipped archives.

Syntax

git archive
git archive --format=zip -o <file> <commit>
git archive HEAD | tar -x -C <dir>

Common options

  • --format=zip|tarOutput format.
  • -o <file>Write to a file.
  • --prefix=<dir>/Nest everything under a directory inside the archive.
  • <commit>:<path>Archive only a subdirectory.

Examples

Build a clean release zip from a tag.

example
git archive --format=zip --prefix=myapp-1.0/ -o myapp-1.0.zip v1.0.0

Extract just one directory at HEAD somewhere else.

example
git archive HEAD:src | tar -x -C /tmp/src-snapshot
git rev-parseSafe

Turn any revision expression into a concrete commit hash.

The translator between how humans name commits (`HEAD~3`, `main@{yesterday}`, `v1.0^{commit}`) and the 40-character hashes Git actually stores. It's the single most-used command inside shell scripts and hooks, because it also answers structural questions like 'where is the repo root?' and 'am I even inside a repository?'.

Syntax

git rev-parse
git rev-parse HEAD
git rev-parse --short HEAD
git rev-parse --show-toplevel

Common options

  • --short[=n]Abbreviated hash.
  • --abbrev-ref HEADThe current branch name.
  • --show-toplevelAbsolute path to the repository root.
  • --git-dirPath to the .git directory.
  • --is-inside-work-treePrints true/false - the standard 'is this a repo?' check.
  • --verifyFail if the revision doesn't resolve.

Examples

Print the current branch name - the basis of every shell prompt.

example
git rev-parse --abbrev-ref HEAD

Jump to the repository root from any subdirectory.

example
cd "$(git rev-parse --show-toplevel)"

Get a short hash to stamp into a build.

example
git rev-parse --short HEAD
git rev-listSafe

List commit hashes matching a range or filter - the engine behind git log.

Where `git log` formats commits for humans, rev-list emits raw hashes for scripts. It powers most repository analysis: counting commits, walking every object in history, or finding what one branch has that another doesn't. Almost every 'find the biggest files in my repo' recipe starts here.

Syntax

git rev-list
git rev-list HEAD
git rev-list --count HEAD
git rev-list --all --objects

Common options

  • --countJust the number of commits.
  • --allStart from every ref.
  • --objectsList every object, not just commits - blobs and trees included.
  • --left-right <a>...<b>Show which side of a divergence each commit is on.
  • --no-mergesExclude merge commits.

Examples

Total number of commits - a handy monotonic build number.

example
git rev-list --count HEAD

How many commits each side is ahead by.

example
git rev-list --left-right --count main...feature

The canonical recipe for finding the ten largest files in your entire history.

example
git rev-list --objects --all |
  git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' |
  awk '/^blob/ {print $3, $4}' | sort -rn | head -10
git ls-filesSafe

List files in the index, with precise filters for state.

Reports exactly which paths Git is tracking, and can filter by state - modified, deleted, ignored, untracked, or in conflict. It's far more reliable than parsing `git status` in a script, and `--unmerged` is the cleanest way to enumerate conflicted files during a merge.

Syntax

git ls-files
git ls-files
git ls-files --others --ignored --exclude-standard
git ls-files -u

Common options

  • -c, --cachedTracked files (the default).
  • -o, --othersUntracked files.
  • -i --exclude-standardCombined with -o, lists ignored files.
  • -u, --unmergedFiles currently in conflict.
  • -d, --deletedTracked files missing from disk.
  • -s, --stageShow mode, hash and stage number.

Examples

List every file .gitignore is actually excluding.

example
git ls-files --others --ignored --exclude-standard

Enumerate conflicted files during a merge.

example
git ls-files -u | cut -f2 | sort -u

Count tracked files.

example
git ls-files | wc -l
git ls-treeSafe

List the contents of a tree object at any commit.

Shows what files and directories existed at a given commit, along with their modes and blob hashes, without checking anything out. Use it to inspect an old directory listing, to spot a file-mode change, or to pull the hash of a specific historical file so you can extract it with cat-file.

Syntax

git ls-tree
git ls-tree <commit>
git ls-tree -r <commit>
git ls-tree <commit> <path>

Common options

  • -rRecurse into subdirectories.
  • --name-onlyJust the paths.
  • -lInclude object sizes.
  • -dShow only directories.

Examples

List every file that existed at the v1.0.0 tag.

example
git ls-tree -r --name-only v1.0.0

Find the five biggest files in the current commit.

example
git ls-tree -r -l HEAD | sort -k4 -n | tail -5
git hash-objectSafe

Compute the Git hash of a file - and optionally store it as an object.

Shows you exactly how Git identifies content: hash a file and you get the same 40-character id Git would use. With `-w` it writes the object into the database, which is the low-level building block behind `git add`. In practice its best use is forensic - hashing a local file to check whether that exact content already exists somewhere in your history.

Syntax

git hash-object
git hash-object <file>
git hash-object -w <file>
git hash-object --stdin

Common options

  • -wWrite the object into .git/objects, not just compute the hash.
  • --stdinRead the content from standard input.
  • -t <type>Treat the input as blob, tree, commit or tag.

Examples

Compute the object id of a file's current contents.

example
git hash-object src/config.json

Check whether a local file's exact content already exists as an object.

example
H=$(git hash-object old-copy.cs)
git cat-file -t "$H" 2>/dev/null && echo "this exact content IS in the repo"
git for-each-refSafe

Query and format every branch, tag and ref in the repository.

A scriptable, precisely formattable listing of every reference, with sorting and filtering that `git branch` and `git tag` only partly expose. It's how you build reports like 'every branch, its author and how stale it is' in a single command.

Syntax

git for-each-ref
git for-each-ref
git for-each-ref --format='<fmt>' <pattern>

Common options

  • --sort=<field>Sort by committerdate, refname, etc. Prefix with - to reverse.
  • --format=<fmt>Fields like %(refname:short), %(authorname), %(committerdate:relative).
  • --count=<n>Limit the number of results.
  • --merged / --no-mergedFilter by merge state.

Examples

Every local branch with its age and author - the stale-branch audit.

example
git for-each-ref --sort=-committerdate refs/heads/ \
  --format='%(committerdate:relative)%09%(authorname)%09%(refname:short)'

The five most recently created tags.

example
git for-each-ref --count=5 --sort=-creatordate refs/tags
git update-indexCaution

Manipulate the index directly - including telling Git to ignore changes to a tracked file.

Mostly plumbing, but two flags get reached for constantly: `--skip-worktree`, which makes Git ignore local modifications to a tracked file (the correct way to keep a local config override), and `--assume-unchanged`, a performance hint that people misuse for the same purpose. Both hide real changes, so a forgotten flag looks exactly like a Git bug months later.

Syntax

git update-index
git update-index --skip-worktree <file>
git update-index --no-skip-worktree <file>

Common options

  • --skip-worktreeIgnore local changes to a tracked file. Survives most operations - use this one.
  • --no-skip-worktreeUndo it.
  • --assume-unchangedA performance promise that you won't change the file. Not an ignore mechanism.
  • --chmod=+xSet the executable bit on a tracked file, including on Windows.
  • --refreshRe-stat files to clear phantom modifications.

Examples

Keep your own version of a tracked config file without ever committing it.

example
git update-index --skip-worktree config/local.json

Find every file you've marked skip-worktree - run this before blaming Git.

example
git ls-files -v | grep '^S'

Mark a script executable in the repo from Windows.

example
git update-index --chmod=+x scripts/build.sh
git symbolic-refCaution

Read or set what a symbolic reference like HEAD points to.

HEAD is not a commit - it's a pointer to a branch, and this is the command that reads and writes that pointer. Its practical use is renaming a repository's default branch, particularly on a bare server repo where there's no working tree to check anything out into.

Syntax

git symbolic-ref
git symbolic-ref HEAD
git symbolic-ref HEAD refs/heads/main

Common options

  • --shortPrint just the branch name.
  • -dDelete the symbolic ref.

Examples

The current branch name, without the refs/heads/ prefix.

example
git symbolic-ref --short HEAD

Change the default branch of a bare repository from master to main.

example
git symbolic-ref HEAD refs/heads/main
git diff-treeSafe

List what changed in a commit, in a script-friendly form.

The plumbing behind `git show`'s file list. Because its output is stable and easy to parse, it's what hooks and CI scripts use to answer 'which files did this push touch?' - typically to decide whether to run a particular test suite.

Syntax

git diff-tree
git diff-tree --no-commit-id --name-only -r <commit>

Common options

  • -rRecurse into subdirectories.
  • --no-commit-idOmit the commit hash line.
  • --name-only / --name-statusPaths, optionally with status letters.
  • -mAlso show diffs for merge commits.

Examples

List the files changed by the latest commit - the standard hook one-liner.

example
git diff-tree --no-commit-id --name-only -r HEAD

Run tests only when source files changed.

example
git diff-tree --no-commit-id --name-only -r HEAD | grep -q '^src/' && npm test
git gcDestructive

Compress the repository and delete unreachable objects.

Packs loose objects together, prunes ones nothing references, and expires old reflog entries. Git runs it automatically now and then, which is exactly why recovery has a deadline - once gc prunes an unreachable commit, no amount of fsck will find it. Never run `--prune=now` while you're trying to recover something.

Syntax

git gc
git gc
git gc --aggressive
git gc --prune=now

Common options

  • --aggressiveRepack much more thoroughly. Slow; worth it occasionally after a big rewrite.
  • --prune=<date>Delete unreachable objects older than a date. --prune=now deletes them all immediately.
  • --autoOnly run if Git thinks it's needed. What the automatic invocation uses.
  • --no-pruneRepack but keep unreachable objects.

Examples

Routine housekeeping - safe, keeps recent unreachable objects.

example
git gc

Actually shrink the repo after a history rewrite. Destroys all recovery options first.

example
git reflog expire --expire=now --all
git gc --prune=now --aggressive
git pruneDestructive

Delete unreachable objects from the object database.

The narrow tool that `git gc` calls to remove objects nothing points to. You rarely run it directly, and doing so while a recovery is in progress is how a recoverable situation becomes permanent - `--dry-run` first, always.

Syntax

git prune
git prune --dry-run
git prune --expire <date>

Common options

  • -n, --dry-runReport what would be deleted.
  • --expire <date>Only prune objects older than this.
  • -vVerbose.

Examples

See which unreachable objects would be removed - and check none of them are yours.

example
git prune --dry-run -v
git repackCaution

Rebuild the pack files that store your objects efficiently.

Git stores objects either loose (one file each) or packed (many, delta-compressed, in one file). Repacking is what turns thousands of loose objects into a compact pack, and after a large history rewrite it's what actually reclaims the disk space.

Syntax

git repack
git repack -a -d
git repack -a -d --depth=250 --window=250

Common options

  • -aRepack everything into a single pack.
  • -dDelete the now-redundant packs.
  • --window / --depthTrade CPU time for a smaller result.
  • -fRecompute deltas from scratch.

Examples

Maximum-effort repack - noticeably smaller, and slow on a big repo.

example
git repack -a -d --depth=250 --window=250
git count-objectsSafe

Report how much disk space the repository is using.

Tells you how many loose and packed objects exist and how much space they occupy, in human-readable units with `-vH`. It's the first command to run when a clone feels absurdly slow or `.git` has quietly grown to several gigabytes.

Syntax

git count-objects
git count-objects -vH

Common options

  • -vVerbose breakdown.
  • -HHuman-readable sizes.

Examples

See size-pack and count - the quickest diagnosis of repository bloat.

example
git count-objects -vH
git verify-packSafe

Inspect a pack file to find the largest objects inside it.

Lists every object in a pack with its size, which is the fastest route to identifying what is actually making your repository huge. Sort its output by size, take the top few hashes, and `git rev-list --objects` will tell you their filenames.

Syntax

git verify-pack
git verify-pack -v .git/objects/pack/*.idx

Common options

  • -vList every object with type and size.
  • -sSummary only.

Examples

Find the ten biggest objects in the repository and print their filenames.

example
git verify-pack -v .git/objects/pack/*.idx |
  sort -k 3 -n | tail -10 |
  awk '{print $1}' |
  while read h; do git rev-list --objects --all | grep "$h"; done
git maintenanceSafe

Schedule background upkeep so big repositories stay fast.

The modern replacement for hoping `git gc --auto` runs at a convenient moment. It registers scheduled background tasks - prefetching, commit-graph writing, incremental repacking - that keep large repositories responsive without ever blocking a command you're waiting on.

Syntax

git maintenance
git maintenance start
git maintenance run --task=<task>
git maintenance stop

Common options

  • start / stopRegister or remove the background schedule.
  • registerAdd this repo to the maintenance list without scheduling.
  • run --task=commit-graph|prefetch|gc|incremental-repackRun one task now.

Examples

Turn on background maintenance for a large repository.

example
git maintenance start

Speed up log and blame immediately by writing the commit graph.

example
git maintenance run --task=commit-graph
git commit-graphSafe

Build an index that makes history traversal dramatically faster.

Precomputes commit relationships into a single file so operations that walk history - `git log --graph`, `git merge-base`, branch ahead/behind counts - stop re-parsing thousands of commit objects. On a large repository it can turn a multi-second log into an instant one.

Syntax

git commit-graph
git commit-graph write --reachable
git commit-graph verify

Common options

  • write --reachableBuild the graph from all refs.
  • --changed-pathsAlso index changed paths, which speeds up file-scoped log enormously.
  • verifyCheck the graph file is consistent.

Examples

Build the full graph, including the path index that accelerates git log -- <file>.

example
git commit-graph write --reachable --changed-paths
git fast-export / fast-importCaution

Stream an entire history out and back in - the basis of repo surgery.

fast-export serialises history into a plain-text stream and fast-import reads it back, so piping one into the other through a filter lets you rewrite anything about a repository. It's how migration tools move projects between version control systems, and the mechanism `git filter-repo` is built on.

Syntax

git fast-export / fast-import
git fast-export --all > repo.stream
git fast-import < repo.stream

Common options

  • --allExport every ref.
  • -M -CDetect renames and copies.
  • --signed-tags=stripDrop signatures that would be invalidated.

Examples

Clone a repository through a stream - the base of any custom rewrite.

example
git fast-export --all | git -C ../new-repo fast-import
git worktreeSafe

Check out several branches into separate folders from one repository.

A worktree gives you an additional working directory backed by the same object database, so you can have main and a feature branch open side by side without cloning twice or stashing constantly. It's ideal when a build takes a long time, or when you need to review a colleague's branch while your own work stays untouched.

Syntax

git worktree
git worktree add <path> <branch>
git worktree list
git worktree remove <path>

Common options

  • add <path> <branch>Create a new working directory for an existing branch.
  • add -b <new> <path>Create a new branch and a worktree for it at once.
  • listShow all worktrees.
  • remove <path>Delete a worktree cleanly.
  • pruneClean up records for worktrees whose folders were deleted.

Examples

Open the hotfix branch in a sibling folder while you keep working in the main one.

example
git worktree add ../repo-hotfix hotfix/crash

Inspect an arbitrary commit in its own folder without disturbing anything.

example
git worktree add --detach ../repo-review a1b2c3d
git submoduleCaution

Embed another Git repository inside yours at a pinned commit.

A submodule records a specific commit of an external repo rather than copying its files into your history. Cloning a project with submodules gives you empty folders until you initialise them, which is the number one submodule confusion. Many teams prefer a package manager or subtree instead, because submodules add real day-to-day friction.

Syntax

git submodule
git submodule add <url> <path>
git submodule update --init --recursive
git clone --recurse-submodules <url>

Common options

  • add <url> <path>Attach an external repo at a path.
  • update --init --recursiveFetch and check out all submodules, including nested ones.
  • update --remoteAdvance submodules to their latest upstream commit.
  • foreach <cmd>Run a command in every submodule.
  • deinit <path>Unregister a submodule.
  • statusShow each submodule's checked-out commit.

Examples

Fix the classic 'my submodule folders are empty after cloning'.

example
git submodule update --init --recursive

Bring every submodule up to date on its main branch.

example
git submodule foreach 'git switch main && git pull'
git subtreeCaution

Vendor another repository into a subdirectory - without submodules' friction.

Subtree merges an external project's files directly into a folder of your repo, so anyone who clones you gets everything with no extra initialisation step. You can still pull upstream updates and even push changes back. The trade-off is a fatter history and slightly awkward commands, but for consumers it is dramatically simpler than a submodule.

Syntax

git subtree
git subtree add --prefix=<dir> <repo> <ref> --squash
git subtree pull --prefix=<dir> <repo> <ref> --squash

Common options

  • add --prefix=<dir>Import a repository into a subdirectory.
  • pull --prefix=<dir>Update it from upstream.
  • push --prefix=<dir>Send your changes back upstream.
  • --squashCollapse the imported history into a single commit. Usually what you want.
  • split --prefix=<dir>Extract a subdirectory's history into its own branch.

Examples

Vendor a dependency in so clones just work, no submodule init required.

example
git subtree add --prefix=vendor/lib https://github.com/other/lib.git main --squash

Split a subdirectory out into its own branch, ready to become a separate repo.

example
git subtree split --prefix=packages/ui -b ui-only
git lfsCaution

Store large binary files outside history and keep the repo small.

Git stores a complete copy of every version of every file, which is fine for text and catastrophic for 200 MB textures, audio and 3D models. Git LFS replaces those files with small pointer files and keeps the real data on a separate server. Set it up before committing large assets - retrofitting LFS means rewriting history.

Syntax

git lfs
git lfs install
git lfs track "*.psd"
git lfs ls-files

Common options

  • installSet up the LFS hooks in this repo (once per machine per repo).
  • track "<pattern>"Route matching files through LFS and record it in .gitattributes.
  • ls-filesList files currently managed by LFS.
  • migrate import --include="*.psd"Move existing large files in history into LFS - rewrites history.
  • pruneDelete local LFS files that are no longer needed.

Examples

Set up LFS for a game project's art assets before committing them.

example
git lfs install
git lfs track "*.psd"
git lfs track "*.fbx"
git add .gitattributes
git commit -m "Track binary assets with LFS"

Retrofit LFS onto a repo that already committed big binaries. Rewrites history.

example
git lfs migrate import --include="*.psd,*.fbx" --everything
.gitattributesSafe

Per-path rules for line endings, diffing, merging and export.

A tracked file that tells Git how to treat particular paths - which is why, unlike your local config, its rules apply identically for everyone who clones. It's the correct fix for CRLF/LF churn, for marking binary files as unmergeable, and for teaching Git to produce readable diffs of unusual formats.

Syntax

.gitattributes
# in .gitattributes
<pattern> <attribute>...

Common options

  • * text=autoNormalise line endings in the repository. The standard first line.
  • *.png binaryShorthand for -text -diff: never try to merge or diff it.
  • *.unity merge=unityyamlmergeRoute Unity scenes through a smart merge tool.
  • *.md diff=markdownUse a language-aware diff driver for better hunk headers.
  • tests/ export-ignoreExclude a path from git archive output.
  • *.psd filter=lfs diff=lfs merge=lfs -textWhat git lfs track writes for you.

Examples

Kill line-ending noise across a mixed Windows/macOS team.

example
# .gitattributes
* text=auto
*.sh text eol=lf
*.bat text eol=crlf
*.png binary
*.fbx binary

Apply new line-ending rules to files already in the repo.

example
git add .gitattributes
git commit -m "Normalise line endings"
git add --renormalize .
git commit -m "Renormalise existing files"
git hooksSafe

Run your own scripts automatically at points in the Git lifecycle.

Hooks are executable scripts in `.git/hooks` that fire on events like `pre-commit`, `commit-msg` and `pre-push`. They're how projects enforce linting, formatting and commit-message conventions locally. They aren't cloned with the repo, so teams use a tool like Husky or set `core.hooksPath` to share them.

Syntax

git hooks
git config core.hooksPath .githooks
chmod +x .githooks/pre-commit
git commit --no-verify

Common options

  • pre-commitRuns before a commit is created - the usual place for linting.
  • commit-msgValidate or rewrite the commit message.
  • pre-pushLast chance to block a push - run the test suite here.
  • post-checkout / post-mergeReact to a branch change, e.g. reinstall dependencies.
  • --no-verifySkip hooks for one command when you genuinely need to.

Examples

Share hooks with your team by committing them to a tracked folder.

example
git config core.hooksPath .githooks

A pre-commit hook that catches credentials before they enter history.

example
#!/bin/sh
# .githooks/pre-commit - block accidental secrets
if git diff --cached | grep -qE "(api[_-]?key|secret|password)\s*="; then
  echo "Possible secret in staged changes. Use --no-verify to override."
  exit 1
fi
git bugreportSafe

Collect your Git version and environment into a ready-to-file report.

Generates a text file with your Git version, platform details and configuration, prefilled with the questions maintainers always ask. Even if you never file a bug, it's a fast way to capture the environment details that explain why a command behaves differently on your machine than a colleague's.

Syntax

git bugreport
git bugreport
git bugreport -o <dir>

Common options

  • -o <dir>Where to write the report.
  • -s <suffix>Custom filename suffix.

Examples

Produce a full environment report before asking for help.

example
git bugreport -o /tmp

Git commands FAQ

How many Git commands are there?

Git ships with well over 150 commands, but they split into 'porcelain' (the friendly ones you type daily) and 'plumbing' (low-level internals scripts are built from). In practice about a dozen cover most work, and this reference documents the 80-odd that are genuinely worth knowing.

Which Git commands should I learn first?

status, add, commit, push, pull, switch, branch, merge, log and diff will carry you through almost every normal day. Add restore and reset for undoing things, then reflog and fsck — not because you'll use them often, but because they're what get your work back when something goes wrong.

Which Git commands are dangerous?

The ones that can destroy uncommitted work: git reset --hard, git clean -fdx, git checkout -- <file> and git restore <file>. Rewriting commands like rebase, commit --amend and filter-repo are dangerous in a different way — they change history others may already have. Every command here carries a danger rating for exactly this reason.

What is the difference between porcelain and plumbing commands?

Porcelain commands (log, commit, merge, status) are the human-facing interface, and their output can change between versions. Plumbing commands (rev-parse, cat-file, ls-tree, rev-list) are stable, script-friendly internals — the porcelain is built on top of them, which is why they're what you reach for in hooks and CI.

What is git reflog and why does it matter so much?

It's a local journal of every position HEAD and each branch has held, kept for about 90 days — including states no branch points at any more. That makes it the single most valuable recovery command in Git: a bad reset, a botched rebase or a deleted branch are all still listed there and can be pointed at again.

What does git fsck do?

It walks every object in .git/objects and reports the ones nothing references. Dangling blobs are file contents from work that was staged but never committed; dangling commits come from deleted branches and dropped stashes. It's the deepest recovery layer Git has, below even the reflog.

What is the difference between git switch and git checkout?

git checkout does three unrelated jobs — change branches, restore files and detach HEAD — which is why a typo could silently destroy uncommitted work. Git 2.23 split it into git switch (branches only) and git restore (file contents only). Prefer the new pair; checkout still works and appears throughout older tutorials.

Can I create shortcuts for long Git commands?

Yes — git config --global alias.<name> '<command>'. For example alias.lg for a graph log, or alias.unstage for restore --staged. Prefix the value with ! to run an arbitrary shell command instead. Aliases are personal and never shared through the repository.

Do I need to memorise all of these?

No. Learn the dozen you use daily and bookmark the rest. The value of a reference like this is recognising that a command exists — knowing git bisect can find a bad commit automatically, or that git range-diff compares two versions of a branch, matters far more than remembering the exact flags.

Something actually broken?

Knowing the command is one thing — knowing which one to run at 2am is another. There are 56 step-by-step rescue guides for the situations these commands are meant to fix.

Browse the fix-it guides →