Pular para o conteúdo principal

git cherry-pick & git bisect — Precision Surgery

Module 05 45 min

Section Objectives

  • Use git cherry-pick to apply specific commits to another branch
  • Use git bisect to find the commit that introduced a bug
  • Know when to use these commands and their limitations

git cherry-pick — Apply Specific Commits

git cherry-pick takes a commit from one branch and applies it to another, creating a new commit with the same changes (different hash).

Basic Usage

# Cherry-pick a single commit
git cherry-pick abc1234

# Cherry-pick multiple commits
git cherry-pick abc1234 def5678 ghi9012

# Cherry-pick a range of commits (exclusive of first)
git cherry-pick abc1234..def5678

# Cherry-pick without creating a commit (stage only)
git cherry-pick --no-commit abc1234

# Cherry-pick and edit the commit message
git cherry-pick -e abc1234

Handle Cherry-pick Conflicts

# If a conflict occurs:
# 1. Fix the conflict
git status # Shows conflicted files
# edit the files...
git add fixed-file.py

# 2. Continue
git cherry-pick --continue

# OR: Abort
git cherry-pick --abort

# OR: Skip this commit
git cherry-pick --skip

When to Use Cherry-pick

ScenarioUse Cherry-pick?Alternative
Critical fix needed on release branch✅ Yes-
Accidentally committed to wrong branch✅ Yes-
Reuse a utility function from another branch✅ Yes-
Integrate an entire feature❌ NoMerge or rebase
Regularly syncing branches❌ NoMerge or rebase
Cherry-pick vs Merge

Cherry-pick creates a copy of the commit (new hash). If you later merge the original branch, Git will see these as duplicate changes. Use cherry-pick sparingly and for specific use cases.

Practical Examples

# Scenario 1: Critical fix needed on release branch
git switch release/v1.0
git cherry-pick hotfix-commit-hash
git push origin release/v1.0

# Scenario 2: Committed on wrong branch
git log --oneline # Find the commit hash you want to move
git switch correct-branch
git cherry-pick abc1234 # Apply to correct branch
git switch wrong-branch
git reset HEAD~1 # Remove from wrong branch

git bisect — Binary Search for Bugs

git bisect performs a binary search through your commit history to find the exact commit that introduced a bug.

Manual Bisect

# 1. Start bisect
git bisect start

# 2. Mark current commit as bad (bug present)
git bisect bad

# 3. Mark a known good commit (no bug)
git bisect good v1.0.0
# or by hash:
git bisect good abc1234

# Git will check out the middle commit
# Test your application...

# 4. Mark each tested commit
git bisect good # No bug on this commit
git bisect bad # Bug present on this commit

# 5. Git narrows down and shows the culprit:
# abc1234 is the first bad commit

# 6. Exit bisect
git bisect reset # Returns to original HEAD

Automated Bisect

If you have a test that can detect the bug, you can fully automate bisect.

Create a test script test_bug.sh:

#!/bin/bash
# Exits 0 (success) if no bug, 1 if bug present
python -c "
from app import get_statistics
from app import TASKS
TASKS.clear()
try:
stats = get_statistics()
if stats['total'] == 0:
exit(0)
else:
exit(1)
except ZeroDivisionError:
exit(1)
"
chmod +x test_bug.sh

# Let Git do the bisect automatically!
git bisect start
git bisect bad HEAD
git bisect good v1.0.0
git bisect run ./test_bug.sh

# Git runs the script on each commit and finds the culprit automatically
# At the end:
git bisect reset

Bisect Log and Replay

# Save a bisect session for later
git bisect log > bisect-session.log

# Replay a saved session
git bisect replay bisect-session.log

git reflog — The Safety Net

git reflog records every HEAD movement in your repository — it's your ultimate safety net:

# View the reflog
git reflog

# Output:
# d5a1b4c HEAD@{0}: commit: feat: add statistics
# c2e8f3a HEAD@{1}: checkout: moving from feature to main
# b7c9d1e HEAD@{2}: reset: moving to HEAD~1
# a3f4b2c HEAD@{3}: commit: feat: add search

Recovering "Lost" Commits

# You accidentally ran git reset --hard and lost commits
git reset --hard HEAD~5 # Oops!

# Find the lost commits in reflog
git reflog
# HEAD@{2} was before the reset

# Recover
git reset --hard HEAD@{2}

# Or create a new branch from the lost state
git switch -c recovery-branch HEAD@{2}
Reflog stays local

The reflog is not pushed to GitHub. It's a local safety net only. Reflog entries are kept for 90 days by default.


Summary

CommandDescription
git cherry-pick <hash>Apply a specific commit
git cherry-pick --continueContinue after conflict
git cherry-pick --abortCancel cherry-pick
git bisect startStart binary search
git bisect good/badMark commit as good/bad
git bisect run <script>Automatic bisect
git bisect resetEnd bisect session
git reflogView all HEAD movements

Next Steps