Most developers use about 20% of Git and fight the other 80%. Interactive rebase feels dangerous until you understand what it does. Cherry-pick seems redundant until you need to backport a fix to three release branches simultaneously. Bisect looks academic until you are staring at a regression that could be in any of 200 commits. This guide covers the commands that save hours when you need them.
Try it yourself: Free Diff Checker — free, no signup, runs in your browser.
Interactive Rebase: Clean History Before Merging
Interactive rebase lets you rewrite the commit history of your branch before it merges into main. The goal is a clean, reviewable history — not a forensic record of every save-and-test cycle.
# Start interactive rebase against the branch point
git rebase -i main
# Or rebase the last N commits
git rebase -i HEAD~5
# Or rebase from a specific commit (not including it)
git rebase -i abc1234
The interactive editor opens with a list of commits and commands. The most useful commands:
# Commands available in the interactive rebase editor:
pick abc1234 Add user authentication endpoint # keep as-is
reword def5678 Fix typo in validator # keep, but edit the message
edit 789abcd Add Redis caching layer # pause here to amend
squash bcd1234 WIP: cache working # meld into previous commit
fixup cde5678 fix lint error # meld into prev, discard message
drop ef01234 Remove debug console.log # delete this commit entirely
exec npm test # run a command between commits
Real-world squash workflow: you have a feature branch with 8 commits, 3 of which are "fix lint" and "WIP". Before raising a PR:
# See what you have
git log --oneline main..HEAD
# a3f1c2d Add user profile endpoint
# b4e2d3e Add profile schema
# c5f3e4f WIP saving
# d6g4f5g Fix tests
# e7h5g6h Fix more tests
# f8i6h7i Fix lint
# g9j7i8j Add profile validation
# h0k8j9k Fix validation edge case
# Rebase interactively — 8 commits
git rebase -i HEAD~8
After the editor, the result is 2-3 logical commits with meaningful messages. Reviewers see the intent, not the iteration.
Rebase vs Merge: When to Use Each
# Merge: preserves full history, creates a merge commit
git checkout main
git merge feature/user-profile
# Result: non-linear history, shows exactly when branches diverged/merged
# Rebase: replays your commits on top of main, linear history
git checkout feature/user-profile
git rebase main
# Result: your commits appear after all of main's commits, no merge commit
# After rebasing a feature branch, merge with --no-ff to preserve the branch point
git checkout main
git merge --no-ff feature/user-profile
# Fast-forward only (use when you want to enforce rebase workflow)
git merge --ff-only feature/user-profile
# Fails if there are divergent commits, forcing a rebase first
Handling Rebase Conflicts
# Conflict during rebase — Git pauses and tells you which file
git rebase main
# CONFLICT (content): Merge conflict in src/auth/middleware.ts
# error: could not apply a3f1c2d... Add JWT middleware
# 1. Fix the conflict in the file
# 2. Stage it
git add src/auth/middleware.ts
# 3. Continue the rebase (NOT git commit!)
git rebase --continue
# Made a mistake? Abort and return to original state
git rebase --abort
# Skip a commit entirely (be careful — you might lose changes)
git rebase --skip
Cherry-Pick: Surgical Commit Transplants
Cherry-pick copies one or more commits from one branch to another. The primary use case is hotfix backporting: a bug is fixed on main and needs to go into the release/1.x and release/2.x branches without merging unrelated changes.
# Cherry-pick a single commit
git cherry-pick a3f1c2d
# Cherry-pick a range of commits (inclusive)
git cherry-pick a3f1c2d..h0k8j9k
# Cherry-pick without committing (stage the changes, let you review first)
git cherry-pick --no-commit a3f1c2d
# Cherry-pick and edit the commit message
git cherry-pick --edit a3f1c2d
# Backport workflow: fix is on main, need it on release/1.x
git log --oneline -5 main
# a3f1c2d Fix SQL injection in user search (this is the fix)
git checkout release/1.x
git cherry-pick a3f1c2d
# If it applies cleanly: done. If conflict: resolve like a rebase conflict.
# Cherry-pick multiple specific commits
git cherry-pick a3f1c2d b4e2d3e c5f3e4f
Git Bisect: Binary Search for Regressions
Bisect performs a binary search through your commit history to find which commit introduced a bug. Given a "good" commit and a "bad" commit, it checks out the midpoint, asks you to test, and narrows down to the exact commit in O(log n) steps.
# Start bisect
git bisect start
# Mark current state as bad (the bug exists)
git bisect bad HEAD
# Mark the last known good commit (tests passed)
git bisect good v2.3.0
# or by commit hash:
git bisect good abc1234
# Git checks out the midpoint commit. Test it, then:
git bisect bad # if the bug exists here
git bisect good # if the bug does not exist here
# Git keeps narrowing down. After 7-8 steps for 100 commits, you get:
# a3f1c2d is the first bad commit
# commit a3f1c2d
# Author: Dev Name
# Date: ...
# Refactor user search to use LIKE query
# Clean up — return to HEAD
git bisect reset
Automated bisect with a test script. This is the power mode — bisect runs the script at each step:
# Write a test script that exits 0 for good, non-zero for bad
cat > /tmp/test-regression.sh /dev/null || exit 125 # skip un-buildable commits
npm test -- --testPathPattern="user-search" --silent 2>/dev/null
SCRIPT
chmod +x /tmp/test-regression.sh
# Run automated bisect
git bisect start
git bisect bad HEAD
git bisect good v2.3.0
git bisect run /tmp/test-regression.sh
# Git runs the script at each midpoint and narrows down automatically
# Exit 125 means "skip this commit" (use for broken builds that aren't the bug)
# When done
git bisect reset
Reflog: Recovering Lost Work
The reflog is Git's safety net. Every time HEAD moves — commit, checkout, rebase, reset — Git records it. You can recover from almost any disaster if you act quickly.
# View the reflog
git reflog
# HEAD@{0}: rebase (finish): returning to refs/heads/feature/auth
# HEAD@{1}: rebase (pick): Add JWT middleware
# HEAD@{2}: rebase (pick): Add auth schema
# HEAD@{3}: rebase (start): checkout main
# HEAD@{4}: commit: WIP save before rebase
# HEAD@{5}: checkout: moving from main to feature/auth
# Recover a commit after accidental reset --hard
git reset --hard HEAD~3 # oops, went back 3 commits
git reflog # find the commit you were at
git reset --hard HEAD@{3} # restore to that point
# Recover a deleted branch
git branch -D feature/old-work # oops
git reflog | grep "feature/old-work"
# HEAD@{12}: checkout: moving from feature/old-work to main
git checkout -b feature/old-work HEAD@{12}
# Find a dangling commit (detached HEAD work that got lost)
git fsck --lost-found
# Lists unreachable commits, blobs
git show
git cherry-pick
Git Worktrees: Multiple Branches Simultaneously
Worktrees let you check out multiple branches in separate directories simultaneously. No stashing, no context switching — open a hotfix in a new directory while keeping your feature branch untouched.
# List existing worktrees
git worktree list
# Add a worktree for a hotfix
git worktree add ../myapp-hotfix release/1.x
# Creates ../myapp-hotfix/ directory checked out to release/1.x
# Work in the hotfix worktree
cd ../myapp-hotfix
git checkout -b hotfix/sql-injection
# ... make fixes ...
git commit -m "fix(auth): patch SQL injection in user search"
# Back in main worktree, cherry-pick if needed
cd ../myapp
git cherry-pick hotfix/sql-injection
# Remove worktree when done
git worktree remove ../myapp-hotfix
Advanced Log and Diff Commands
# Compact, visual branch graph
git log --oneline --graph --decorate --all
# Find commits that changed a specific file
git log --follow -p -- src/auth/middleware.ts
# Find commits by message content
git log --grep="SQL injection" --oneline
# Find commits by author in a date range
git log --author="dev" --since="2 weeks ago" --oneline
# Show what changed between two branches
git diff main..feature/auth --stat
# Show commits in feature/auth not in main
git log main..feature/auth --oneline
# Find which branch a commit is on
git branch --contains a3f1c2d
# Show the diff of a specific commit
git show a3f1c2d
# Show files changed in a commit
git show --stat a3f1c2d
# Diff between two tags
git diff v2.3.0..v2.4.0 -- src/
People Also Ask
Is git rebase safe to use on shared branches?
Never rebase a branch that other people have pulled. Rebase rewrites commit hashes — if someone has the old hashes, pushing the rebased version forces them to reset their local branch. Safe rule: rebase your own feature branches before they are merged, never after. The golden rule of rebase is: do not rebase commits that exist outside your repository.
When should I use cherry-pick vs merge vs rebase?
Use cherry-pick when you need specific commits from one branch without bringing the entire branch. Classic use case: backporting a security fix to multiple release branches. Use merge when you want to bring a complete feature branch into main with history preserved. Use rebase when you want to replay your feature branch on top of the latest main before merging, for a linear history.
How does git bisect find bugs faster than manual searching?
Bisect uses binary search — each test eliminates half the remaining commits. For 1,000 commits, it takes at most 10 tests to find the exact bad commit. Manual linear searching would take up to 1,000 tests. Combined with an automated test script (git bisect run), bisect can find a regression in seconds without any human steps.
For Git workflow templates, CI/CD setup guides, and developer automation tools, visit WOWHOW developer tools. Browse all productivity and DevOps resources at the full catalog.
Originally published at wowhow.cloud
Top comments (0)