Git Cheat Sheet
Every command, flag, and workflow pattern. Searchable, filterable by level, copy-ready.
Every command, flag, and workflow pattern. Searchable, filterable by level, copy-ready.
Most developers don't memorize every git command. They keep a reliable git cheat sheet nearby and look things up when needed. That's not a weakness. That's just practical.
Git has a lot of commands. The git commit and branch management basics are easy enough. But then you need to undo a merge, recover a lost commit with git reflog, or figure out the difference between git fetch vs git pull, and things get tricky fast.
This guide covers the most used git commands across the full workflow: from git init and git clone through staging, committing, branching, merging, rebasing, and working with remote repositories on GitHub or GitLab.
Quick reference. No fluff.
A git cheat sheet is a condensed reference of the most common git commands, grouped by workflow stage so you can find what you need without digging through full documentation.
It's not a replacement for learning git. It's a practical tool for when you already know what you need to do but can't remember the exact syntax.
Git adoption rose from 87.1% in 2016 to 93.87% by 2025 (RhodeCode), making it by far the most widely used version control system in professional software development.
|
Use Case |
Who Benefits Most |
|---|---|
|
Daily workflow commands |
Junior developers building habits |
|
Branch and merge operations |
Mid-level devs on multi-branch projects |
|
Recovery and revert commands |
Senior devs managing production repos |
|
Remote sync (push/pull/fetch) |
Teams working across GitHub or GitLab |
The official Pro Git book (by Scott Chacon and Ben Straub) remains the most comprehensive reference, but it's not something you keep open mid-sprint. That's what this guide is for.
Before running a single git commit, your local environment needs to know who you are. Git uses this identity to attach to every commit you make.
Core setup commands:
git config --global user.name "Your Name" sets your display name
git config --global user.email "you@example.com" sets your commit email
git config --global core.editor "code --wait" sets VS Code as your default editor
git config --list shows all currently active config values
Authentication setup:
HTTPS: use Git Credential Manager to cache credentials locally
SSH: generate a key with ssh-keygen -t ed25519 -C "you@example.com", then add it to GitHub
50% of developers have run into SSH key or authentication issues at some point (Hutte, 2024). Getting this right upfront saves a lot of frustrating Permission denied errors later.
Setting git config --global init.defaultBranch main renames the default branch from master to main globally. Most teams now expect main as the default, so it's worth setting this early.
Two ways to start working with Git: create a new repository locally, or copy an existing one from a remote source like GitHub or GitLab.
git init creates a .git folder in the current directory, turning it into a tracked repository.
Running git init my-project creates a new subfolder named my-project with Git already initialized inside it.
After init, connect to a remote:
git remote add origin https://github.com/user/repo.git
git branch -M main
git push -u origin main
git clone <url> copies the full remote repository to your machine, including all branches, tags, and commit history.
Useful clone variations:
git clone <url> folder-name - clones into a custom directory name
git clone --depth 1 <url> - shallow clone, fetches only the latest commit (faster for large repos)
git clone --branch develop <url> - clones and checks out a specific branch directly
GitHub hosts over 630 million repositories as of 2025 (CoinLaw). Most developers clone far more often than they init from scratch.
Once cloned, the remote is automatically named origin. You can verify this with git remote -v.
This is the core daily loop. Stage changes, commit them with a message, repeat.
The three-state model:
|
State |
What it means |
|---|---|
|
Working directory |
Files you've changed but not staged |
|
Staging area (index) |
Changes marked for the next commit |
|
Repository |
Committed history |
git status shows exactly where each changed file sits across these three states.
git add <file> stages a specific file. git add . stages everything in the current directory. git add -p (patch mode) lets you stage specific chunks of a file, which is genuinely useful for keeping commits focused.
Committing:
git commit -m "your message" creates a commit with an inline message
git commit --amend rewrites the last commit (message or staged content)
git commit --amend --no-edit amends the last commit without changing the message
80% of senior developers recommend committing frequently with small, incremental changes rather than large batches (Hutte, 2024). It keeps history readable and makes git bisect actually usable.
git diff shows unstaged changes. git diff --staged shows what's staged and about to be committed. Both are worth running before you commit.
Discarding working directory changes:
git restore <file> discards unstaged changes to a specific file
git restore . discards all unstaged changes (careful, this is permanent)
Unstaging files:
git restore --staged <file> moves a file back from staging to the working directory
This replaces the older git reset HEAD <file> syntax, though both still work
Undoing commits:
git reset --soft HEAD~1 undoes the last commit but keeps changes staged
git reset --mixed HEAD~1 undoes the last commit and unstages changes (default)
git reset --hard HEAD~1 undoes the commit and deletes the changes entirely
git revert <commit-hash> creates a new commit that reverses a previous one without rewriting history. This is the safe option on shared branches where others may have already pulled.
70% of developers have run a git command without fully understanding what it would do (Hutte, 2024). git reset --hard is one of the most dangerous to misuse, as it permanently removes uncommitted changes.
Branching is how parallel work happens without stepping on anyone else's code. Every feature, bug fix, or experiment should live on its own git branch.
Viewing branches:
git branch - lists local branches, highlights current
git branch -a - lists local and remote branches
git branch -r - lists only remote-tracking branches
Creating and switching:
git switch -c feature/login - creates and switches to a new branch (preferred modern syntax)
git checkout -b feature/login - older equivalent, still widely used
git switch main - switches to an existing branch
Renaming and deleting:
git branch -m old-name new-name - renames a branch locally
How to rename a branch in Git covers the full remote-update process
git branch -d branch-name - deletes a merged branch
git branch -D branch-name - force-deletes even if unmerged
git push origin --delete branch-name - removes the branch from the remote
GitHub reached over 150 million developers by 2025, with over 5 billion contributions made in 2024 alone (electroiq). Most of that activity happens across branches.
45% of developers have had work affected by a colleague's force push to a shared branch (Hutte, 2024). Protecting main and develop branches at the repository level is standard practice for a reason.
Two approaches for bringing branch changes together. They produce the same end result but write very different histories.
git merge feature/login integrates changes from feature/login into the current branch.
Merge types:
Fast-forward merge: no new commit, HEAD moves forward (happens when no divergence exists)
Three-way merge: creates a merge commit to combine diverged histories
git merge --no-ff forces a merge commit even when fast-forward is possible, preserving branch history
Merge conflicts happen when two branches edit the same lines differently. Nearly 90% of developers have faced merge conflicts at some point (Hutte, 2024), and they consume an estimated 10-20% of developer time in collaborative projects.
Resolving a conflict:
# After git merge reports conflicts:
git status # see which files conflict
# Edit files to resolve markers
git add <resolved-file>
git merge --continue
git rebase main replays your current branch's commits on top of main, creating a linear history.
When to use which:
Merge: preserves full branch context, better for shared branches
Rebase: cleaner linear history, better for local feature branches before merging
git rebase -i HEAD~3 opens interactive rebase for the last 3 commits. From here you can squash, reword, reorder, or drop commits entirely.
Roughly 55% of developers find git rebase challenging and error-prone (Hutte, 2024). If you're new to it, always rebase on a local branch you haven't pushed, or use git push --force-with-lease instead of --force when you do push a rebased branch.
git cherry-pick <commit-hash> applies a single specific commit from any branch onto the current one. Useful for backporting a fix without merging an entire branch.
Working with remotes is where Git becomes a collaboration tool. These commands sync your local work with GitHub, GitLab, or Bitbucket.
75% of developers run git fetch or git pull at least once daily to stay in sync with remote changes (Hutte, 2024).
|
Command |
What it does |
When to use |
|---|---|---|
|
|
Lists remotes with URLs |
Verify origin setup |
|
|
Downloads without merging |
Check changes before merging |
|
|
Fetch + merge in one step |
Quick sync on trusted branches |
|
|
Uploads local commits |
After committing locally |
|
|
Force push with safety check |
After rebasing a branch |
git fetch: downloads new commits, branches, and tags from the remote but makes no changes to your working directory.
Your local branches stay untouched. You review what came in, then decide whether to merge.
git pull: runs git fetch followed immediately by a merge (or rebase, if configured).
Use git pull --rebase to replay your local commits on top of the fetched changes instead of creating a merge commit. Most teams prefer this for keeping a cleaner history.
Learn more about what git fetch does and what git pull does if you want the full breakdown of each.
git push -u origin feature/login pushes the branch and sets it as the upstream, so future git push commands on that branch need no extra arguments.
git push --force-with-lease is the safer alternative to git push --force. It checks whether the remote has commits you haven't seen yet and rejects the push if it does, preventing you from accidentally overwriting someone else's work.
Only 30% of developers regularly prune stale remote-tracking branches using git remote prune origin (Hutte, 2024). Running it occasionally keeps git branch -r output clean.
git log is how you read a repository's story. Getting comfortable with its flags turns a wall of output into a useful audit trail.
Core log commands:
git log - full log with author, date, and message
git log --oneline - one commit per line, hash + subject
git log --oneline --graph --decorate - ASCII branch visualization
git log --author="Alice" - filter by contributor
git log --since="2024-01-01" --until="2024-06-30" - filter by date range
92% of Git projects enforce code review before merging (Hutte, 2024). Knowing how to read commit history is a practical skill for reviewing what changed and when.
git log -- path/to/file shows only commits that touched a specific file. Useful when you're debugging and want to trace a file's change history without reading through unrelated commits.
git show <commit-hash> displays the full diff and metadata for one specific commit.
git diff main..feature/login compares two branches directly, showing what's in feature/login that isn't in main.
For line-level accountability:
git blame <file> shows the last commit that modified each line, with author and date
git blame -L 20,40 <file> limits output to lines 20 through 40
Git blame is especially useful when tracking down when a bug was introduced
Around 40% of developers use git blame to trace changes to specific lines (Hutte, 2024).
git shortlog -sn summarizes commits per author across the entire repo, sorted by volume. Teams use this during retrospectives to get a quick sense of contribution distribution.
Stash is for the exact moment when you're mid-task on one branch and need to switch to another without committing half-finished work.
Around 52% of developers use git stash regularly for saving uncommitted changes (Hutte, 2024), but 28% have lost work because of confusion about how stash pop and apply differ.
git stash saves both staged and unstaged changes, then reverts the working directory to match the last commit.
git stash push -m "WIP: login form validation" saves with a label, which matters once you have multiple stashes.
Retrieving:
git stash pop - applies the most recent stash and removes it from the list
git stash apply stash@{2} - applies a specific stash without removing it
git stash list - shows all saved stashes with their index numbers
The key difference: pop removes the stash after applying, apply keeps it. If you're unsure whether the apply worked cleanly, use apply first and manually drop it after confirming.
git stash show -p shows a full diff of the most recent stash before applying it.
Cleanup commands:
git stash drop stash@{1} - deletes one specific stash
git stash clear - deletes all stashes permanently
git stash -u (or --include-untracked) stashes untracked files too. Without this flag, newly created files that haven't been staged yet will stay in your working directory.
Stashes are stored on a stack. The most recent one is always stash@{0}.
These commands don't come up every sprint, but when you need them, they're hard to work around.
Approximately 15% of developers have used git bisect to locate the exact commit that introduced a bug (Hutte, 2024). It's underused, considering how much time it saves in large repos.
Git tags mark specific commits as significant, usually for version releases. They don't move as branches do.
|
Tag type |
Command |
Use case |
|---|---|---|
|
Lightweight |
|
Quick local marker |
|
Annotated |
|
Production releases, includes metadata |
|
Push to remote |
|
Share a tag with the team |
|
Push all tags |
|
Sync all local tags |
Semantic versioning conventions like MAJOR.MINOR.PATCH are the standard way to name annotated tags in most projects.
git cherry-pick: applies a single commit from another branch onto your current one.
Common use case: a bug fix lands on main and you need it in a hotfix/v2 branch without merging everything else.
git cherry-pick a1b2c3d
git bisect: binary searches through commit history to find where a bug was introduced.
git bisect start
git bisect bad # current commit is broken
git bisect good v1.2.0 # this tag was working
# Git checks out the midpoint; you test, then run:
git bisect good # or: git bisect bad
# Repeat until Git identifies the culprit commit
git bisect reset # exit bisect mode
On large repositories with hundreds of commits, bisect narrows the search down to the exact bad commit in around 7 steps.
git reflog records every time HEAD moved, including resets and branch switches. It's the recovery tool for commits that seem lost.
After running git reset --hard by mistake, git reflog shows you the commit hash from before the reset. You can restore it with git checkout -b recovery-branch <hash>.
git clean removes untracked files from the working directory:
git clean -n - dry run, shows what would be deleted without deleting anything
git clean -fd - deletes untracked files and directories
git clean -fdx - also removes files ignored by .gitignore
The Linux kernel repository, one of the oldest active Git projects in existence, uses git bisect as a standard debugging step during kernel release cycles (CommandLinux, 2025).
git status is the one command worth running constantly. It shows your working directory state, staged changes, and untracked files at a glance. Most developers check it before every commit to avoid staging the wrong files.
git fetch downloads remote changes without touching your working directory. git pull fetches and immediately merges. Use fetch when you want to review changes first, pull when you're ready to sync directly.
Run git reset --soft HEAD~1. This moves the commit back to staged, so your work stays intact. If you want it unstaged instead, use git reset --mixed HEAD~1. Both are safe on local branches.
git stash temporarily saves uncommitted changes and reverts your working directory to the last commit. Use it when switching branches mid-task. Retrieve saved work later with git stash pop or git stash apply.
Open the conflicting file and look for <<<<<<<, =======, and >>>>>>> markers. Edit the file to keep the correct version, remove all markers, then run git add on the file and complete the merge with git merge --continue.
Both integrate branch changes, but git rebase rewrites history into a linear sequence while git merge preserves the full branch context with a merge commit. Use rebase on local feature branches, merge on shared ones.
Delete locally with git branch -d branch-name. Force delete with -D if the branch is unmerged. Remove the remote branch with git push origin --delete branch-name. You can learn more in the guide on how to delete a branch in Git.
git clone copies a full remote repository to your machine, including all branches, tags, and commit history. The remote is automatically named origin. Add a folder name after the URL to clone into a custom directory.
Run git log for the full history. Use git log --oneline for a compact view. Add --graph --decorate to visualize branches. Filter by author with --author="Name" or by date with --since and --until flags.
git reflog records every movement of HEAD, including resets and branch switches. Use it after accidentally running git reset --hard to recover the lost commit hash. It's essentially an undo log for your local repository.