15 minlesson

Interactive Rebase and Bisect

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

bash
1$ git rebase -i HEAD~3

This opens your editor with the last 3 commits:

1pick abc1234 feat: add user model
2pick def5678 fix: typo in user model
3pick ghi9012 feat: add user validation
4
5# Rebase xyz789..ghi9012 onto xyz789 (3 commands)
6#
7# Commands:
8# p, pick = use commit
9# r, reword = use commit, but edit the commit message
10# e, edit = use commit, but stop for amending
11# s, squash = use commit, but meld into previous commit
12# f, fixup = like "squash", but discard this commit's message
13# d, drop = remove commit
14# ...

Common Operations

Squash commits together:

Change:

1pick abc1234 feat: add user model
2pick def5678 fix: typo in user model

To:

1pick abc1234 feat: add user model
2squash def5678 fix: typo in user model

The second commit merges into the first.

Reword a message:

1reword abc1234 feat: add user model
2pick def5678 fix: typo

Git will prompt you to edit the message.

Reorder commits:

1pick def5678 fix: typo
2pick abc1234 feat: add user model

Simply change the order of lines.

Drop a commit:

1pick abc1234 feat: add user model
2drop def5678 debugging code (remove this)

Fixup: Squash Without Message

fixup is like squash but discards the commit message:

1pick abc1234 feat: add user model
2fixup def5678 fix: typo
3fixup 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 model
2pick def5678 fix: typo

Git pauses at that commit. Make changes, then:

bash
1$ git add .
2$ git commit --amend
3$ git rebase --continue

Handling Conflicts

If rebase encounters conflicts:

bash
1$ git status
2# Shows conflicted files
3
4# Fix conflicts manually
5$ vim conflicted-file.js
6
7$ git add conflicted-file.js
8$ git rebase --continue

To abort and return to original state:

bash
1$ 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 (HEAD is bad)
  • It didn't exist at version 1.0 (v1.0 is good)
  • There are 100 commits between them

Checking each commit manually takes forever. Bisect finds it in ~7 steps.

Starting Bisect

bash
1$ git bisect start
2$ git bisect bad # Current commit has the bug
3$ git bisect good v1.0 # This commit was working
4Bisecting: 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:

bash
1# If this commit has the bug:
2$ git bisect bad
3Bisecting: 25 revisions left to test...
4
5# If this commit is fine:
6$ git bisect good
7Bisecting: 12 revisions left to test...

Repeat until Git identifies the culprit:

bash
1$ git bisect good
2def5678 is the first bad commit
3commit def5678
4Author: Someone <someone@example.com>
5Date: Mon Nov 25 10:00:00 2025
6
7 feat: add caching (this broke it!)

Ending Bisect

bash
1$ 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:

bash
1$ git bisect start HEAD v1.0
2$ git bisect run ./test-script.sh

Git automatically runs the script at each step.

Bisect Example Script

bash
1#!/bin/bash
2# test-for-bug.sh
3npm test 2>&1 | grep -q "expected output"

Skipping Untestable Commits

If a commit won't compile or can't be tested:

bash
1$ git bisect skip

Git tries a nearby commit instead.

Commands Summary

CommandPurpose
git rebase -i HEAD~NInteractive rebase last N commits
git rebase --continueContinue after resolving conflict
git rebase --abortCancel rebase
git bisect startBegin binary search
git bisect badMark current commit as bad
git bisect good <ref>Mark commit as good
git bisect resetEnd 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.