Advanced Git Techniques: Interactive Rebase, Bisect, Worktree, and Hook Automation
You're Only Using 20% of Git's Power
Most developers only use add, commit, push, pull, and merge on a daily basis. Git's real power lies in: precise history control, rapid bug location, parallel multi-tasking, and automated workflows.
1. Interactive Rebase: Reshaping Commit History
Basic Operation
git rebase -i HEAD~5
Opens an editor showing the last 5 commits:
pick a1b2c3f feat: add user list page
pick d4e5f6g fix: fix list sorting issue
pick h7i8j9k feat: add search functionality
pick l0m1n2o chore: update dependencies
pick p3q4r5s feat: add pagination component
Six Operations
| Command | Purpose | Use Case |
|---|---|---|
pick |
Keep commit | Default |
squash |
Merge into previous commit | Combine multiple small fixes |
fixup |
Merge and discard message | Same as above, without keeping messages |
reword |
Modify commit message | Message has typos |
edit |
Pause and modify commit | Split or modify content |
drop |
Discard commit | Remove erroneous commits |
Practical: Cleaning Up a Feature Branch
# Original commits
pick abc1234 feat: user module WIP
pick def5678 fix: fix null pointer
pick ghi9012 fix: fix type errors
pick jkl3456 feat: add search
pick mno7890 chore: format code
# Cleaned up
pick abc1234 feat: add user module
fixup def5678 # merge into abc1234
fixup ghi9012 # merge into abc1234
pick jkl3456 feat: add search functionality
drop mno7890 # discard formatting commit
Auto Fixup
# Create a fixup commit (tagging the target commit)
git commit --fixup=abc1234
# Auto-rebase, fixup commits will find their targets and merge
git rebase -i --autosquash
2. Git Bisect: Binary Search for Bug Introduction Points
When a bug appears but you don't know which commit introduced it, bisect uses binary search to quickly pinpoint it.
Manual Bisect
# Start binary search
git bisect start
# Mark current version as bad (has bug)
git bisect bad
# Mark known good version
git bisect good v2.0.0
# Git automatically checks out the middle version
# After testing, mark it
git bisect good # or git bisect bad
# Repeat until the bug-introducing commit is found
# Git outputs: abc1234 is the first bad commit
# End the search
git bisect reset
Automated Bisect
# Use a script to auto-test each version
git bisect start HEAD v2.0.0
git bisect run npm test
# Or with a custom script
git bisect run ./scripts/test-bug.sh
#!/bin/bash
# scripts/test-bug.sh
npm run build
if curl -s http://localhost:3000/api/health | grep -q "ok"; then
exit 0 # good
else
exit 1 # bad
fi
Efficiency: 1000 commits only require 10 bisect steps (log₂(1000) ≈ 10).
3. Git Worktree: Working on Multiple Branches Simultaneously
The Problem
You're developing on feature/A when an urgent hotfix for hotfix/B comes in—you don't want to stash, and you don't want to create a new clone.
The Solution
# Create a worktree for the hotfix
git worktree add ../hotfix-B hotfix/B
# Work in the ../hotfix-B directory without affecting the current branch
cd ../hotfix-B
# Fix, commit, push
git add . && git commit -m "fix: urgent fix"
git push
# Return to original work
cd ../main-project
# Continue developing feature/A, completely unaffected
# Clean up the worktree
git worktree remove ../hotfix-B
Managing Worktrees
# List all worktrees
git worktree list
# Lock a worktree (prevent accidental deletion)
git worktree lock ../hotfix-B
# Unlock
git worktree unlock ../hotfix-B
| Comparison | git stash | git worktree | git clone |
|---|---|---|---|
| Disk Usage | 0 | Diff files only | Full copy |
| Switch Cost | stash + checkout | cd to directory | cd to directory |
| Parallel Work | Not supported | Supported | Supported |
| Shares .git | Yes | Yes | No |
4. Git Hooks: Automated Workflows
Client-Side Hooks
| Hook | Trigger | Use Case |
|---|---|---|
pre-commit |
Before git commit |
Code linting, formatting |
prepare-commit-msg |
Before editing commit message | Auto-add prefixes |
commit-msg |
After writing commit message | Validate message format |
pre-push |
Before git push |
Run tests |
post-checkout |
After switching branches | Install dependencies |
Server-Side Hooks
| Hook | Trigger | Use Case |
|---|---|---|
pre-receive |
Before receiving push | Permission validation |
update |
Before each ref update | Branch protection |
post-receive |
After receiving push | Trigger CI/CD |
Using Husky + lint-staged
npm install husky lint-staged --save-dev
npx husky init
// .husky/pre-commit
npx lint-staged
// package.json
{
"lint-staged": {
"*.{js,ts,tsx}": [
"eslint --fix",
"prettier --write"
],
"*.css": [
"stylelint --fix"
]
}
}
commitlint for Commit Message Validation
npm install @commitlint/cli @commitlint/config-conventional --save-dev
// commitlint.config.js
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [2, 'always', [
'feat', 'fix', 'docs', 'style', 'refactor',
'perf', 'test', 'build', 'ci', 'chore', 'revert',
]],
'subject-max-length': [2, 'always', 100],
},
};
# .husky/commit-msg
npx --no -- commitlint --edit $1
5. Git Stash Advanced Usage
Multiple Stashes
# Stash with a message
git stash push -m "WIP: user list search feature"
# List all stashes
git stash list
# stash@{0}: On feature/search: WIP: user list search feature
# stash@{1}: On feature/order: WIP: order detail page
# Apply a specific stash
git stash apply stash@{1}
# Partial stash
git stash push -m "stash CSS only" -- '**/*.css'
Create a Branch from Stash
git stash branch feature/search stash@{0}
# Creates a new branch and applies the stash—great for turning WIP into a formal branch
6. Git Log Advanced Queries
Searching Commit Content
# Search for commits containing a specific string
git log -S "function calculateTotal"
# Search for commits matching a regex
git log -G "calculate.*Total"
# Search history for a specific file
git log --follow -- src/utils/calc.ts
# View file change stats per commit
git log --stat
# View detailed diffs per commit
git log -p -- src/utils/calc.ts
Formatted Output
# Custom format
git log --format="%h %ad | %s%d [%an]" --date=short
# Output:
# a1b2c3f 2026-05-30 | feat: add search functionality (HEAD -> main) [John]
# d4e5f6g 2026-05-29 | fix: fix sorting issue [Jane]
View Branch Merge Graph
git log --graph --oneline --all --decorate
7. Git Reflog: The Time Machine
reflog records every movement of HEAD—even commits that were "deleted" can be recovered.
# View operation history
git reflog
# a1b2c3f HEAD@{0}: commit: feat: new feature
# d4e5f6g HEAD@{1}: rebase: continue rebasing
# h7i8j9k HEAD@{2}: reset: moving to HEAD~1
# l0m1n2o HEAD@{3}: commit: accidentally deleted commit
# Recover a deleted commit
git cherry-pick l0m1n2o
# Or go directly back to a previous state
git reset --hard HEAD@{3}
Retention period: Default 90 days (gc.reflogExpire), 30 days for unreferenced commits.
8. Useful Alias Configuration
git config --global alias.lg "log --graph --oneline --all --decorate"
git config --global alias.last "log -1 HEAD --stat"
git config --global alias.unstage "reset HEAD --"
git config --global alias.amend "commit --amend --no-edit"
git config --global alias.wip "commit -m 'WIP'"
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.st status
Usage: git lg, git last, git unstage file.ts, etc.