Git Advanced: The Commands I Wish I Knew Earlier (2026)
Beyond add, commit, push. These commands save hours of frustration.
Interactive Staging
# Review every change before committing
git add -p
# This opens an interactive prompt for EACH changed hunk:
# y - stage this hunk
# n - don't stage
# s - split into smaller hunks
# e - edit the hunk manually
# q - quit
# Why this matters:
# → You made 3 unrelated changes in one file
# → add -p lets you commit them separately
# → Clean commit history = easier debugging, easier code review
# Stage a file piece by piece
git add -p feature.js
# (y/n/s/e for each change)
# Unstage a file
git restore --staged file.js # Unstage but keep changes
git restore file.js # Discard changes entirely (DANGEROUS!)
# Stash management
git stash # Save current changes temporarily
git stash push -m "WIP: auth feature" # Stash with message
git stash list # List all stashes
git stash pop stash@{0} # Apply and remove stash
git stash apply stash@{0} # Apply but keep stash
git stash drop stash@{0} # Remove stash without applying
git stash clear # Remove ALL stashes
Commit History Magic
# View commit history (my favorite variations)
git log --oneline --graph -15
# * abc1234 (HEAD -> main) feat: add user auth
# * def5678 fix: resolve login bug
# | * ghi9012 (feature/login) feat: login flow
# |/
git log --oneline --all --graph
# See ALL branches and their relationship
git log --since="1 week ago" --author="you"
# Filter by date and author
git log -p # Show actual code changes
git log --stat # Show file change statistics
# Find the commit that introduced a bug
git bisect start # Start bisection
git bisect bad # Mark current commit as broken
git bisect good v1.0 # Mark known-good commit
# Git checks out middle commit → you test → mark good/bad
# Binary search narrows to the exact commit!
git bisect reset # Stop bisecting
# Find which commit changed a specific line
git log -L 10,20:src/auth.js # History of lines 10-20
git blame src/auth.js # Who changed what, when
# Pick specific commits (copy changes from one branch to another)
git cherry-pick abc1234 # Apply commit abc1234 to current branch
git cherry-pick abc1234 def5678 # Apply multiple commits
# Edit the LAST commit (fix typo, add forgotten file)
git commit --amend # Modify last commit message + add staged changes
# ⚠️ Never amend pushed commits! Creates different history.
# Undo things safely
git revert abc1234 # Create NEW commit that undoes abc1234
# Safe: doesn't rewrite history, OK for shared branches
git reset --soft HEAD~1 # Undo last commit, keep changes staged
git reset --mixed HEAD~1 # Undo last commit, keep changes unstaged (default)
git reset --hard HEAD~1 # Undo last commit AND discard changes (DANGEROUS!)
# Recover from git reset --hard
git reflog # Shows ALL HEAD movements
git reset --hard HEAD@{1} # Go back to previous state
Branching Strategies
# Create and switch (the modern way)
git switch -c feature/user-auth # New branch + switch to it
git switch main # Switch to main
git switch - # Switch to previous branch
# Rename current branch
git branch -m new-name
# Delete branch
git branch -d feature/old # Safe: only if merged
git branch -D feature/old # Force: even if not merged
# Track remote branch
git switch --track origin/feature/xyz
# See all branches (including remote)
git branch -a
# Find merged branches (safe to delete)
git branch --merged main # Branches already in main
git branch --no-merged main # Branches NOT yet in main
Rebase: Clean History
# ⚠️ GOLDEN RULE: Never rebase shared/public branches!
# Only rebase YOUR feature branch.
# Rebase onto latest main
git switch feature/my-feature
git fetch origin
git rebase origin/main
# Your feature commits now come AFTER latest main commits
# Resolves: "merge commit" clutter in history
# Interactive rebase (SUPER powerful)
git rebase -i HEAD~5 # Edit last 5 commits
# Opens editor with:
# pick abc1234 feat: add login
# pick def5678 fix: typo in login
# pick ghi9012 feat: add validation
# pick jkl3456 fix: edge case
# pick mno7890 refactor: clean up
# You can:
# pick - Keep commit as-is
# squash - Combine with previous commit
# fixup - Combine (discard message)
# drop - Remove commit entirely
# reword - Change commit message
# edit - Pause to amend the commit
# Example: Squash fixup commits into feature commits
# pick abc1234 feat: add login
# fixup def5678 fix: typo in login ← merges into above
# pick ghi9012 feat: add validation
# fixup jkl3456 fix: edge case ← merges into above
# pick mno7890 refactor: clean up
# → Result: 3 clean commits instead of 5 messy ones
# Abort a rebase gone wrong
git rebase --abort
# Continue after resolving conflicts
git rebase --continue
Conflict Resolution
# When conflicts happen (during merge or rebase):
# 1. See what conflicts exist
git status
# both modified: src/auth.js
# both modified: src/utils.js
# 2. Open the files and look for conflict markers:
# <<<<<<< HEAD
# your version
# =======
# their version
# >>>>>>> feature-branch
# 3. Choose a resolution strategy:
# Strategy A: Use THEIR version entirely
git checkout --theirs src/auth.js
git add src/auth.js
# Strategy B: Use YOUR version entirely
git checkout --ours src/auth.js
git add src/auth.js
# Strategy C: Manual resolution (most common)
# Edit the file, remove conflict markers, keep what you want
# Then:
git add src/auth.js
git rebase --continue # or git commit for merge
# 4. Use a merge tool (much easier than manual!)
git mergetool # Opens VS Code/Beyond Compare/etc.
# Configure your tool:
git config --global merge.tool vscode
git config --global mergetool.vscode.cmd 'code --wait $MERGED'
Worktree: Multiple Branches at Once
# Problem: You're on feature-A and need to fix a bug on feature-B
# Without worktree: stash → switch → fix → switch back → unstash
# With worktree: both branches checked out simultaneously!
git worktree add ../hotfix main
# Creates ../hotfix directory with main branch checked out
# Your original directory keeps feature-A
cd ../hotfix
# Work on the hotfix independently
git commit -m "hotfix: critical bug"
git push origin main
# When done:
cd ../original-project
git worktree remove ../hotfix
# List all worktrees
git worktree list
Hooks: Automate Your Workflow
# Pre-commit hook: Run linter before every commit
# .git/hooks/pre-commit (make executable with chmod +x)
#!/bin/sh
# Run ESLint on staged files
npx eslint --staged
if [ $? -ne 0 ]; then
echo "❌ ESLint found errors. Fix them before committing."
exit 1
fi
# Pre-push hook: Run tests before pushing
#!/bin/sh
npm test
if [ $? -ne 0 ]; then
echo "❌ Tests failed. Not pushing."
exit 1
fi
# Install hooks automatically (with husky)
npx husky init
# Then add hooks:
echo "npx eslint ." > .husky/pre-commit
echo "npm test" > .husky/pre-push
# Commit-msg hook: Enforce conventional commits
#!/bin/sh
commit_msg=$(cat "$1")
if ! echo "$commit_msg" | grep -qE "^(feat|fix|docs|style|refactor|test|chore|perf)(\(.+\))?: "; then
echo "❌ Use conventional commit format: type(scope): message"
echo " Types: feat, fix, docs, style, refactor, test, chore, perf"
exit 1
fi
Searching Git History
# Find commits by message content
git log --all --grep="password" --oneline
# Find commits that changed a specific word
git log -S "password" --oneline
# "pickaxe" search: finds commits that added/removed the string
# Find which commit last modified a function
git log -L :functionName:src/file.js
# Show diff between branches
git diff main...feature-branch # Changes on feature branch since diverging
git diff main feature-branch # All differences between branches
# Show changes staged for next commit
git diff --staged
# Show only filenames that changed
git diff --name-only HEAD~3
# Beautiful patch output (for code review)
git format-patch HEAD~1..HEAD # Generate patch file
git send-email *.patch # Email patches (for mailing list projects)
Which git command here will you use tomorrow? What's your most-used git trick?
Follow @armorbreak for more practical developer guides.
Top comments (0)