← Back to Blog

Git Commands Cheat Sheet 2026: Every Command You'll Actually Use

Git has hundreds of commands but you use around 20 of them daily. This cheat sheet covers every command you actually need - organized by workflow, with dangerous operations clearly marked and the lesser-known commands that will save you hours.

Why Every Developer Needs to Know Git Deeply

Git is the single tool that every software developer uses regardless of language, framework, or platform. Yet most developers learn just enough to get by: git add, git commit, git push, and then panic when something goes wrong. The gap between that basic knowledge and genuine Git fluency is what this guide fills.

The commands that separate confident Git users from anxious ones are not complicated. They are just rarely taught: interactive rebase to clean up messy history before a PR, git bisect to find a regression in minutes, git reflog to recover what looks like lost work. By the end of this guide you will have all of them.

Setup and Initial Configuration

Before your first commit, configure Git correctly. These settings affect every repository on your machine.

# Identity - required for every commit
git config --global user.name "Your Name"
git config --global user.email "you@example.com"

# Quality-of-life defaults
git config --global init.defaultBranch main         # new repos use 'main' not 'master'
git config --global pull.rebase true                # rebase instead of merge on pull
git config --global fetch.prune true                # auto-clean deleted remote branches
git config --global diff.algorithm histogram        # better diff output (less noise)
git config --global core.autocrlf input             # normalize line endings on macOS/Linux
git config --global rerere.enabled true             # remember conflict resolutions
git config --global push.autoSetupRemote true       # git push works on new branches without -u

# Set your preferred editor (VSCode shown)
git config --global core.editor "code --wait"

# Useful aliases
git config --global alias.lg "log --oneline --graph --all --decorate"
git config --global alias.st "status -sb"
git config --global alias.undo "reset HEAD~1 --mixed"

# Check all settings and where they come from
git config --list --show-origin

Everyday Commands

# Clone a repository
git clone git@github.com:user/repo.git
git clone --depth 1 git@github.com:user/repo.git       # shallow clone: only latest commit
git clone --branch develop git@github.com:user/repo.git # clone specific branch

# Check what changed
git status                        # what is staged, unstaged, untracked
git diff                          # unstaged changes (working tree vs index)
git diff --staged                 # staged changes (index vs last commit)
git diff main..feature            # diff between two branches
git diff HEAD~3                   # diff against 3 commits ago

# Stage and commit
git add file.js                   # stage a specific file
git add src/                      # stage an entire directory
git add -p                        # interactive staging: approve/reject hunks
git commit -m "fix: null pointer in auth middleware"
git commit --amend                # edit last commit message or add forgotten files
git commit --amend --no-edit      # amend without changing the message

# Remote operations
git push origin main
git push -u origin feature/auth   # push and set upstream tracking
git push --force-with-lease       # safer force push: fails if remote has new commits
git pull                          # fetch + rebase (if pull.rebase=true)
git fetch --all                   # download all remote changes without merging
git fetch origin main:main        # update local main without switching to it

Branching and Merging

# Create and switch branches
git checkout -b feature/auth-refactor    # old style
git switch -c feature/auth-refactor      # new style (Git 2.23+, preferred)
git switch main                          # switch to existing branch

# List branches
git branch                        # local branches
git branch -r                     # remote branches
git branch -a                     # all branches
git branch -v                     # branches with last commit
git branch --merged main          # branches already merged into main (safe to delete)
git branch --no-merged main       # branches NOT yet merged

# Merge
git merge feature/auth            # merge into current branch
git merge --no-ff feature/auth    # always create a merge commit (no fast-forward)
git merge --squash feature/auth   # squash all commits into one staged change, then commit

# Delete branches
git branch -d feature/auth        # safe delete (only if merged)
git branch -D feature/auth        # force delete (even if not merged)
git push origin --delete feature/auth    # delete remote branch
git branch -r | grep -v '\->' | while read remote; do git branch --track "${remote#origin/}" "$remote" 2>/dev/null; done  # track all remote branches

Rebase vs Merge: The Definitive Answer

Merge creates a new "merge commit" that ties together the histories of two branches. It preserves exactly when branches were integrated. Use merge when combining long-running branches where the integration history matters (e.g., merging a release branch into main).

Rebase rewrites commits to appear as if they were made on top of another branch, producing a perfectly linear history. Use rebase to update a feature branch with the latest main before opening a PR, or to clean up your local commits before they are shared. The golden rule: never rebase commits that have already been pushed to a shared branch.

# Keep feature branch up to date with main using rebase
git switch feature/auth
git fetch origin
git rebase origin/main            # replay your commits on top of latest main

# If conflicts arise during rebase:
git status                        # see conflicting files
# ...resolve conflicts in editor...
git add resolved-file.js
git rebase --continue             # continue to next commit
# Or to abort and return to the original state:
git rebase --abort

# Interactive rebase: squash, reorder, edit, drop commits before PR
git rebase -i HEAD~5              # interactively edit the last 5 commits
# In the editor, change 'pick' to:
# squash  (s) - combine with previous commit
# fixup   (f) - combine with previous, discard message
# reword  (r) - edit the commit message
# drop    (d) - delete this commit entirely
# edit    (e) - pause and amend this commit

Undoing Mistakes

This section covers the commands most people desperately search for at 2am. None of these are as scary as they look.

# Discard changes to a file (unstaged, working tree)
git restore file.js               # new syntax (Git 2.23+)
git checkout -- file.js           # old syntax

# Unstage a file (keep the changes, just remove from staging area)
git restore --staged file.js      # new syntax
git reset HEAD file.js            # old syntax

# Undo last commit but keep changes (staged)
git reset --soft HEAD~1

# Undo last commit and keep changes (unstaged, back in working tree)
git reset HEAD~1                  # same as --mixed (the default)

# Undo last commit and DISCARD all changes permanently
git reset --hard HEAD~1           # WARNING: this is irreversible (mostly)

# Undo a commit that was already pushed (creates a new revert commit - safe for shared branches)
git revert abc1234                # reverts the specified commit
git revert HEAD~3..HEAD           # revert the last 3 commits

# Recover commits after a hard reset (the safety net)
git reflog                        # shows all recent HEAD positions with hashes
git checkout abc1234              # detached HEAD at the lost commit
git switch -c recovery-branch     # save it as a new branch

The reflog is your ultimate safety net. Git keeps a record of every position HEAD has pointed to for 30 days. Even after reset --hard, your commits are not gone - they are just unreferenced. git reflog finds them. This is the most important Git command most developers do not know about.

Stashing

Stash saves your work in progress so you can switch branches without committing half-done code.

# Save and restore work in progress
git stash                          # stash tracked modified files
git stash -u                       # include untracked files
git stash push -m "WIP: half-done auth refactor"  # with a descriptive name
git stash push -- src/auth.js      # stash a specific file only

# Manage stashes
git stash list                     # list all stashes (stash@{0} is most recent)
git stash show -p stash@{0}        # show the diff of a stash
git stash pop                      # restore most recent stash and delete it
git stash apply stash@{2}          # restore specific stash without deleting
git stash drop stash@{0}           # delete a specific stash
git stash clear                    # delete all stashes (irreversible)

Cherry-Pick: Apply Specific Commits

# Apply a specific commit to the current branch
git cherry-pick abc1234            # apply one commit
git cherry-pick abc1234..def5678   # apply a range (exclusive of first, inclusive of last)
git cherry-pick abc1234 def5678 ghi9012  # apply multiple specific commits
git cherry-pick --no-commit abc1234  # apply changes without creating a commit

Git Bisect: Find the Commit That Broke Things

When you know a bug exists but do not know which commit introduced it, git bisect performs a binary search through history to find it automatically. On a project with 1000 commits it narrows the problem to the exact offending commit in around 10 steps.

git bisect start
git bisect bad                     # current commit has the bug
git bisect good v1.2.0             # this tag/commit did not have the bug

# Git checks out a middle commit. Run your test, then mark it:
git bisect good                    # this commit is fine
git bisect bad                     # this commit has the bug

# Repeat ~10 times. Git tells you: "abc1234 is the first bad commit"
git bisect reset                   # done, return to original HEAD

# Automate with a test script (returns 0 for good, non-zero for bad)
git bisect run npm test

Log and History Exploration

# Useful log formats
git log --oneline --graph --all --decorate   # visual branch history (alias: git lg)
git log --since="2 weeks ago"                # commits from the last 2 weeks
git log --author="Jane"                      # commits by a specific author
git log -p -- src/auth.js                    # all changes to a specific file
git log -S "functionName"                    # search for commits that added/removed text
git log --grep="JIRA-1234"                   # search commit messages
git log --pretty=format:"%h %ad %an %s" --date=short  # custom format
git shortlog -sn                             # commit count by author

# Blame: who last modified each line
git blame src/auth.js
git blame -L 50,75 src/auth.js              # specific line range
git log -L 50,75:src/auth.js               # history of a specific line range

Tags

# Create tags for releases
git tag v1.2.0                     # lightweight tag (just a pointer)
git tag -a v1.2.0 -m "Release 1.2.0: adds OAuth support"  # annotated tag (preferred)
git tag -a v1.2.0 abc1234 -m "Release 1.2.0"  # tag a specific past commit

# List and push tags
git tag                            # list all tags
git tag -l "v1.*"                  # filter tags by pattern
git push origin v1.2.0             # push a specific tag
git push origin --tags             # push all tags
git push origin --delete v1.2.0    # delete a remote tag

Commit Message Convention

Most teams use Conventional Commits to standardize messages and enable automated changelogs and semantic versioning:

feat: add OAuth2 authentication via Google
fix: resolve null pointer exception in payment webhook handler
docs: update API reference for v3 pagination endpoints
refactor: extract email validation into shared utility module
perf: optimize user search query (3x faster with index hint)
test: add integration tests for the checkout flow
chore: upgrade all dependencies to latest minor versions
ci: add Docker image scanning to GitHub Actions workflow

Format: type(optional scope): short description. Keep the first line under 72 characters. Add a blank line and then a longer body if the change needs explanation. Mark breaking changes with ! after the type (feat!:) or a BREAKING CHANGE: footer.

Scan Your Site for Free

Our Exposure Checker runs 19 parallel security checks - SSL, headers, exposed paths, DNS, open ports, and more.

Run Free Security Scan

Frequently Asked Questions

What is the difference between git fetch and git pull?

git fetch downloads changes from the remote repository into your local remote-tracking branches (e.g., origin/main) but does not touch your working branch. It is always safe. git pull is git fetch followed by git merge (or git rebase if configured). Running git fetch --all first to inspect what changed before merging is a good habit, especially on active repositories.

How do I undo a git push to a shared branch?

Use git revert, not git reset. git revert abc1234 creates a new commit that undoes the changes from that commit without rewriting history. Everyone who has already pulled the branch continues to work without issue. A git reset --hard followed by a force push rewrites history and will break the local repos of anyone who pulled the reverted commits - only do this on your personal feature branches before they are reviewed.

What does git reset --soft vs --mixed vs --hard do?

All three move the current branch pointer to a different commit. What differs is what happens to the changes: --soft keeps all changes staged (ready to recommit). --mixed (the default) keeps all changes in the working tree but unstages them. --hard discards all changes in staging and working tree permanently. A useful mnemonic: soft = just move the pointer, mixed = move + unstage, hard = move + delete everything.

When should I rebase vs merge?

Rebase your local feature branch onto the latest main before opening a pull request - it makes the PR diff clean and ensures no merge conflicts. Use merge when integrating pull requests into main (or let the platform do it). Never rebase a branch that other developers are working on, because you are rewriting the commits they have based their work on, which forces them to resolve complex conflicts.

How do I remove a file from git history entirely?

This is a history-rewriting operation - treat it with care. The modern tool is git filter-repo (install separately). Run git filter-repo --path secrets.txt --invert-paths to remove the file from every commit in history. After rewriting, force-push to all remotes and notify all collaborators to re-clone the repository. Note: if the secret was pushed to GitHub, also rotate the credential - it may be cached in forks, stars, or third-party mirrors.

What is the best Git branching strategy in 2026?

For most teams, GitHub Flow (short-lived feature branches + pull requests into main + deploy from main) hits the right balance of simplicity and safety. Gitflow (with develop, release, and hotfix branches) adds complexity that teams rarely need unless they maintain multiple versions simultaneously. The key principles regardless of strategy: keep feature branches short-lived (days, not weeks), require code review before merge, automate CI on every branch, and deploy frequently to reduce the blast radius of each change.

The Bottom Line

Git fluency pays compound returns over a career. The commands that feel intimidating - rebase, bisect, reflog, reset - become second nature with a little practice, and they will save you hours of confused debugging and anxious googling. When you are stuck: git status to understand the current state, git stash to clear the deck, and git reflog to find what you think you lost.

Use our free tool here → Diff Checker to compare code versions side by side.

UK
Written by Usman Khan
DevOps Engineer | MSc Cybersecurity | CEH | AWS Solutions Architect

Usman has 10+ years of experience securing enterprise infrastructure, managing high-traffic servers, and building zero-knowledge security tools. Read more about the author.