Most developers use 10% of Git’s capabilities. They add, commit, push, and occasionally merge. Senior engineers reach for a completely different toolset: interactive rebase to clean up history before review, bisect to find which commit introduced a bug, worktrees to work on multiple branches simultaneously, and reflog to recover from any mistake. These are the commands that separate experienced engineers from beginners.
⚡ TL;DR:
git rebase -ito clean history before PRs.git bisectto find which commit broke something.git reflogto recover anything.git stashwith names for context-switching.git worktreefor parallel branches.git blame -Lto understand code history.
Interactive rebase — clean history before review
# Clean up last 5 commits before opening PR
git rebase -i HEAD~5
# In the editor, you can:
# pick abc123 Add user auth → keep as-is
# squash def456 Fix typo in auth → merge into previous
# squash ghi789 Fix typo again → merge into previous
# reword jkl012 Add tests → keep but edit message
# drop mno345 WIP debugging commit → remove entirely
# fixup pqr678 Minor cleanup → squash, discard message
# Result: clean history with logical commits
# Never rebase shared branches (main, develop) — only feature branches
# Squash all feature branch commits into one before merge:
git checkout main
git merge --squash feature/user-auth
git commit -m "feat: add user authentication"
git bisect — find which commit broke production
# Binary search through commits to find the one that introduced a bug
# 1000 commits? Only needs ~10 checks.
git bisect start
git bisect bad HEAD # Current commit has the bug
git bisect good v2.1.0 # This version was working
# Git checks out a commit midway between good and bad
# Test it: does the bug exist?
git bisect good # Bug not here — go forward
# or
git bisect bad # Bug here — go backward
# Repeat ~10 times. Git tells you:
# "abc1234 is the first bad commit"
# commit abc1234
# Author: Developer
# Date: Tue Apr 1 10:23:45 2026
# "Optimize database query in user service"
git bisect reset # Return to HEAD when done
# Automate with a test script:
git bisect start HEAD v2.1.0
git bisect run npm test -- --grep "user auth" # Auto-bisects!
git reflog — recover anything
# Reflog records every HEAD movement for 90 days
# Accidentally deleted a branch? Amend the wrong commit? Hard reset?
# Reflog can recover all of it.
git reflog
# abc1234 HEAD@{0}: commit: Add feature X
# def5678 HEAD@{1}: reset: moving to HEAD~3 ← accidentally lost commits!
# ghi9012 HEAD@{2}: commit: Add feature Y
# jkl3456 HEAD@{3}: commit: Add feature Z
# Recover the commits lost in the accidental reset:
git checkout -b recovery-branch HEAD@{2}
# or:
git reset --hard HEAD@{2} # Return to that state
# Recover deleted branch:
git branch recovered-feature ghi9012 # Create branch at commit SHA
git worktree — multiple branches simultaneously
# Work on hotfix while continuing feature work — no stash needed
git worktree add ../hotfix-branch hotfix/critical-bug
# Creates a new working directory linked to same repository
# You now have two terminals:
# ~/myapp → feature/user-auth branch
# ~/hotfix-branch → hotfix/critical-bug branch
# Both share .git history — no clone overhead
# Fix the hotfix in one terminal, keep working in the other
# Remove when done:
git worktree remove ../hotfix-branch
# List worktrees:
git worktree list
git stash — named stashes for context switching
# Named stash — don't lose context when interrupted
git stash push -m "WIP: user auth validation, blocked on API spec"
git stash push -m "WIP: payment flow, waiting for QA"
# List named stashes:
git stash list
# stash@{0}: WIP: payment flow, waiting for QA
# stash@{1}: WIP: user auth validation, blocked on API spec
# Apply specific stash by name:
git stash pop stash@{1} # Apply and remove
git stash apply stash@{1} # Apply and keep in stash list
# Stash only unstaged changes (keep staged):
git stash push --keep-index
Useful aliases every senior engineer has
# Add to ~/.gitconfig [alias] section:
# Beautiful one-line log:
log1 = log --oneline --graph --decorate --all
# Show changed files in last commit:
last = log -1 HEAD --stat
# Undo last commit, keep changes staged:
undo = reset --soft HEAD~1
# Stage only parts of a file interactively:
stage = add -p
# See what will be pushed:
outgoing = log @{upstream}..HEAD --oneline
# Incoming from remote:
incoming = log HEAD..@{upstream} --oneline
# Find when a string was introduced:
pickaxe = log -S # Usage: git pickaxe "secretKey"
# Show all branches with last commit date:
branches = branch -v --sort=-committerdate
git blame and log for code archaeology
# Understand why code was written this way
# Blame specific line range:
git blame -L 45,60 src/auth/middleware.ts
# Shows commit SHA, author, date for each line in range
# Follow function across renames:
git log -L :functionName:filename.ts
# Shows every commit that touched that function
# Find all commits that changed a specific string:
git log -S "deprecated_function" --all --oneline
# Show changes to a file across all branches:
git log --all --follow --oneline -- path/to/deleted-file.ts
# See the full context of a commit:
git show abc1234 --stat # Files changed
git show abc1234 # Full diff
Git senior engineer checklist
- ✅
git rebase -i HEAD~nbefore every PR — clean history saves reviewers time - ✅
git bisect run script— automate bug hunting in large history - ✅
git reflog— nothing is permanently lost within 90 days - ✅
git worktree— parallel branches without multiple clones - ✅ Named stashes with
-m— never lose context again - ✅
git log -L :function:file— trace a function’s entire history - ✅
git log -S "string"— find when code was introduced - ❌ Never
git push --forceto shared branches — use--force-with-lease - ❌ Never rebase commits that have been pushed to shared branches
Git mastery is foundational for the debugging techniques in the API debugging guide — git bisect and git log -S are often the fastest way to trace when a production bug was introduced. External reference: Pro Git book (free online).
Recommended Books
→ Designing Data-Intensive Applications — The essential deep-dive on distributed systems, databases, and production engineering at scale.
→ The Pragmatic Programmer — Timeless principles for writing better code, debugging smarter, and advancing as an engineer.
Affiliate links. We earn a small commission at no extra cost to you.
Discover more from CheatCoders
Subscribe to get the latest posts sent to your email.
