Git Cheatsheet
Rebasing
Use this Git reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
Basic Rebase
Rebase replays commits from the current branch on top of another base commit, producing a linear history.
git rebase <branch> # Rebase current branch onto <branch> git rebase main # Most common: rebase current feature onto main git rebase origin/main # Rebase onto remote-tracking branch git rebase <sha> # Rebase onto a specific commit git rebase --onto <newbase> <upstream> <branch> # Three-argument form (see below)
Merge vs. Rebase
Before: main: A---B---C feature: D---E git merge main → preserves fork: feature: A---B---C---M (merge commit) \ / D-E git rebase main → linear history: feature: A---B---C---D'---E'
Interactive Rebase
Rewrite, reorder, squash, edit, or drop commits in a range:
git rebase -i HEAD~3 # Interactively rebase the last 3 commits git rebase -i HEAD~10 # Last 10 commits git rebase -i <sha> # Commits after a specific commit git rebase -i <sha>^ # Include that commit too git rebase -i --root # Edit the entire history from the very first commit
Interactive Rebase Commands
| Command | Alias | Action |
|---|---|---|
pick | p | Keep the commit as-is |
reword | r | Keep commit but edit the message |
edit | e | Pause to amend the commit (changes or message) |
squash | s | Meld into the previous commit (keep both messages) |
fixup | f | Meld into the previous commit (discard this message) |
drop | d | Remove the commit entirely |
exec | x | Run a shell command after this commit |
break | b | Pause here (use --continue to resume) |
label | l | Label the current HEAD for use by reset |
reset | t | Reset HEAD to a label |
merge | m | Create a merge commit (preserves branches in rebase) |
# Example: squash last 3 commits into one git rebase -i HEAD~3 # In the editor, change "pick" to "squash" (or "fixup") for commits 2 and 3
Rebase Flow Control
git rebase --continue # Continue after resolving a conflict git rebase --skip # Skip the current conflicting commit git rebase --abort # Abort the entire rebase, return to pre-rebase state git rebase --quit # Abort but leave HEAD where it is (Git ≥2.12) git rebase --edit-todo # Re-open the todo list in interactive rebase git rebase --show-current-patch # Show the current conflicting patch
The --onto Flag
Replays commits from <upstream>...<branch> onto <newbase>:
git rebase --onto <newbase> <upstream> <branch>
# Move feature2 (branched from feature1) directly onto main git rebase --onto main feature1 feature2 # Move the last 4 commits to a different base git rebase --onto main HEAD~4 HEAD # Remove a range of commits from the middle git rebase --onto HEAD~5 HEAD~3 HEAD # Drop the 2 commits at HEAD~4 and HEAD~3
Visual Example
Before: main: A---B feature1: A---B---C---D feature2: A---B---C---D---E---F git rebase --onto main feature1 feature2 After: main: A---B feature1: A---B---C---D (unchanged) feature2: A---B---E'---F'
Rebasing onto a Remote
git fetch origin git rebase origin/main # Rebase onto the fetched remote main git pull --rebase # Fetch + rebase in one step git pull --rebase=interactive # Fetch + interactive rebase
Autosquash
Automatically squash commits whose messages start with fixup! or squash!:
git commit --fixup=<sha> # Create a "fixup! <original-message>" commit git commit --squash=<sha> # Create a "squash! <original-message>" commit git rebase -i --autosquash HEAD~10 # Auto-arrange fixup!/squash! commits
Auto-enable autosquash:
git config --global rebase.autoSquash trueAuto-Stash During Rebase
git rebase --autostash main # Stash dirty state, rebase, re-apply stash git config --global rebase.autoStash true # Always auto-stash
Rebase Preserving Merges
git rebase -p <branch> # Preserve merge commits (--preserve-merges, deprecated) git rebase --rebase-merges <branch> # Modern replacement (Git ≥2.18) git rebase -r <branch> # Shorthand for --rebase-merges
Resolving Rebase Conflicts
git status # See which file has a conflict # Edit the file and resolve conflict markers git add <resolved-file> git rebase --continue # Move to the next commit # or: git rebase --skip # Drop this commit's changes and continue # or: git rebase --abort # Give up and return to pre-rebase state
During interactive rebase with edit:
# Git pauses at that commit in detached HEAD git commit --amend # Amend the commit (message or changes) git rebase --continue # Resume
exec Command
Run a command after each (or a specific) commit during interactive rebase:
# In the todo list:
pick abc1234 feat: add login
exec npm test
pick def5678 feat: add logout
exec npm testOr run a command across all commits:
git rebase -i --exec "npm test" HEAD~10
Splitting a Commit
git rebase -i HEAD~3 # Mark the commit you want to split as "edit" # Git pauses at that commit: git reset HEAD^ # Unstage all changes from this commit git add -p # Stage first portion interactively git commit -m "part one" git add -p # Stage second portion git commit -m "part two" git rebase --continue
Safety Rules
Never rebase commits that have been pushed to a shared branch. Rebase rewrites commit SHAs; pushing rewritten commits forces everyone else to reconcile diverged history.
Safe to rebase: local-only commits, personal feature branches not shared with others.
If you've already pushed and must rebase anyway: coordinate with the team, then
git push --force-with-lease.
Configuring Rebase Defaults
git config --global pull.rebase true # Always rebase on pull git config --global rebase.autoSquash true # Enable --autosquash by default git config --global rebase.autoStash true # Auto-stash dirty state git config --global rebase.stat true # Show diffstat after rebase git config --global sequence.editor "code --wait" # Editor for todo list
Checking for Rebase Conflicts Ahead of Time
git merge-base main HEAD # Find the common ancestor SHA git log main..HEAD # Commits that will be replayed git diff main...HEAD # Changes introduced since branch point