Git Command Line Cheat Sheet

Sidebar

Programming ยท Git Command Line Cheat Sheet

The Git commands you use every day, grouped by task: setup, the daily loop, history, branches, merging and rebasing, undoing, remotes, stash and tags, searching, ignoring files and naming commits. Written for Git 2.49 on Windows, the version installed here; the commands and options were run in a scratch repository to check they work. This is the command-line companion to the VS Code Git and Source Control sheet, which covers the editor's settings.

Setup & Configuration

git --versionCheck the install (here: 2.49.0.windows.1)
git config --global user.name "Your Name"Who your commits are from; also user.email
git config --list --show-originEvery setting and the file it came from
--system --global --localWhere a setting is stored: all users / your account (~/.gitconfig) / this repository (.git/config); local beats global beats system
git config --global init.defaultBranch mainNew repositories start on this branch. Yours is currently master, set in Git's system config
git config --global alias.st "status -sb"Create a shortcut: then git st works
git config --global core.editor "code --wait"Use VS Code for commit messages
core.autocrlfLine-ending conversion; true here (Windows), which causes the "LF will be replaced by CRLF" warnings
credential.helpermanager here: Git Credential Manager remembers your logins
git help <command> or git <command> -hFull manual page / one-screen summary

Starting a Repository

git initTurn the current folder into a repository; -b main (or --initial-branch) names the first branch
git clone <url> [folder]Copy a remote repository
git clone --depth 1 <url>Only the latest commit: much faster for big repositories
git clone --branch <name> --single-branch <url>Only one branch
git clone --filter=blob:none <url>A partial clone: file contents are fetched when needed
git clone --recurse-submodules <url>Also fetch submodules
git clone --bare / --mirrorServer-style copies with no working folder

The Daily Loop

git status -sbShort status with the branch and its upstream (-s short, -b branch)
git add <file> git add . git add -uStage a file / everything here / only files Git already tracks
git add -pChoose which pieces of a file to stage, one hunk at a time
git diffChanges not yet staged
git diff --staged (or --cached)Changes that are staged for the next commit
git diff --stat --name-only --word-diffSummary / just file names / word-level changes; git diff --check finds whitespace mistakes
git commit -m "message"Commit what is staged; -a also stages tracked files; -v shows the diff in the editor
git commit --amendChange the last commit; --no-edit keeps its message; only before you push it
git commit --allow-empty --signoff --fixup <sha>Empty commit / add a Signed-off-by line / mark a fix for a later autosquash
git rm <file> git rm --cached <file>Delete and stop tracking / stop tracking but keep the file
git mv old newMove or rename a tracked file

Looking at History

git log --oneline --graph --decorate --allThe classic compact picture of every branch
git log -p git log --statWith the changes / with a change summary; add -3 to limit
git log --author="Name" --since="2 weeks ago"Filter by author and date
git log --grep="fix"Commits whose message matches
git log -S"text" git log -G"regex"Commits that added or removed that text / changed lines matching the pattern
git log --follow -- <file>History of one file, through renames
git log -L 10,20:<file>History of a range of lines
git log main..featureCommits on feature that are not on main
git log main...feature --left-rightCommits on either side but not both
git log --first-parent --no-mergesFollow only the main line / hide merge commits
git log --pretty=format:"%h %an %s"Your own layout: hash, author, subject
git show <rev> git show <rev>:<path>One commit / a file as it was then
git blame -L 1,20 <file>Who last changed each line
git shortlog -snCommit counts per author
git describe --tags --alwaysA readable name for the current commit

Branches

git branchList local branches; -vv adds the last commit and upstream, -a includes remote ones, -r only remote ones
git branch --show-currentPrint just the current branch name
git switch <branch>Move to a branch
git switch -c <new>Create a branch and move to it (git checkout -b in older guides)
git switch -Back to the previous branch
git switch --detach <rev>Look at an old commit without being on a branch
git branch <new>Create a branch without moving to it
git branch -m <old> <new>Rename a branch
git branch -d <b> git branch -D <b>Delete if fully merged / delete regardless
git branch --merged --no-mergedWhich branches are already in the current one, and which are not

Merging, Rebasing & Cherry-Picking

git merge <branch>Bring that branch into the current one
git merge --no-ff / --ff-only / --squashAlways make a merge commit / refuse unless it fast-forwards / combine everything into one change you commit yourself
git merge --abortGive up a merge that has conflicts
<<<<<<< ======= >>>>>>>Conflict markers in a file: edit the file, git add it, then git merge --continue (or commit)
git mergetoolOpen your configured merge tool
git rebase mainReplay your commits on top of main
git rebase -i HEAD~3Edit the last three commits: pick, reword, edit, squash, fixup, drop
git rebase --autosquash --autostashFold --fixup commits automatically / stash and restore your changes around it
git rebase --onto <new> <old> <branch>Move a branch to a different base
git rebase --continue --skip --abortAfter fixing a conflict / skip this commit / go back to before the rebase
git cherry-pick <sha>Copy one commit here; -x notes where it came from, --no-commit leaves it staged
git revert <sha>Make a new commit that undoes one (-m 1 for a merge commit)
Do not rebase shared historyRebasing rewrites commits: only rebase branches that nobody else has pulled

Undoing Things (from safest to riskiest)

git restore --staged <file>Unstage a file; your edits stay
git restore <file>Discard your uncommitted edits to a file: they cannot be recovered
git restore --source=HEAD~1 <file>Bring back a file as it was one commit ago
git commit --amendFix the last commit (not yet pushed)
git reset --soft HEAD~1Undo the last commit; changes stay staged
git reset --mixed HEAD~1Undo the last commit; changes stay in your files, unstaged (the default)
git revert <sha>Undo a commit you already pushed, safely, with a new commit
git reset --hard <rev>Throw away commits and uncommitted changes: use with great care
git reflogWhere HEAD has been: your safety net for "lost" commits
git switch -c rescue <sha>Give a lost commit from the reflog a branch again
git clean -n -dDry run: which untracked files and folders would be deleted
git clean -fdDelete them (-x also removes ignored files)

Remotes: Fetch, Pull & Push

git remote -vList remotes and their addresses
git remote add origin <url>Add one; set-url changes it, rename and remove also exist
git remote show originDetails of a remote and how your branches track it
git fetch --prune --allDownload new commits and forget deleted remote branches; nothing in your files changes
git pullFetch and then merge; --rebase rebases instead, --ff-only refuses a merge, --autostash saves and restores your changes
git pushUpload the current branch
git push -u origin <branch>First push of a branch; -u (--set-upstream) remembers it
git push --force-with-leaseA forced push that fails if someone else pushed in the meantime: use this instead of --force
git push --tags --follow-tagsUpload all tags / annotated tags that point at pushed commits
git push origin --delete <branch>Delete a remote branch
git push --dry-runShow what would be pushed
git branch --set-upstream-to=origin/<b>Tell Git which remote branch this one follows

Stash & Tags

git stash push -u -m "wip"Put away your uncommitted work (-u includes untracked files)
git stash listSee the stack of stashes
git stash show -p stash@{0}See what is in a stash
git stash pop git stash applyRestore the latest stash and remove it / restore it and keep it
git stash drop git stash clearDelete one stash / all of them
git stash branch <name>Make a branch from a stash
git tag v1.0A lightweight tag on the current commit
git tag -a v1.0 -m "Release 1.0"An annotated tag with a message (better for releases)
git tag -l git tag -d v1.0List tags / delete one
git push origin v1.0Upload one tag

Searching & Inspecting

git grep -n -i "text"Search tracked files; -c counts per file
git ls-files -m --others --exclude-standardModified files / untracked files that are not ignored
git check-ignore -v <file>Which ignore rule applies to a file
git rev-parse --short HEAD --show-toplevelShort hash of the current commit / the repository's top folder
git ls-tree -r HEAD --name-onlyEvery file in a commit
git cat-file -p <sha>Show the raw contents of a Git object
git bisect start / bad / good <sha>Binary-search for the commit that introduced a bug; finish with git bisect reset
git bisect run <command>Let a script decide good or bad automatically
git archive --format=zip -o out.zip HEADMake a zip of a commit without the .git folder
git worktree add ../dir -b <branch>A second working folder for another branch; list, remove manage them
git sparse-checkout set <folders>Check out only some folders of a big repository
git fsck git gc git maintenance runCheck, tidy and optimise the repository

Ignoring Files & Line Endings

.gitignoreA file of patterns for files Git should not track
*.logIgnore by pattern
build/A trailing slash means a folder
/config.localA leading slash anchors it to the top folder
**/tempMatch at any depth
!keep.logA leading ! re-includes something an earlier pattern ignored
# commentComment line
git rm --cached <file>A file already tracked stays tracked until you do this; adding it to .gitignore is not enough
core.excludesFileA personal ignore file that applies to every repository
.gitattributesPer-path rules, such as * text=auto or *.sh text eol=lf to fix line endings across machines
Git LFSInstalled here (filter.lfs.* in the system config): stores large files outside the normal history

Naming Commits & Ranges (revision syntax)

HEAD @The current commit
HEAD~1 HEAD~3The parent / the great-grandparent along the first-parent line
HEAD^ HEAD^2First parent / second parent (the merged-in side of a merge)
main@{upstream} @{u}The remote branch a local branch follows
main@{yesterday} main@{3}Where a branch was yesterday / three moves ago (from the reflog)
A..BCommits in B but not in A
A...BCommits in either but not both
:/textThe most recent commit whose message contains the text
<rev>:<path>A file as it was in that commit
short hashesThe first 7 or more characters of a hash are enough if they are unique

Handy Aliases to Copy (my suggestions)

git config --global alias.st "status -sb"Short status
git config --global alias.lg "log --oneline --graph --decorate --all"The graph in two letters
git config --global alias.co "switch"A short name for switching branches
git config --global alias.unstage "restore --staged"Say what you mean
git config --global alias.last "log -1 HEAD --stat"Show the last commit
git config --global alias.amend "commit --amend --no-edit"Add staged changes to the last commit
git config --global pull.ff onlyMake git pull refuse anything but a fast-forward (a safe habit)
git config --global push.autoSetupRemote trueFirst git push sets the upstream for you
I made a mistake! Work down this ladder
1) Is it only an uncommitted edit? git restore <file> discards it for good, so be sure. 2) Is it staged by mistake? git restore --staged <file>. 3) Is it the last commit and not yet pushed? git commit --amend or git reset --soft HEAD~1. 4) Already pushed? git revert <sha> adds a new commit that undoes it, without rewriting shared history. 5) Think you lost commits? git reflog lists where HEAD has been for a long while: pick the hash and git switch -c rescue <sha>. Git rarely loses committed work, but it cannot bring back uncommitted changes you discarded.
master or main? Check your default branch
Many hosting sites now call the main branch main, but your Git installation's system settings still create master in new repositories (init.defaultBranch=master). Either name works, but if you push to a new repository on a site that expects main, rename with git branch -m main or set git config --global init.defaultBranch main before running git init.
Never force-push to a shared branch
git push --force overwrites the remote branch with yours and can destroy other people's commits. If you must update a branch you have rebased or amended, use --force-with-lease, which stops if someone else has pushed since you last fetched, and only do it on a branch that is yours alone.