Git gives you the power to reshape history — to clean up messy work-in-progress commits before sharing them, or to integrate changes from another branch cleanly. This lesson covers the tools for that: rebase, interactive rebase, stash, and cherry-pick.
git rebase
Rebase replays your branch's commits on top of another commit, giving your branch a new "base." The result is a linear history — as if you had started your branch from the latest version of main:
Before rebase:
main: A -- B -- C
feature: D -- E
git switch feature
git rebase main
After rebase:
main: A -- B -- C
feature: D' -- E' (new commits — SHA changed)
git switch feature/my-feature
git fetch origin
git rebase origin/main
Important: Rebase rewrites commit SHAs. If you have already pushed the branch to a remote, you will need to force-push. Use --force-with-lease to avoid overwriting changes from others:
git push --force-with-lease origin feature/my-feature
The golden rule: Never rebase a branch that other people are working from. Rebase is safe for your own feature branches before they are merged — not for main or shared branches.
Interactive Rebase
Interactive rebase (git rebase -i) opens an editor showing the last N commits and lets you edit each one:
# Interactively edit the last 4 commits
git rebase -i HEAD~4
The editor shows:
pick a1b2c3d Add login form
pick d4e5f6g WIP
pick h7i8j9k Fix typo
pick l0m1n2o Add form validation
Change the action word before each commit:
| Command | Action |
|---|---|
pick | Keep this commit as-is |
reword | Keep the commit but edit the message |
edit | Pause to amend the commit's content |
squash | Merge this commit into the previous one (combine messages) |
fixup | Merge into previous, discard this commit's message |
drop | Delete this commit entirely |
A common use: squash all the "WIP" and "fix typo" commits into a single clean commit before opening a PR.
git stash
Stash saves your current working tree and staging area onto a stack and reverts to a clean state. Useful when you need to switch branches mid-work without making a messy commit:
# Stash all uncommitted changes
git stash
# Stash with a descriptive message
git stash push -m "half-finished login refactor"
# List all stashes
git stash list
# Apply the most recent stash and remove it from the stack
git stash pop
# Apply a specific stash without removing it
git stash apply stash@{2}
# Delete all stashes
git stash clear
git cherry-pick
Cherry-pick applies the changes from a specific commit onto the current branch — without merging the entire branch. Useful for backporting a bug fix to a release branch:
# Apply commit abc1234 to the current branch
git cherry-pick abc1234
# Apply a range of commits
git cherry-pick abc1234..def5678
Like rebase, cherry-pick creates a new commit (new SHA) with the same changes. Use it sparingly — frequent cherry-picking can cause divergence that is painful to reconcile later.
git amend
# Fix the message of the most recent commit
git commit --amend -m "Correct commit message"
# Add forgotten staged changes to the most recent commit
git add forgotten-file.ts
git commit --amend --no-edit
Like rebase, --amend rewrites the most recent commit — only use it before pushing.
When Is Rewriting History Safe?
- Safe: Rewriting commits on your own local or remote feature branch that no one else has pulled
- Unsafe: Rewriting commits on
main, or any branch shared with teammates who have already cloned those commits - If you must force-push a shared branch (e.g., fixing a leaked secret), communicate clearly with all affected developers