Advanced Git Commands Every Developer Should Know
Commands like interactive rebase, amend, and blame provide deeper control over Git history.
Advanced Git Commands Every Developer Should Know
Once you have mastered the basic Git workflow of add, commit, push, and pull, a world of powerful advanced commands awaits. These commands give you finer control over your repository history, help you debug complex issues, recover from mistakes, and craft a clean, meaningful commit history. While you may not use them every day, knowing these advanced commands will make you significantly more effective when you need them.
Advanced Git commands allow you to rewrite history, selectively apply changes, inspect the evolution of your code, and recover from seemingly disastrous mistakes. They separate casual Git users from power users who can shape their repository history exactly how they want it. To understand these commands properly, it is helpful to be familiar with Git core concepts, branching fundamentals, and basic Git workflow.
Interactive Rebase → Rewrite, reorder, squash, or edit commits
Cherry-Pick → Apply specific commits from one branch to another
Bisect → Find which commit introduced a bug
Reflog → Recover lost commits and undo mistakes
Blame → See who last modified each line of a file
Worktree → Work on multiple branches simultaneously
Rerere → Reuse recorded conflict resolutions
Filter-Repo → Rewrite repository history
Interactive Rebase
Interactive rebase is one of Git's most powerful features. It allows you to rewrite, reorder, squash, edit, or delete commits before they are applied to a new base. This is invaluable for cleaning up your commit history before sharing it with others.
# Interactive rebase of the last 3 commits
git rebase -i HEAD~3
# Interactive rebase from a specific commit onward
git rebase -i abc1234
When you run interactive rebase, Git opens an editor with a list of commits. You can change the command next to each commit to control what happens.
pick - Use the commit as is
reword - Change the commit message
edit - Stop to amend the commit content
squash - Combine this commit with the previous one
fixup - Combine with previous commit, discarding its message
drop - Remove the commit entirely
Git Cherry-Pick
Cherry-pick allows you to apply specific commits from one branch to another without merging the entire branch. This is useful when you need only a particular fix or feature from another branch.
# Cherry-pick a single commit
git cherry-pick abc1234
# Cherry-pick a range of commits
git cherry-pick abc1234..def5678
# Cherry-pick without committing (stage changes only)
git cherry-pick -n abc1234
Git Bisect
Bisect is a binary search tool that helps you find which commit introduced a bug. It is invaluable when you know a bug exists but do not know when it was introduced.
# Start bisect
git bisect start
# Mark the current commit as bad (contains the bug)
git bisect bad
# Mark an old commit as good (does not contain the bug)
git bisect good abc1234
# Git checks out a commit halfway between good and bad
# Test the commit, then mark it as good or bad
git bisect good # or git bisect bad
# Repeat until Git identifies the faulty commit
# When done, reset to original state
git bisect reset
# Run bisect automatically using a test script
git bisect start HEAD abc1234
git bisect run npm test
# The script should exit with 0 for good commits, non-0 for bad commits
Git Reflog
Reflog (reference log) records every movement of HEAD in your local repository. It is your safety net for recovering commits that you thought were lost forever after a hard reset, rebase, or branch deletion.
# View the reflog
git reflog
# Output shows:
# abc1234 HEAD@{0}: reset: moving to HEAD~1
# def5678 HEAD@{1}: commit: Add new feature
# 789abcd HEAD@{2}: commit: Fix login bug
# Recover a lost commit by creating a branch at that point
git branch recovered-branch def5678
# Or reset back to that commit
git reset --hard def5678
The reflog is local to your repository and is not shared when you push. It typically retains entries for 90 days, after which they are cleaned up by garbage collection.
Git Blame
Blame shows you who last modified each line of a file and in which commit. It is essential for understanding why a line of code was written and who to ask about it.
# Show who last modified each line
git blame filename.txt
# Show blame for a specific range of lines
git blame -L 10,20 filename.txt
# Show blame ignoring whitespace changes
git blame -w filename.txt
# Show blame with commit hashes and authors
git blame -l filename.txt
abc1234 (John Doe 2024-01-15 10:30:00 1) function calculateTotal(items) {
def5678 (Jane Smith 2024-02-01 14:20:00 2) return items.reduce((sum, item) => {
def5678 (Jane Smith 2024-02-01 14:20:00 3) return sum + item.price * item.quantity;
abc1234 (John Doe 2024-01-15 10:30:00 4) }, 0);
abc1234 (John Doe 2024-01-15 10:30:00 5) }
Git Worktree
Worktree allows you to have multiple branches checked out simultaneously in different directories. This is useful when you need to work on two branches at once without stashing or committing unfinished work.
# Create a new worktree for a feature branch
git worktree add ../my-project-feature feature-branch
# Create a worktree for a hotfix from main
git worktree add ../my-project-hotfix -b hotfix/urgent main
# List all worktrees
git worktree list
# Remove a worktree
git worktree remove ../my-project-feature
# Prune worktree references
git worktree prune
Each worktree has its own working directory and staging area but shares the same Git history. You can run Git commands in each worktree independently.
Git Rerere (Reuse Recorded Resolution)
Rerere stands for "reuse recorded resolution." It remembers how you resolved merge conflicts so that Git can automatically resolve the same conflicts in future merges. This is invaluable for long-running branches that need frequent merges.
# Enable rerere globally
git config --global rerere.enabled true
# Rerere now records conflict resolutions automatically
# On future merges with the same conflict, Git applies the saved resolution
# See recorded resolutions
git rerere status
# Forget a specific resolution
git rerere forget file.txt
Git Filter-Repo (History Rewriting)
Filter commands allow you to rewrite repository history by removing files, replacing text, or changing commit metadata. This is useful for removing accidentally committed secrets or large files, or for splitting a repository.
# Install git-filter-repo (recommended over filter-branch)
pip install git-filter-repo
# Remove a file from entire history
git filter-repo --path secrets.txt --invert-paths
# Replace text in all commits
git filter-repo --replace-text <(echo 'old_password==>new_password')
# Keep only specific files
git filter-repo --path src/ --path README.md
Warning: Rewriting history with filter commands changes commit hashes. Only do this on repositories that have not been shared with others, or coordinate with your entire team.
Common Advanced Command Mistakes to Avoid
- Rebasing Public Branches: Never rebase branches that others have already pulled. This creates divergent histories and causes confusion.
- Hard Resetting Without Backup: Always check
git reflogbefore a hard reset to ensure you can recover if something goes wrong. - Cherry-Picking Dependencies: Cherry-picking a commit without its dependencies may break functionality. Check what the commit relies on.
- Ignoring Bisect Automation: Manual bisect is tedious. Write a test script and use
git bisect runfor automated searching. - Not Using Worktrees for Parallel Work: Stashing and switching branches constantly is inefficient. Worktrees let you work on multiple branches simultaneously.
Best Practices for Advanced Git
- Squash Before Merging: Use interactive rebase to squash related commits into logical units before merging to main.
- Write a Test Script for Bisect: Create a script that exits 0 for good commits and non-0 for bad commits, then use
git bisect run. - Use Reflog as Your Safety Net: Before any destructive operation, remember that reflog can recover lost commits for 90 days.
- Enable Rerere for Long-Running Branches: If you frequently merge main into a feature branch, rerere saves you from resolving the same conflicts repeatedly.
- Document Complex Workflows: If your team uses advanced commands like rebase or filter-repo, document the workflow for everyone.
Frequently Asked Questions
- What is the difference between git rebase and git merge?
Merge creates a merge commit preserving history. Rebase rewrites commits to create a linear history. Rebase is cleaner but can be dangerous on shared branches. - Can I recover a commit after git reset --hard?
Yes. Usegit reflogto find the commit hash andgit reset --hard <hash>to restore it. Reflog keeps entries for about 90 days. - What is the difference between git cherry-pick and git merge?
Cherry-pick applies specific commits individually. Merge applies all commits from one branch to another. Use cherry-pick for selective changes, merge for complete features. - How do I find which commit introduced a bug?
Usegit bisect. Mark a known good commit and a known bad commit, then Git performs a binary search to find the faulty commit. - What is the difference between git filter-branch and git filter-repo?
Filter-repo is the recommended modern tool. It is faster, safer, and easier to use than the legacy filter-branch. Filter-branch is deprecated. - What should I learn next after advanced Git commands?
After mastering advanced Git, explore Git workflows, Git internals, Git hooks, and Git submodules for complete Git mastery.
