Most developers use Git every day, but most use only a fraction of its power. You know git add, git commit, git push. But when you need to untangle a messy rebase, recover a lost commit from the reflog, binary-search a bug with bisect, or set up Git hooks that enforce commit message conventions, the everyday commands fall short. Our free Git Commands Expansion Cheat Sheet fills this gap. It covers one hundred and twenty commands across ten categories — everything from repository initialization to advanced recovery tools. Every entry is interactive, searchable, and one click away from your clipboard. No signup, no tracking, entirely client-side.
Why Developers Need an Expansion Reference
The Git manual is over eight hundred pages. Memorizing it is neither practical nor necessary. What you need is a reference that surfaces the right command at the right moment — the flag you forgot, the workflow you use once a month, the recovery procedure you hope you will never need.
A basic Git cheat sheet answers: "How do I create a branch?" An expansion cheat sheet answers: "How do I split a commit during interactive rebase?" "How do I cherry-pick a range of commits without merge conflicts?" "How do I configure a pre-push hook that runs the full test suite?" These are the questions that separate developers who use Git from those who truly understand it.
Our Git Commands Expansion Cheat Sheet is themed "The Git Geologist's Stratigraphy Lab" — a deep-earth archaeological aesthetic with stratified mineral layers, floating dust motes, and specimen catalog cards. Each of the ten categories maps to a distinct mineral crystal color: Gold for Setup, Malachite green for Staging, Copper for Branching, Amethyst for History, Cinnabar red for Undo, Azurite blue for Stashing, Silver for Remotes, Quartz for Rebasing, Iron for Advanced Tools, and Obsidian for Hooks. The metaphor is intentional: Git commits are geological strata, and navigating them requires the same precision as excavating a fossil bed.
Repository Setup and Configuration: The Foundation Layer
Before any code enters version control, someone must initialize the repository and configure its behavior. These commands are used once per project but shape every subsequent operation.
Initializing and Cloning
git init creates a new repository in the current directory. It writes a .git subdirectory containing all the plumbing: the object database, refs, hooks templates, and configuration. For a central server repository that accepts pushes, use git init --bare — this creates a repository without a working tree, which is required because pushing to a non-bare repository causes errors.
git clone is how you obtain an existing repository. The basic form downloads the entire history:
git clone https://github.com/user/repo.git For large repositories with years of history, a shallow clone saves time and bandwidth:
git clone --depth 1 https://github.com/user/repo.git The --depth 1 flag downloads only the latest commit. Shallow clones are ideal for CI pipelines that only need the current state. To clone a specific branch without fetching others:
git clone --branch develop --single-branch https://github.com/user/repo.git Configuration Management
Git configuration has three scopes: local (repository-specific, stored in .git/config), global (user-specific, stored in ~/.gitconfig), and system (machine-wide, stored in /etc/gitconfig). Local overrides global, which overrides system.
Set your identity for commit attribution:
git config user.name "Your Name"
git config user.email "email@example.com" Configure essential behaviors globally:
git config --global core.editor "code --wait"
git config --global pull.rebase true
git config --global push.default current The pull.rebase true setting makes git pull use rebase instead of merge by default — this keeps your history linear. The push.default current setting pushes the current branch to a remote branch with the same name, which is usually what you want.
Aliases are productivity multipliers. A few keystrokes saved across thousands of commands adds up:
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.st status
git config --global alias.lg "log --graph --oneline --all" Remote Management
git remote add connects your local repository to a remote:
git remote add origin https://github.com/user/repo.git If a remote URL changes — for example, when a repository is renamed or migrated — update it without re-cloning:
git remote set-url origin git@github.com:new-org/repo.git To see all configured remotes with their URLs:
git remote -v Staging and Commits: The Deposition Layer
Git's staging area is its most distinctive feature. Unlike other version control systems that commit everything that has changed, Git lets you craft exactly what goes into each commit. This fine-grained control is the foundation of a clean, readable history.
Understanding the Staging Area
git status is your constant companion. It shows three categories of files: changes to be committed (staged), changes not staged for commit (modified but unstaged), and untracked files. The short format (git status -s) is ideal for scripting and for fitting more information on screen.
git add stages changes. Its most powerful variant is patch mode:
git add -p Patch mode walks you through each change hunk and asks: stage this hunk? (y/n). You can split hunks (s), edit them (e), or skip them (n). This means you can make three logical commits from a single file's changes without ever leaving the command line.
To stage everything — modifications, deletions, and new files — in one command:
git add -A Writing Good Commits
A commit is not just a save point. It is a communication tool. git commit -m is for short, single-line messages. For anything more complex — and most commits should be — omit -m to open your editor:
git commit The convention for commit messages: a short summary line (50 characters or fewer), a blank line, and a detailed explanation of what changed and why. The summary line should complete the sentence "This commit will...". Write in the imperative: "Fix login validation bug" not "Fixed login validation bug".
If you forgot to include a file or need to fix a typo in the last commit:
git add forgotten-file.txt
git commit --amend --no-edit The --amend flag rewrites the last commit to include the newly staged changes. The --no-edit flag keeps the original commit message. This rewrites history, so never amend a commit that has been pushed to a shared branch.
Inspecting Changes
git diff shows unstaged changes. git diff --staged shows staged changes. Understanding the difference is critical:
git diff # what did I change but not yet stage?
git diff --staged # what will go into the next commit?
git diff HEAD~1 # how does this commit differ from the last? To remove a tracked file and stage the deletion:
git rm file.txt To move or rename a file while preserving its history:
git mv old-name.js new-name.js Branching and Merging: The Fork Layer
Branching is Git's superpower. Branches are lightweight — just a pointer to a commit — which makes them cheap to create and merge. This enables workflows like feature branching, where every feature, bug fix, or experiment gets its own isolated timeline.
Branch Operations
Create branches, list them, and delete them:
git branch feature/new-login # create
git branch # list local
git branch -a # list all including remotes
git branch -d feature/old-login # safe delete (only if merged)
git branch -D feature/broken # force delete The modern way to switch branches (Git 2.23+) uses git switch:
git switch main # switch to existing branch
git switch -c feature/experiment # create and switch The traditional git checkout still works and is more widely known:
git checkout develop
git checkout -b feature/experiment Merging Strategies
A merge joins two development histories:
git checkout main
git merge feature/completed By default, Git uses a fast-forward merge if possible — it simply moves the branch pointer forward without creating a merge commit. This produces a linear history but loses the information that a branch existed. Use --no-ff to force a merge commit:
git merge --no-ff feature/completed When conflicts arise, Git marks the conflicting regions in the affected files with <<<<<<<, =======, and >>>>>>>. After resolving them:
git add resolved-file.txt
git merge --continue If the conflicts are too complex and you want to start over:
git merge --abort For a squash merge — combining all commits from a feature branch into a single commit on main:
git merge --squash feature/completed
git commit -m "Add user authentication feature" Squash merges keep the main branch's history clean. The tradeoff is losing the granular commit history from the feature branch. This is the GitHub default for pull request merges.
History and Logs: The Stratigraphy Layer
Git's history is a directed acyclic graph of commits. Navigating it efficiently requires knowing the right log flags. The default git log output is verbose and rarely what you want.
Essential Log Formats
The most useful log format for daily use:
git log --graph --oneline --all --decorate This shows every branch and tag as an ASCII graph with one line per commit. Many developers alias this to git lg.
To see the full diff for recent commits:
git log -p -2 Filter by author, date range, or commit message:
git log --author="Jane" --since="2 weeks ago" --oneline
git log --grep="fix" --oneline Searching Through History
The pickaxe search (-S) finds commits that added or removed a specific string. This is invaluable for answering "when was this function introduced or removed?":
git log -S "deprecated_function" --oneline git blame annotates each line of a file with the commit that last modified it, along with the author and date:
git blame src/main.js For a specific line range:
git blame -L 10,50 src/main.js git show displays the full details of any Git object — most commonly a commit:
git show HEAD~3 # show the 4th most recent commit
git show abc1234 # show a specific commit
git show --stat HEAD # show commit with file change summary git shortlog groups commits by author, useful for release notes:
git shortlog -sn # commit counts by author
git shortlog v1.0..v2.0 # commits between two tags Undoing Changes: The Excavation Layer
Mistakes happen. Git provides multiple levels of undo, from gentle to destructive. Knowing which tool to use — reset, revert, restore, or clean — is essential for working safely.
Reset: Rewinding the Branch Pointer
git reset moves the current branch pointer and optionally modifies the staging area and working tree. It comes in three modes:
git reset --soft HEAD~1 # undo commit, keep changes staged
git reset --mixed HEAD~1 # undo commit, unstage changes (default)
git reset --hard HEAD~1 # undo commit, discard all changes (DESTRUCTIVE) --soft is safest: it undoes the commit but leaves your changes staged, ready to re-commit. --hard discards changes permanently — use it only on private branches and only when you are certain.
To unstage a specific file without losing work:
git reset HEAD file.txt Revert: Safe Undo for Shared History
For commits that have already been pushed, git reset rewrites history and will cause conflicts for collaborators. Use git revert instead:
git revert HEAD Revert creates a new commit that undoes the specified commit. It does not erase history — it adds to it. This is always safe for shared branches. To revert a range of commits in a single commit:
git revert --no-commit HEAD~3..HEAD
git commit -m "Revert last 3 commits" Restore: Modern File-Level Undo
git restore (Git 2.23+) provides a clearer interface for file-level undo. It replaces the overloaded git checkout -- file and git reset HEAD file:
git restore file.txt # discard working tree changes
git restore --staged file.txt # unstage but keep changes
git restore --source HEAD~2 file.txt # restore file to version from 2 commits ago Clean: Removing Untracked Files
git clean removes untracked files — generated build artifacts, editor temp files, test outputs. Always dry-run first:
git clean -n # show what would be removed
git clean -fd # force remove untracked files and directories Stashing: The Temporary Storage Layer
Stashing is Git's context-switching mechanism. You are halfway through a feature, and a critical hotfix comes in. Instead of making a half-baked commit or losing work, stash your changes, switch branches, fix the issue, and pop the stash when you return.
git stash # stash tracked changes
git stash push -m "WIP: auth refactor" # stash with message
git stash -u # stash including untracked files
git stash list # see all stashes Stashes form a stack. The most recent is stash@0:
git stash pop # apply and remove top stash
git stash pop stash@{2} # apply and remove a specific stash
git stash apply # apply without removing
git stash drop stash@{0} # delete without applying To inspect what is inside a stash before applying it:
git stash show -p stash@{0} To recover a stash as a new branch (useful if the original branch has changed significantly):
git stash branch feature/recover stash@{0} When you are certain you will never need any stashed changes again:
git stash clear Remote Operations: The Distributed Layer
Git is a distributed version control system. Every clone is a full backup of the repository. Remote operations synchronize these independent copies.
Fetching Without Merging
git fetch downloads objects and refs from a remote without modifying your working tree or branches. This is the safe first step — see what has changed before deciding how to integrate it:
git fetch origin
git fetch --all
git fetch --prune # also remove tracking branches deleted on remote Pulling: Fetch and Integrate
git pull is git fetch followed by git merge (or git rebase with --rebase):
git pull origin main
git pull --rebase origin main The --rebase flag produces a linear history by replaying your local commits on top of the remote ones. This avoids unnecessary merge commits and is the preferred workflow for many teams.
Pushing: Sharing Your Work
git push uploads your commits to a remote:
git push origin main
git push -u origin feature/new-feature # push and set upstream tracking
git push --tags # push all local tags If you need to force-push — for example, after amending a commit or rebasing a feature branch — use --force-with-lease instead of --force:
git push --force-with-lease origin main --force-with-lease checks that the remote branch hasn't changed since you last fetched. If someone else pushed in the meantime, the force push is rejected. This prevents accidentally overwriting a collaborator's work.
Remote Maintenance
Clean up stale remote-tracking branches:
git remote prune origin Get detailed information about a remote's branches and configuration:
git remote show origin Rebasing: The History Rewriting Layer
Rebasing is Git's most powerful — and most dangerous — history manipulation tool. It rewrites commit history to create a cleaner, more logical narrative.
Basic Rebase
A standard rebase replays the current branch's commits on top of another branch:
git checkout feature
git rebase main This makes it appear as if the feature branch was created from the latest commit on main. The resulting history is linear, with no merge commits. Use this before opening a pull request to ensure a clean merge.
If conflicts occur during a rebase, resolve them and continue:
git add resolved-file.txt
git rebase --continue To abort and return to the pre-rebase state:
git rebase --abort Interactive Rebase: Editing History
Interactive rebase is where Git's power truly shows. It opens an editor listing the last N commits and lets you reorder, squash, edit, split, or drop them:
git rebase -i HEAD~5 The editor shows each commit with the default action pick. Change pick to:
- squash or s: meld this commit into the previous one, combining messages
- fixup or f: like squash but discard this commit's message
- reword or r: change the commit message
- edit or e: stop for amending
- drop or d: remove this commit entirely
The autosquash workflow makes cleaning up fixup commits effortless:
git commit --fixup HEAD~3 # create a fixup targeting commit 3 back
git rebase -i --autosquash HEAD~10 # automatically reorder and squash Transplanting Commits with --onto
git rebase --onto is surgical. It moves a range of commits from one base to another:
git rebase --onto main feature/old-base feature/topic This takes the commits on feature/topic that are not on feature/old-base and replays them on top of main. Use this when a feature was built on the wrong base branch.
Cherry-Pick: Selective Commit Transfer
Cherry-pick applies a specific commit to the current branch without merging the entire history:
git cherry-pick abc1234 For multiple commits:
git cherry-pick abc1234..def5678 To cherry-pick without auto-committing (useful for combining multiple picks into one commit):
git cherry-pick -n abc1234 Cherry-pick shines when you need to backport a bug fix to a release branch without merging all the other changes from the development branch.
Advanced Tools: The Laboratory Layer
These commands solve specific, complex problems. You may not use them daily, but when you need them, nothing else will do.
Bisect: Binary Search for Bugs
git bisect performs a binary search through your commit history to identify exactly which commit introduced a regression:
git bisect start
git bisect bad # current commit has the bug
git bisect good v1.0 # v1.0 was known good Git checks out a commit at the midpoint. Test it. If the bug is present, mark it bad. If not, mark it good. Git narrows the range by half each time. After roughly log2(N) steps, Git identifies the problematic commit.
Automate this with a test script:
git bisect run npm test The script should exit 0 for good (no bug) and any code from 1 to 127 for bad. After bisect finishes, return to normal:
git bisect reset Reflog: The Commit Safety Net
The reflog records every position your HEAD has visited — commits, resets, rebases, merges, checkouts. It is your undo for commands that seem irreversible:
git reflog Even if you delete a branch or git reset --hard past a commit, the reflog retains the SHA. To recover a lost commit:
git checkout -b recovered-branch <SHA-from-reflog> Reflog entries expire after 90 days by default for unreachable commits. For critical repositories, consider extending this:
git config gc.reflogExpire 180.days Worktree: Parallel Development
git worktree lets you check out multiple branches simultaneously in separate directories — all sharing the same repository data:
git worktree add ../hotfix hotfix/critical
git worktree add ../feature feature/new-module Now you can work on the hotfix in ../hotfix and the feature in ../feature without stashing or switching branches. This is faster than the traditional stash-switch-work-commit-switch-pop cycle and dramatically reduces context-switching friction.
git worktree list # see all linked worktrees
git worktree remove ../hotfix # clean up when done Submodule Management
Submodules embed external repositories inside your project:
git submodule add https://github.com/lib/dep.git libs/dep After cloning a project with submodules, initialize and fetch them:
git submodule update --init --recursive To update submodules to their latest remote commits:
git submodule update --remote Git Grep: Fast Code Search
git grep searches the working tree using Git's internal engine. It is faster than system grep for large codebases because it uses Git's index:
git grep "TODO"
git grep -n "FIXME" -- "*.js"
git grep -i "error" -- "src/**/*.ts" Hooks and Configuration: The Automation Layer
Git hooks are executable scripts that trigger at specific points in the Git workflow. They enforce standards, run checks, and automate repetitive tasks — all without external tooling.
Client-Side Hooks
The most impactful hooks for daily development:
pre-commit — runs before a commit is created. Use for linting, formatting, and fast tests:
#!/bin/sh
# .git/hooks/pre-commit
npm run lint && npm test -- --onlyChanged commit-msg — validates commit message format. Enforce conventional commits:
#!/bin/sh
# .git/hooks/commit-msg
grep -qE "^(feat|fix|docs|style|refactor|test|chore)" "$1" || {
echo "Commit message must start with a conventional commit type"
exit 1
} pre-push — runs before a push. Use for the full test suite and security checks:
#!/bin/sh
# .git/hooks/pre-push
npm run test:full && npm audit post-merge — runs after a successful merge. Ideal for dependency updates:
#!/bin/sh
# .git/hooks/post-merge
npm install Git Attributes and Ignore Rules
.gitignore tells Git which files to exclude from tracking entirely:
# .gitignore
node_modules/
.env
*.log
dist/
.DS_Store .gitattributes defines per-path behaviors — line ending normalization, diff drivers, merge strategies:
# .gitattributes
*.js text eol=lf
*.png binary
*.md diff=markdown
*.lock merge=binary To debug why a file is being ignored:
git check-ignore -v dist/bundle.js Repository Maintenance
Over time, Git repositories accumulate loose objects and unnecessary files. Periodic maintenance keeps performance acceptable:
git gc --aggressive --prune=now git fsck verifies the integrity of the object database:
git fsck --full Tags: Marking Release Points
Tags are permanent references to specific commits, typically used for version releases:
git tag v1.0.0 # lightweight tag
git tag -a v1.0.0 -m "First stable release" # annotated tag
git tag -l "v2.*" # list matching tags Annotated tags include a message, author, and date — they are full Git objects. Always use annotated tags for releases. Lightweight tags are just pointers and should be reserved for temporary or private use.
Putting It All Together: A Production Workflow
Here is a realistic workflow that combines many of the commands covered above. You are working on a feature, and a hotfix comes in:
# Save your in-progress work
git stash push -m "WIP: user dashboard refactor"
# Create and work on the hotfix
git switch main
git pull --rebase origin main
git switch -c hotfix/critical-bug
# ... fix the bug ...
git add -p # stage only the relevant changes
git commit -m "Fix null pointer in payment processing"
git push -u origin hotfix/critical-bug
# Return to your feature
git switch feature/dashboard
git stash pop
# Before merging, clean up your branch history
git fetch origin
git rebase -i origin/main # squash fixup commits, reword messages
git push --force-with-lease origin feature/dashboard This workflow uses stashing for context switching, patch staging for precise commits, interactive rebase for history cleanup, and force-with-lease for safe force-pushing. Every command serves a purpose, and each builds on the foundation of the core Git model: a directed acyclic graph of commits.
Explore More DevToolkit Git References
The Git Commands Expansion Cheat Sheet is part of a growing ecosystem of developer reference tools. For related resources, explore:
- Git Advanced Patterns Cheat Sheet — 65+ advanced Git patterns and workflows with the Time Cartographer's Archive aesthetic
- Docker Commands Expansion Cheat Sheet — 120+ Docker commands across 10 categories
- Kubernetes Commands Cheat Sheet — 120+ kubectl and Helm commands
- DevOps Commands Cheat Sheet — 75+ DevOps CLI commands across 6 categories
- Bash Scripting Advanced Patterns Cheat Sheet — 70+ bash scripting patterns
- Regex Tester — Interactive regular expression testing tool
- JSON Formatter — Format, validate, and prettify JSON
All tools are free, interactive, and 100% client-side. No signup required. Bookmark the ones you use most.