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.

Advanced Git commands overview:
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.

Interactive rebase commands:
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
Automated bisect with a test script:
# 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
Example blame output:
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 reflog before 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 run for 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

  1. 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.
  2. Can I recover a commit after git reset --hard?
    Yes. Use git reflog to find the commit hash and git reset --hard <hash> to restore it. Reflog keeps entries for about 90 days.
  3. 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.
  4. How do I find which commit introduced a bug?
    Use git bisect. Mark a known good commit and a known bad commit, then Git performs a binary search to find the faulty commit.
  5. 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.
  6. 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.