Master Git with this comprehensive cheat sheet. Essential commands for setup, branching, merging, rebasing, stashing, and advanced workflows with practical examples.
I've been using Git daily for years, and I still look things up. Not the basics — add, commit, push — but the commands you need once a month and can never quite remember the flags for. How do you squash the last three commits? What's the difference between reset --soft and reset --mixed? How do you find which commit introduced a bug?
This cheat sheet is the reference I wish I'd had when I started. It covers everything from initial setup to advanced workflows, organized by category so you can find what you need fast.
| Task | Command |
|---|---|
| Initialize a repo | git init |
| Clone a repo | git clone <url> |
| Stage all changes | git add . |
| Commit with message | git commit -m "message" |
| Push to remote | git push origin main |
| Pull latest changes | git pull origin main |
| Create a branch | git branch feature-name |
| Switch branch | git switch feature-name |
| Merge branch | git merge feature-name |
| View commit history | git log --oneline |
| Stash changes | git stash |
| Undo last commit (keep changes) | git reset --soft HEAD~1 |
| Discard file changes | git restore <file> |
| View diff | git diff |
Before writing any code, configure your identity. Every commit records who made it.
# Set your name and email (global)
git config --global user.name "Your Name"
git config --global user.email "your@email.com"
# Set default branch name to main
git config --global init.defaultBranch main
# Set default editor
git config --global core.editor "code --wait"
# Enable colored output
git config --global color.ui auto
# View all your settings
git config --list
# View a specific setting
git config user.nameOn Windows, you'll want to handle line endings correctly:
# Windows: convert CRLF to LF on commit
git config --global core.autocrlf true
# Mac/Linux: convert CRLF to LF on commit, no conversion on checkout
git config --global core.autocrlf inputThis is the daily cycle. You'll run these commands hundreds of times.
# Initialize a new repository
git init
# Clone an existing repository
git clone https://github.com/user/repo.git
# Clone into a specific directory
git clone https://github.com/user/repo.git my-project
# Check the status of your working directory
git status
# Stage a specific file
git add index.html
# Stage multiple files
git add src/app.js src/utils.js
# Stage all changes (new, modified, deleted)
git add .
# Commit staged changes
git commit -m "Add user authentication flow"
# Stage and commit tracked files in one step
git commit -am "Fix login validation bug"
# Push to remote repository
git push origin main
# Pull latest changes from remote
git pull origin mainA good commit message describes why the change was made, not what was changed. The diff already shows the what. Write messages like "Fix race condition in session cleanup" instead of "Update auth.js".
Branches are cheap in Git. Use them for every feature, bug fix, and experiment.
# List all local branches
git branch
# List all branches including remote
git branch -a
# Create a new branch
git branch feature/user-profile
# Switch to a branch (modern syntax)
git switch feature/user-profile
# Create and switch in one step
git switch -c feature/user-profile
# Rename the current branch
git branch -m new-branch-name
# Delete a merged branch
git branch -d old-branch
# Force delete an unmerged branch
git branch -D experimental-branch
# Push a new branch to remote
git push -u origin feature/user-profileThe -u flag in git push -u origin feature/user-profile sets up tracking, so future git push and git pull commands work without specifying the remote and branch name.
Merging combines the work from one branch into another.
# Merge feature branch into main
git switch main
git merge feature/user-profile
# Merge with a commit message (no fast-forward)
git merge --no-ff feature/user-profile
# Abort a merge if there are conflicts you're not ready to resolve
git merge --abort
# After resolving conflicts, complete the merge
git add .
git commitWhen a merge conflict occurs, Git marks the conflicted sections in your files:
<<<<<<< HEAD
your changes
=======
their changes
>>>>>>> feature/user-profile
Edit the file to keep the code you want, remove the markers, then stage and commit. You can compare the conflicting versions side by side using a Text Diff tool to make conflict resolution easier.
By default, if the target branch hasn't diverged, Git performs a fast-forward merge — it just moves the pointer. Using --no-ff creates a merge commit even when fast-forward is possible, which preserves the branch history in the log.
Rebasing replays your commits on top of another branch. It produces a cleaner, linear history compared to merge commits.
# Rebase current branch onto main
git rebase main
# Abort a rebase in progress
git rebase --abort
# Continue after resolving a conflict during rebase
git rebase --continue
# Rebase and squash last 3 commits
git rebase -i HEAD~3When to rebase vs. merge: Rebase your feature branch onto main to keep history clean. Merge when combining completed work into shared branches. Never rebase commits that have been pushed to a shared branch — it rewrites history and will cause problems for your teammates.
Stashing saves your uncommitted changes temporarily so you can switch branches or pull updates.
# Stash current changes
git stash
# Stash with a description
git stash push -m "WIP: user profile validation"
# List all stashes
git stash list
# Apply the most recent stash (keep it in stash list)
git stash apply
# Apply and remove the most recent stash
git stash pop
# Apply a specific stash
git stash apply stash@{2}
# Drop a specific stash
git stash drop stash@{1}
# Clear all stashes
git stash clear
# Stash including untracked files
git stash -uCherry-pick applies a specific commit from one branch to another without merging the entire branch.
# Apply a specific commit to the current branch
git cherry-pick abc1234
# Cherry-pick without committing (stage only)
git cherry-pick --no-commit abc1234
# Cherry-pick a range of commits
git cherry-pick abc1234..def5678This is useful when a bug fix was made on a feature branch and you need it on main immediately, without merging unfinished feature work.
These commands undo changes, but they work differently.
Reset moves the branch pointer backward. It rewrites history.
# Undo last commit, keep changes staged
git reset --soft HEAD~1
# Undo last commit, keep changes unstaged
git reset --mixed HEAD~1
# Undo last commit, discard all changes (destructive)
git reset --hard HEAD~1
# Unstage a file (keep changes in working directory)
git restore --staged file.jsRevert creates a new commit that undoes a previous commit. It's safe for shared branches because it doesn't rewrite history.
# Revert a specific commit
git revert abc1234
# Revert without auto-committing
git revert --no-commit abc1234
# Revert a merge commit (specify parent)
git revert -m 1 abc1234Use reset for local cleanup before pushing. Use revert for undoing changes that have already been shared.
Understanding the history of your project is half the battle.
# Compact one-line log
git log --oneline
# Log with graph visualization
git log --oneline --graph --all
# Log for a specific file
git log --follow -- src/auth.js
# Search commit messages
git log --grep="fix login"
# Show commits by author
git log --author="Your Name"
# Show commits in a date range
git log --after="2026-01-01" --before="2026-03-27"
# Show last 5 commits
git log -5
# View changes in working directory
git diff
# View staged changes
git diff --staged
# Compare two branches
git diff main..feature/user-profile
# Show changes in a specific commit
git show abc1234
# Show file statistics (insertions/deletions)
git diff --stat main..feature/user-profileFor comparing longer text files or code output, the Text Diff tool provides a visual side-by-side comparison that's easier to parse than terminal output.
Working with remote repositories.
# List remotes
git remote -v
# Add a remote
git remote add origin https://github.com/user/repo.git
# Add a second remote (e.g., for deployment)
git remote add production https://deploy.example.com/repo.git
# Rename a remote
git remote rename origin upstream
# Remove a remote
git remote remove upstream
# Fetch updates without merging
git fetch origin
# Fetch all remotes
git fetch --all
# Push all branches
git push --all origin
# Delete a remote branch
git push origin --delete old-feature
# Set upstream tracking
git branch --set-upstream-to=origin/main main
# Prune deleted remote branches
git fetch --pruneTags mark specific points in history, typically used for releases.
# Create a lightweight tag
git tag v1.0.0
# Create an annotated tag (recommended)
git tag -a v1.0.0 -m "Release version 1.0.0"
# Tag a specific commit
git tag -a v1.0.0 abc1234 -m "Release version 1.0.0"
# List all tags
git tag
# Push a tag to remote
git push origin v1.0.0
# Push all tags
git push origin --tags
# Delete a local tag
git tag -d v1.0.0
# Delete a remote tag
git push origin --delete v1.0.0The .gitignore file tells Git which files and directories to exclude from tracking.
# Dependencies
node_modules/
vendor/
# Build output
dist/
build/
.next/
# Environment files
.env
.env.local
# OS files
.DS_Store
Thumbs.db
# IDE files
.vscode/
.idea/
# Logs
*.log
npm-debug.log*
# Coverage
coverage/Patterns in .gitignore:
* matches any characters except /** matches any directory depth! negates a pattern (force include a file)/ at the start anchors to the repo root/ at the end matches directories onlyIf a file is already tracked, adding it to .gitignore won't stop tracking it. You need to remove it from the index first:
# Stop tracking a file without deleting it
git rm --cached config.json
# Stop tracking an entire directory
git rm -r --cached dist/These come up less often, but when you need them, you really need them.
# Find which commit introduced a bug (binary search)
git bisect start
git bisect bad # current commit is broken
git bisect good abc1234 # this commit was working
# Git checks out a middle commit; test it, then:
git bisect good # or git bisect bad
# Repeat until Git identifies the first bad commit
git bisect reset # return to original state
# Show who last modified each line of a file
git blame src/auth.js
# Create a patch file
git format-patch -1 HEAD
# Apply a patch
git apply fix.patch
# Clean untracked files (dry run first)
git clean -n
git clean -fd
# List all files tracked by Git
git ls-files
# Count commits by author
git shortlog -snWorktrees let you check out multiple branches simultaneously in separate directories. No more stashing and switching.
# Create a worktree for a branch
git worktree add ../hotfix-branch hotfix/login-fix
# List active worktrees
git worktree list
# Remove a worktree
git worktree remove ../hotfix-branchSave time by creating shortcuts for commands you use constantly.
git config --global alias.st "status"
git config --global alias.co "switch"
git config --global alias.cm "commit -m"
git config --global alias.lg "log --oneline --graph --all"
git config --global alias.last "log -1 HEAD --stat"
git config --global alias.unstage "restore --staged"After setting these up, git st replaces git status, git lg gives you a visual branch graph, and git unstage file.js removes a file from staging.
# Start a new feature
git switch main
git pull origin main
git switch -c feature/new-dashboard
# Work, commit, repeat
git add .
git commit -m "Add dashboard layout and data fetching"
# Stay up to date with main
git fetch origin
git rebase origin/main
# Push and create a pull request
git push -u origin feature/new-dashboard# You committed to main but meant to commit to a feature branch
git switch -c feature/accidental-work # create branch with current commits
git switch main
git reset --hard HEAD~1 # remove the commit from main# Squash all feature branch commits into one
git switch main
git merge --squash feature/messy-history
git commit -m "Add complete user authentication system"Git has hundreds of commands, but most daily work uses fewer than twenty. Learn the basics well, bookmark this cheat sheet for the advanced stuff, and don't be afraid to experiment — as long as you haven't force-pushed, almost everything in Git is reversible.
If you're writing scripts or code alongside your Git workflow, try the Code Playground to test snippets quickly, or the Markdown Editor for writing documentation and README files.
The best way to learn Git is to use Git. Create a throwaway repo, try every command on this page, break things, and fix them. That's how the knowledge sticks.