Interactive Rebase and Bisect
These advanced commands help you maintain clean history and debug regressions efficiently.
Interactive Rebase
Interactive rebase lets you edit, reorder, squash, or drop commits before sharing them.
When to Use
- Clean up messy commit history before PR
- Combine "WIP" commits into logical units
- Fix commit messages
- Reorder commits
- Remove accidental commits
Starting Interactive Rebase
bash1$ git rebase -i HEAD~3
This opens your editor with the last 3 commits:
1pick abc1234 feat: add user model2pick def5678 fix: typo in user model3pick ghi9012 feat: add user validation45# Rebase xyz789..ghi9012 onto xyz789 (3 commands)6#7# Commands:8# p, pick = use commit9# r, reword = use commit, but edit the commit message10# e, edit = use commit, but stop for amending11# s, squash = use commit, but meld into previous commit12# f, fixup = like "squash", but discard this commit's message13# d, drop = remove commit14# ...
Common Operations
Squash commits together:
Change:
1pick abc1234 feat: add user model2pick def5678 fix: typo in user model
To:
1pick abc1234 feat: add user model2squash def5678 fix: typo in user model
The second commit merges into the first.
Reword a message:
1reword abc1234 feat: add user model2pick def5678 fix: typo
Git will prompt you to edit the message.
Reorder commits:
1pick def5678 fix: typo2pick abc1234 feat: add user model
Simply change the order of lines.
Drop a commit:
1pick abc1234 feat: add user model2drop def5678 debugging code (remove this)
Fixup: Squash Without Message
fixup is like squash but discards the commit message:
1pick abc1234 feat: add user model2fixup def5678 fix: typo3fixup ghi9012 more fixes
Result: One commit with the original message.
Editing a Commit
Use edit to stop and modify a commit:
1edit abc1234 feat: add user model2pick def5678 fix: typo
Git pauses at that commit. Make changes, then:
bash1$ git add .2$ git commit --amend3$ git rebase --continue
Handling Conflicts
If rebase encounters conflicts:
bash1$ git status2# Shows conflicted files34# Fix conflicts manually5$ vim conflicted-file.js67$ git add conflicted-file.js8$ git rebase --continue
To abort and return to original state:
bash1$ git rebase --abort
Golden Rule
Never rebase commits that have been pushed to a shared branch. Others may have based work on them.
Git Bisect
Bisect uses binary search to find the commit that introduced a bug.
The Problem
You know:
- The bug exists now (
HEADis bad) - It didn't exist at version 1.0 (
v1.0is good) - There are 100 commits between them
Checking each commit manually takes forever. Bisect finds it in ~7 steps.
Starting Bisect
bash1$ git bisect start2$ git bisect bad # Current commit has the bug3$ git bisect good v1.0 # This commit was working4Bisecting: 50 revisions left to test after this (roughly 6 steps)5[abc1234...] Some commit message
Git checks out the middle commit.
Testing Each Step
Test whether the bug exists, then tell Git:
bash1# If this commit has the bug:2$ git bisect bad3Bisecting: 25 revisions left to test...45# If this commit is fine:6$ git bisect good7Bisecting: 12 revisions left to test...
Repeat until Git identifies the culprit:
bash1$ git bisect good2def5678 is the first bad commit3commit def56784Author: Someone <someone@example.com>5Date: Mon Nov 25 10:00:00 202567 feat: add caching (this broke it!)
Ending Bisect
bash1$ git bisect reset
This returns you to your original branch.
Automated Bisect
If you have a test script that exits 0 for good, non-zero for bad:
bash1$ git bisect start HEAD v1.02$ git bisect run ./test-script.sh
Git automatically runs the script at each step.
Bisect Example Script
bash1#!/bin/bash2# test-for-bug.sh3npm test 2>&1 | grep -q "expected output"
Skipping Untestable Commits
If a commit won't compile or can't be tested:
bash1$ git bisect skip
Git tries a nearby commit instead.
Commands Summary
| Command | Purpose |
|---|---|
git rebase -i HEAD~N | Interactive rebase last N commits |
git rebase --continue | Continue after resolving conflict |
git rebase --abort | Cancel rebase |
git bisect start | Begin binary search |
git bisect bad | Mark current commit as bad |
git bisect good <ref> | Mark commit as good |
git bisect reset | End bisect session |
git bisect run <script> | Automated bisect |
Key Takeaway
Interactive rebase is for crafting clean history before sharing. Bisect is for efficiently finding which commit broke something. Both are advanced tools that become essential as projects grow.