Git Advanced: The Commands I Wish I Knew Earlier (2026)
Beyond commit, push, and pull. These are the commands that make you significantly more productive.
Rewriting History (Safe & Useful)
# Amend the last commit (fix typo, add forgotten file)
git commit --amend -m "Better message"
# or: git add forgotten-file && git commit --amend --no-edit
# Interactive rebase — the most powerful Git command
git rebase -i HEAD~3
# Opens editor with last 3 commits:
#
# pick abc1234 Initial implementation
# pick def5678 Add feature X
# pick ghi9012 Fix bug in feature X
#
# Available commands:
# p, pick = use commit as-is
# r, reword = change message only
# e, edit = stop here to amend/split
# s, squash = merge into previous commit
# f, fixup = merge into previous (discard message)
# d, drop = remove commit entirely
# Example: Squash "Fix bug" into "Add feature X"
# Change line to: s ghi9012
# Result: One clean commit with both changes
# Reorder commits (just move lines in the editor)
# Split a commit (mark as 'e', then reset HEAD~1, create multiple commits)
# ⚠️ Only rebase local history! Never rebase pushed/shared commits.
Searching Through History
# Search commit messages
git log --grep="bug" --oneline # Messages containing "bug"
git log --grep="auth" --since="2026-01-01" --oneline # Time-bounded
# Search code changes (find which commit changed something)
git log -S "functionName" --oneline # When was this text added/removed?
git log -G "pattern" --oneline # Regex search through diffs
git log -p -S "API_KEY" # Show actual diff of when it appeared
# Search file history
git log --follow -- filename # Track across renames
git show abc1234:path/to/file # View file at specific commit
git diff main..feature --stat # What files changed between branches?
# Who wrote this line? (blame)
git blame filename # Line-by-line authorship
git blame -L 10,20 filename # Lines 10-20 only
git blame -e filename # Show email addresses
# Find commits by author/time
git log --author="Alice" --oneline # Commits by specific person
git log --after="2026-05-01" --before="2026-06-01" --oneline # Date range
Stashing Like a Pro
# Basic stash
git stash # Save working directory changes
git stash save "WIP: auth feature" # With descriptive message
git stash list # List all stashes
git stash pop # Apply and remove most recent
git stash apply # Apply but keep in list
git stash drop # Remove without applying
git stash clear # Remove ALL stashes
# Stash specifics (not everything)
git stash -m "temp" -- filename # Stash only one file
git stash -u # Include untracked files too
git stash -k # Keep changes in working dir AND stash
# Work with multiple stashes
git stash show stash@{2} # Preview what's in stash #2
git stash apply stash@{1} # Apply specific stash
git stash branch new-branch stash@{0} # Create branch from stash
# Practical use case: Emergency context switch
# You're mid-feature, boss needs a hotfix NOW
git stash -m "WIP: feature 80% done"
git checkout -b hotfix/critical-bug
# ... fix, commit, push ...
git checkout feature-branch
git stash pop # Back where you left off!
Recovering from Mistakes
# I committed to the wrong branch!
git reset --soft HEAD~1 # Undo commit, keep changes staged
git checkout correct-branch
git commit # Commit on right branch
# I pushed to the wrong branch!
git reset --soft HEAD~1 # Undo the bad commit
git checkout correct-branch
git commit
git push origin correct-branch # Push to correct branch
git push origin --force wrong-branch # Remove from wrong branch (⚠️ destructive!)
# I need to undo a pushed commit (clean up history)
git revert abc1234 # Creates NEW commit that undoes the change
# Safer than force-push! Preserves history.
# I deleted a file I need back!
git checkout -- filename # Restore from last commit
git checkout abc1234 -- filename # Restore from specific commit
git reflog # Find lost commits
git checkout abc1234 # Recover any past state
# reflog is your safety net!
git reflog # Shows EVERY state your HEAD has been
# abc1234 HEAD@{0}: commit: Add feature
# def5678 HEAD@{1}: commit: Fix typo
# ghi9012 HEAD@{2}: reset: moving to HEAD~1
git checkout -b recovery ghi9012 # Restore "lost" commit
Branching Strategies
# Create branch from specific point
git checkout -b feature-x abc1234 # Branch from that commit
# Compare branches
git log main..feature --oneline # Commits in feature but not in main
git diff main...feature # Diff between branch tips (triple-dot)
# Merge vs Rebase vs Squash Merge
git merge feature # Creates merge commit (preserves history)
git rebase main # Linear history (rewrites feature's commits)
git merge --squash feature # One commit on main (clean but loses detail)
# Cherry-pick specific commits
git cherry-pick abc1234 # Apply one commit from another branch
git cherry-pick abc1234 def5678 # Apply multiple
git cherry-pick --no-commit abc1234 # To staging area (edit before committing)
# Clean up merged branches
git branch --merged | grep -v 'main' | xargs git branch -d # Delete merged branches
git branch -d feature-x # Delete merged branch safely
git branch -D feature-y # Force delete unmerged branch
# Rename branch (local + remote)
git branch -m old-name new-name # Rename locally
git push origin --delete old-name # Delete old remote
git push origin new-name # Push new remote
Worktrees: Parallel Development
# Why worktrees?
# → Work on two features simultaneously without stashing
# → Test a hotfix while keeping current work intact
# → Run long builds on separate checkouts
# Create worktree
git worktree add ../feature-a feature/branch-a # New directory, different branch
git worktree add ../hotfix main # Start from main
# Now you have three independent working directories:
# ./project/ (your current work)
# ../feature-a/ (feature A development)
# ../hotfix/ (urgent hotfix on main)
# Manage worktrees
git worktree list # Show all worktrees
git worktree remove ../feature-a # Done with this worktree
git worktree prune # Remove stale worktree refs
# Practical workflow:
# 1. Working on feature, urgent bug comes in
# 2. git worktree add ../fix main
# 3. cd ../fix; implement fix; test; commit; push
# 4. cd ../../project; continue where you were
Bisect: Find the Breaking Commit
# When did this bug appear? Don't guess — use bisect!
git bisect start
git bisect bad # Current version has the bug
git bisect good v2.0.0 # This version was fine
# Git will checkout commits automatically.
# For each one, test if the bug exists:
git bisect good # This commit is fine
git bisect bad # Bug is present here
# Eventually Git tells you exactly which commit introduced the bug:
# abc1234 is the first bad commit
# commit description here...
git bisect reset # Done, return to original branch
# Automated bisect (for reproducible bugs):
git bisect start
git bisect bad
git bisect good v2.0.0
git bisect run npm test # Auto-run tests on each checkout
# Git finds the breaking commit without manual intervention!
Hooks: Automate Quality Checks
# Hook locations: .git/hooks/
# Enable a hook: copy it and make executable
# Pre-commit (runs before every commit)
#!/bin/bash
# .git/hooks/pre-commit
npm run lint || exit 1 # Block commit if lint fails
npm run typecheck || exit 1 # Block if types wrong
echo "✅ Pre-commit checks passed"
# Commit-msg (enforce conventional commits)
#!/bin/bash
# .git/hooks/commit-msg
if ! grep -qE "^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\(.+\))?: .+" "$1"; then
echo "❌ Invalid commit message!"
echo "Format: type(scope): description"
echo "Types: feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert"
exit 1
fi
# Pre-push (run tests before pushing)
#!/bin/bash
npm test || {
echo "❌ Tests failed! Push aborted."
exit 1
}
# Install hooks automatically (for team):
# npx husky init # Modern hook manager
# husky add .husky/pre-commit "npm run lint"
# husky add .husky/pre-push "npm test"
# Or use simple-git-hooks (package.json config):
# "simple-git-hooks": { "pre-commit": "npx lint-staged", "pre-push": "npm test" }
Must-Have Aliases
# Add these to ~/.gitconfig [alias] section:
[alias]
co = checkout
br = branch
ci = commit
st = status
l = log --oneline --graph -15
unstage = reset HEAD --
amend = commit --amend --no-edit
prune-all = !git remote | xargs -n1 git remote prune
undo = reset --soft HEAD~1
diffc = diff --cached
recent = branch --sort=-committerdate -10
cleanup = !git branch --merged | grep -v '\\*\\|main\\|develop' | xargs git branch -d
# My daily top 5:
# git co feature/new → checkout
# git st → quick status
# git l → pretty graph log
# git recent → recently worked branches
# git cleanup -> delete old merged branches
What's your favorite Git trick? Which one here is new to you?
Follow @armorbreak for more practical developer guides.
Top comments (0)