Let's start where most people arrive: you did something and you want it undone. Then the normal reference.
| Situation | Fix |
|---|---|
| Wrong commit message (not pushed) | git commit --amend |
| Forgot a file in the last commit | git add f && git commit --amend --no-edit |
| Undo last commit, keep the changes staged | git reset --soft HEAD~1 |
| Undo last commit, keep changes unstaged | git reset HEAD~1 |
| Undo last commit and throw away the work | git reset --hard HEAD~1 |
| Unstage a file (keep edits) | git restore --staged file |
| Discard edits to a file | git restore file |
| Undo a commit that's already pushed | git revert <sha> |
| Set something aside temporarily | git stash / git stash pop |
reset on commits nobody else has, and revert on anything already pushed. revert makes a new commit that undoes the old one, so shared history stays intact. Force-pushing a rewritten branch other people are working on is how you ruin a colleague's afternoon.git reflog lists everywhere HEAD has been — including commits you "deleted." Find the sha and git checkout -b recovered <sha>. This has saved more work than any other Git command.| Command | What it does |
|---|---|
| git status | Where am I, what's changed |
| git add -p | Stage hunk by hunk. Makes clean, reviewable commits instead of one blob. |
| git commit -m "msg" | Commit staged changes |
| git log --oneline --graph --all | Readable history with branch structure |
| git diff | Unstaged changes |
| git diff --staged | What you're about to commit — check before every commit |
| git blame file | Who wrote each line, and in which commit |
| Command | What it does |
|---|---|
| git switch -c feature | Create and switch (modern form of checkout -b) |
| git switch main | Switch branches |
| git branch -d feature | Delete merged branch (-D to force) |
| git merge feature | Merge into current branch |
| git rebase main | Replay your commits on top of main — linear history |
| git cherry-pick <sha> | Grab one commit from elsewhere |
Merge vs rebase, briefly: merge preserves what actually happened and is always safe. Rebase produces cleaner, linear history but rewrites commits — fine on your own branch, avoid on shared ones.
| Command | What it does |
|---|---|
| git clone url | Copy a repo down |
| git remote -v | Where does this push and pull from |
| git fetch | Download refs without touching your files — safe anytime |
| git pull | Fetch + merge into your branch |
| git push -u origin feature | Push a new branch and set upstream |
| git push --force-with-lease | Safer force-push — refuses if someone else pushed meanwhile |
--force. Use --force-with-lease. It does the same thing but aborts if the remote moved since you last looked, which is exactly the case where a plain force-push destroys someone's work.A conflict means Git can't decide between two versions. Open the file, find the <<<<<<< / ======= / >>>>>>> markers, delete the markers and leave the code you want, then git add the file and git commit. If it's going badly, git merge --abort puts everything back and nothing is lost.
The Git & GitHub Cheat Sheet for Beginners — one clean page including the undo table, made to print. Instant download.
Get the sheet — $3 →Pairs with the Linux commands sheet and the Docker sheet — the other two things open in every terminal.