DS DevShelfHub Projects · AI tools
Cheatsheets / Git
Cheatsheet · Dev tooling

Git Cheatsheet: Branches, Rebase and Recovery Reference

By DevShelfHub

Branching, rebasing, fixing mistakes, recovering lost commits, interactive rebase, worktrees — the commands you reach for under pressure.

97 items ◷ 7 min Branches Rebase Recovery

Start hereQuick start · 6 you’ll reach for daily

Statusgit status -sb
Switch branchesgit switch -c name
Stage hunksgit add -p
Sync trunkgit pull --rebase
Tidy historygit rebase -i HEAD~5
Safe pushgit push --force-with-lease

Target versions · paceVersions

Targets: git ≥ 2.40 default branch: main switch / restore

switch and restore are the modern split of the old checkout monster — this sheet prefers them. checkout still works for everything.

identity · defaults · aliasesSetup

bash
# Identity (per-user; --global flag)
git config --global user.name  "Ada Lovelace"
git config --global user.email "ada@example.com"
git config --global init.defaultBranch main
git config --global pull.rebase true             # cleaner history on `git pull`
git config --global rebase.autoStash true        # auto-stash on rebase

# Helpful shortcuts
git config --global alias.lg  "log --oneline --graph --decorate --all"
git config --global alias.s   "status -sb"
git config --global alias.last "log -1 --stat"

# Per-repo overrides
git config user.email "work@example.com"          # local to this repo

# View / drop config
git config --list --show-origin
git config --global --unset pull.rebase

init · clone · remotesRepos & remotes

git initNew repo in cwd.
git clone URLClone into a directory named after the repo.
git clone URL --depth 1Shallow clone. Faster, no history.
git clone URL --filter=blob:nonePartial clone. Fetches blobs on demand.
git remote -vList remotes + URLs.
git remote add upstream URLAdd a second remote (e.g. fork upstream).
git remote set-url origin URLChange remote URL (SSH ↔ HTTPS).
git fetch --all --pruneSync all remotes; drop stale tracking branches.

working tree · indexStaging & commits

git status -sbCompact status with branch line.
git add <path>Stage specific paths.
git add -pInteractive hunk staging. Splits, reviews, edits.
git add -AStage everything (new + modified + deletes).
git restore --staged <path>Unstage. Keeps working-tree changes.
git restore <path>Discard working-tree changes. Destructive.
git commit -m "msg"Commit staged changes.
git commit -am "msg"Stage + commit tracked changes in one go.
git commit --amendRewrite last commit. Don’t use after pushing without --force-with-lease.
git commit --fixup <sha>Marker commit auto-squashed by rebase -i --autosquash.
git stash push -m "wip"Save working-tree to a stack.
git stash list / pop / dropShow, restore, delete entries.
git stash push -kKeep staged changes; stash only unstaged.

switch · restore · trackBranching

git branchList local branches.
git branch -aInclude remote-tracking.
git branch -vvShow upstream + last commit per branch.
git switch mainPreferred Change branch.
git checkout mainLegacy Same idea; also does paths + commits.
git switch -c feat/xCreate + switch in one step.
git switch -c feat/x origin/mainBranch from a specific ref.
git branch -d feat/xDelete merged branch (safe).
git branch -D feat/xForce-delete (loses unmerged work).
git branch -m old newRename a branch.
git push origin --delete feat/xDelete remote branch.
git push -u origin feat/xFirst push + set upstream.

log · diff · blameInspecting

git log --oneline -n 20Last 20 commits, compact.
git log --graph --oneline --all --decorateASCII history graph. Save as alias lg.
git log -p <path>History with diffs for a path.
git log --grep="regex"Search commit messages.
git log -S"substr"Find commits adding/removing a literal string (pickaxe).
git log --author=adaFilter by author.
git log main..feat/xCommits on feat/x not yet in main.
git diffUnstaged changes.
git diff --stagedStaged changes (what will commit).
git diff main...feat/xBranch-diff from common ancestor.
git diff --statPer-file summary.
git show <sha>Commit metadata + diff.
git blame -L 42,60 -- fileWho touched lines 42–60 and when.
git shortlog -snCommit counts per author.

reset · revert · restoreUndoing

git restore <path>Discard working-tree changes. Destructive.
git restore --staged <path>Unstage. Keeps the working-tree edits.
git restore --source=main <path>Copy a path from another ref.
git reset --soft HEAD~1Uncommit; keep changes staged.
git reset --mixed HEAD~1Uncommit; unstage. Working tree untouched.
git reset --hard HEAD~1Uncommit + discard. Destructive.
git revert <sha>Create a new commit that undoes <sha>. Safe on shared branches.
git clean -ndDry-run: list untracked files + dirs that would be deleted.
git clean -fdDelete untracked files + dirs. Destructive.
Reset rewrites; revert appends. Use revert on anything you’ve already pushed to a shared branch. Reserve reset for branches only you own.

replay · squash · reorderRebasing

git rebase mainReplay current branch on top of main.
git rebase origin/mainReplay onto the latest fetched trunk.
git rebase -i HEAD~5Interactive: reword / squash / fixup / drop.
git rebase -i --autosquash HEAD~10Auto-apply --fixup markers.
git rebase --onto base from toSurgical re-anchor. Move commits between branches.
git rebase --continue / --skip / --abortDrive a paused rebase.
git merge --no-ff feat/xMerge with a merge commit even if fast-forward is possible.
git merge --abortBack out of a conflicting merge.
git push --force-with-leasePreferred Safe force-push. Refuses if remote moved.
git push --forceLegacy Overwrites unconditionally. Avoid.
bash
# Rebase your branch onto the latest main
git fetch origin
git rebase origin/main             # replay your commits on top of origin/main

# If a conflict pops up:
#   1) fix files
#   2) git add 
#   3) git rebase --continue
# or bail:
git rebase --abort

# Interactive rebase: squash/edit/reorder the last N commits
git rebase -i HEAD~5
# In the editor — change "pick" to:
#   r  reword   – edit commit message
#   s  squash   – fold into previous, keep both messages
#   f  fixup    – fold into previous, discard message
#   e  edit     – stop to amend
#   d  drop     – delete this commit

# Force-push safely (refuses if remote moved since you pulled)
git push --force-with-lease origin my-branch

reflog · fsckRecovery

git reflogEvery HEAD move, last ~90 days. Your safety net.
git reflog show <ref>Reflog for a specific ref.
git checkout HEAD@{2}Time-travel via reflog index.
git branch rescue <sha>Recreate a deleted branch.
git fsck --lost-foundFind dangling objects after a hard reset.
git cherry-pick <sha>Replay a single commit onto your branch.
git bisect start / good / badBinary search for a regression.
bash
# I just blew away a branch / commit — can I get it back?
git reflog                              # every HEAD move, last ~90 days
git reflog show my-branch               # ref-specific reflog
git checkout -b rescue HEAD@{2}         # recreate from the 2-step-old HEAD
git branch my-branch               # or restore by sha

# I committed to the wrong branch
git log --oneline -n 3                  # note the sha
git reset --soft HEAD~1                 # uncommit but keep changes staged
git switch other-branch
git commit -m "..."                     # commit there instead

# I committed secrets — purge from history (destructive)
git filter-repo --invert-paths --path secrets.env
# Then notify the team; everyone re-clones.

# I want to see who broke a line, when, and why
git blame -L 42,60 -- src/foo.py
git log -p -L 42,60:src/foo.py          # line-range history with diffs

multiple checkouts, one repoWorktrees

git worktree add ../app-hotfix hotfix/xCheckout a branch in a sibling dir.
git worktree listAll worktrees + their refs.
git worktree remove ../app-hotfixRemove a worktree.
git worktree pruneClean up after manual deletion.
Worktrees beat stash for context-switching. Spawn a separate dir for the hotfix, leave your feature branch dirty. No stash juggling, no “wait, did I commit the right thing?”.

releases · markersTags

git tagList tags.
git tag -a v1.0.0 -m "Release v1"Annotated tag (preferred for releases).
git tag -s v1.0.0 -m "…"Signed annotated tag.
git tag v1.0.0 <sha>Tag a specific commit.
git push origin v1.0.0Push one tag.
git push origin --tagsPush all local tags. Use sparingly.
git tag -d v1.0.0 && git push origin :v1.0.0Delete local + remote.
git describe --tags --abbrev=0Most recent tag reachable from HEAD.

repos inside reposSubmodules

git submodule add URL pathAttach a sub-repo.
git clone --recurse-submodules URLClone + initialise submodules.
git submodule update --init --recursiveAfter an existing clone.
git submodule update --remoteMove each submodule to its tracked branch tip.
git submodule foreach 'git pull'Run a command in every submodule.
git config --global submodule.recurse trueMake pull / checkout submodule-aware by default.
Submodules pin a sub-repo to an exact commit. Updating means a new commit in the parent repo that records the new sub-commit — reviewers see the SHA bump, not the contents.

feature branch → merged PREnd-to-end · Feature branch loop

Branch off, hack, tidy with an interactive rebase, sync, push, post-merge cleanup. The loop you’ll repeat hundreds of times.

bash
# Full feature-branch loop with rebase + squash + safe push.

# 1 · Sync main, branch off
git switch main
git pull --rebase
git switch -c feat/cart-discounts

# 2 · Hack hack hack
$EDITOR src/cart.py
git add -p                        # stage hunks selectively
git commit -m "Add discount calc"

# 3 · Before opening the PR — tidy history + sync
git fetch origin
git rebase -i origin/main         # squash WIP commits

# 4 · Push and open a PR
git push -u origin feat/cart-discounts --force-with-lease

# 5 · After review, sync once more before merge
git fetch origin
git rebase origin/main
git push --force-with-lease

# 6 · After merge, prune local state
git switch main
git pull --rebase
git branch -d feat/cart-discounts        # safe delete (refuses if unmerged)
git fetch --prune                        # drop stale origin/* refs

Best practiceGood to know

Use --force-with-lease, never --force. Plain --force overwrites whatever the remote has now — including a colleague’s commit you didn’t pull. --force-with-lease refuses if the remote moved.
Reflog is your seatbelt. Almost nothing is truly lost for ~90 days. Before reaching for git reset --hard, remember git reflog exists.
Commit small, then rewrite history before pushing. Free-text the first pass, rebase -i the cleanup. Reviewers see clean commits; you don’t lose the trail of your own thinking.

Common trapsWatch out for

Don’t rebase a branch others are based on. Rewriting shared history forces everyone else to either re-clone or run a tricky rebase --onto. Revert in place instead, or coordinate explicitly.
git pull defaults to a merge commit. Set pull.rebase=true globally. Otherwise every sync leaves a noisy merge bubble that distorts git log --graph.
Renaming files? Stage the rename in one commit. Git detects renames via similarity index, but mixing a big rename with edits in the same commit fools blame. Rename first, edit second.

Go deeperSee also

Git FAQ

What is the difference between git merge and git rebase?

git merge combines two branches and preserves all history with a merge commit. git rebase replays your commits on top of another branch, producing a linear history without merge commits. Rebase keeps the log clean but rewrites commit SHAs — never rebase public/shared branches.

How do I undo the last commit in Git?

git reset HEAD~1 undoes the last commit and puts the changes back into your working tree (unstaged). Add --soft to keep them staged instead. Use git reset --hard HEAD~1 to discard the changes entirely. If the commit is already pushed, prefer git revert HEAD to create an undo commit without rewriting shared history.

What is git stash used for?

git stash saves your uncommitted changes (both staged and unstaged) onto a stack and restores a clean working tree. Use it when you need to switch branches quickly without committing. Retrieve with git stash pop (removes from stack) or git stash apply (keeps on stack). Name stashes with git stash push -m 'description'.

What is git reflog and how does it help recover lost commits?

git reflog records every time HEAD moved — commits, resets, checkouts, rebases. Even after a hard reset or mistaken branch deletion, commits stay in the object database for at least 30 days. Find the lost SHA in reflog, then git checkout <sha> or git branch recover <sha> to bring it back.

What is the difference between git switch and git checkout?

git switch (Git ≥ 2.23) is the modern command for changing branches: git switch main or git switch -c new-branch. git restore handles discarding file changes. git checkout originally handled both, making it confusing. New workflows should prefer switch and restore; checkout still works for everything.

What is --force-with-lease and when should I use it?

git push --force-with-lease is a safer alternative to --force. It refuses to overwrite the remote if someone else has pushed since you last fetched, preventing you from silently discarding their commits. Always use --force-with-lease instead of --force when you need to push a rewritten branch.