Git Advanced: The Commands I Wish I Knew Earlier (2026)
Beyond add, commit, push. These are the Git commands that actually save time.
The Basics (Quick Refresher)
git status # What changed?
git diff # What exactly changed?
git log --oneline # Recent commits
git add -A # Stage everything
git commit -m "msg" # Commit staged changes
git push origin main # Send to remote
You know these. Let's go further.
Undo Everything (Safely)
# Unstage a file (keep changes)
git reset HEAD path/to/file
# Discard all unstaged changes in a file
git checkout -- path/to/file
# Or newer syntax:
git restore path/to/file
# Discard ALL unstaged changes
git checkout -- .
git restore .
# Uncommit (keep changes, remove commit)
git reset --soft HEAD~1 # Changes stay staged
git reset HEAD~1 # Changes stay unstaged
git reset --hard HEAD~1 # Changes GONE forever ⚠️
# Amend last commit (fix message or add forgotten file)
git commit --amend -m "Better message"
git add forgotten-file.txt
git commit --amend # Add file to previous commit
Interactive Rebase: Clean Up History
# Edit/reorder/squash last 5 commits
git rebase -i HEAD~5
# Opens editor with:
pick abc1234 First commit
pick def5678 Second commit
pick ghi9012 Third commit
pick jkl3456 Fourth commit
pick mno7890 Fifth commit
# Change 'pick' to:
# reword = edit commit message
# edit = pause to amend files
# squash = merge into previous commit
# fixup = merge into previous (discard this message)
# drop = remove commit entirely
# exec = run shell command
# Example: Squash the last 2 commits into one
pick abc1234 First commit
squash def5678 Second commit
# → Creates single commit with combined changes
Stashing: Save Work Without Committing
# Save current work temporarily
git stash
git stash push -m "WIP: feature X"
# List all stashes
git stash list
# stash@{0}: On main: WIP: feature X
# stash@{1}: On main: bugfix attempt
# Restore most recent stash
git stash pop # Apply + remove from list
git stash apply # Apply + keep in list
# Restore specific stash
git stash apply stash@{1}
# Drop a stash
git stash drop stash@{0}
# Clear all stashes
git stash clear
# Stash only some files (not everything)
git stash push -m "partial" src/utils.js src/config.js
# Stash with untracked files included
git stash push -u -m "include new files"
Searching Through History
# Search commit messages
git log --grep="bug fix" --oneline
git log --grep="auth" --since="2026-01-01"
# Search code content across all history
git log -S "functionName" --oneline # Added/removed this string
git log -G "pattern" --oneline # Changed matching this regex
git log -p -S "TODO" # Show actual diffs too
# Find which commit introduced a bug
git bisect start
git bisect bad # Current version has bug
git bisect good v1.0.0 # This version was fine
# Git will check out middle commit → you test → mark good/bad
# Repeat until it finds the exact bad commit
git bisect reset # When done
# Search current working tree
git grep "search term" # In tracked files
git grep "search term" $(git rev-list --all) # Across ALL history!
Branching Strategies That Work
Feature Branch Workflow
# Start a new feature
git checkout -b feature/user-auth
# Or:
git switch -c feature/user-auth
# Make commits...
git add -A && git commit -m "Add login page"
# Update your branch with latest main
git fetch origin
git rebase origin/main # Cleaner than merge for PRs
# Push branch (first time needs -u)
git push -u origin feature/user-auth
# After PR is merged, clean up
git branch -d feature/user-auth # Delete local
git push origin --delete feature/user-auth # Delete remote
Quick Branch Management
# See all branches (local + remote)
git branch -a
# Rename current branch
git branch -m old-name new-name
# Rename remote branch (after local rename)
git push origin :old-name new-name
# Switch to previous branch
git checkout -
# Or: git switch -
# Compare branches
git log main..feature-branch --oneline # Commits in feature but not main
git diff main...feature-branch # Diff between branch tips
# Merge vs Rebase summary:
# git merge feature → Creates merge commit, preserves exact history
# git rebase feature → Linear history, rewrites commits (cleaner for PRs)
Dealing with Remote Changes
# Fetch all remotes (doesn't merge)
git fetch --all
# Pull = fetch + merge
git pull origin main
# Pull with rebase (avoids extra merge commits)
git pull --rebase origin main
# Force push (⚠️ dangerous on shared branches!)
git push --force-with-lease origin feature-branch
# Safer than --force: checks if remote changed first
# Remove remote tracking branch that was deleted
git prune
git fetch --prune # Fetch + cleanup stale refs
Cherry-Picking: Grab Specific Commits
# Apply one commit from another branch
git cherry-pick abc1234
# Apply multiple commits
git cherry-pick abc1234 def5678 ghi9012
# Cherry-pick without committing (edit first)
git cherry-pick -n abc1234
# Make changes, then:
git commit -m "Modified cherry-pick"
# Cherry-pick from another repo (as patch)
git format-patch -1 abc1234 --stdout > /tmp/patch.git
git am < /tmp/patch.git
Fixing Mistakes in Committed Code
# Forgot to include a file in last commit?
git add forgotten-file.js
git commit --amend --no-edit
# Need to change an older commit? Use interactive rebase:
git rebase -i HEAD~5
# Change 'pick' to 'edit' on the target commit
# Make your changes
git add fixed-file.js
git rebase --continue
# Split a commit into two:
git rebase -i HEAD~3
# Change 'pick' to 'edit' on target commit
git reset HEAD~1 # Uncommit while keeping changes
git add file-a.js # Stage part of changes
git commit -m "Part A: file A"
git add file-b.js # Stage rest
git commit -m "Part B: file B"
git rebase --continue
Understanding .gitignore
# Patterns
node_modules/ # Directory
*.log # All .log files
!.important.log # Except this one
build/ # Build output
.env # Secrets (NEVER commit!)
.DS_Store # macOS junk
.vscode/ # Editor config (optional)
# Global ignore (for all repos)
git config --global core.excludesfile ~/.gitignore_global
# Debug what's being ignored
git check-ignore -v node_modules/debug.log
git status --ignored # Show ignored files too
# Track a file that's already .gitignored
git add -f important.log # Force add (-f overrides ignore rules)
# Stop tracking a file (but keep locally)
git rm --cached large-file.dat
# Then add to .gitignore
Useful Aliases
# Save typing with aliases
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.st status
git config --global alias.lg "log --graph --oneline --decorate -20"
git config --global alias.unstage "reset HEAD --"
git config --global alias.last "log -1 --stat"
git config --global alias.amend "commit --amend --no-edit"
git config --global alias.cleanup "!git branch --merged | grep -v '\\*\\|main\\|develop' | xargs git branch -d"
git config --global alias.discard "checkout --"
# Now use:
git co feature-branch # = git checkout
git lg # Beautiful graph log
git cleanup # Delete merged branches
git discard filename # Discard changes to file
Quick Reference Card
| Task | Command |
|---|---|
| Undo last commit (keep files) | git reset --soft HEAD~1 |
| Undo last commit (lose files) | git reset --hard HEAD~1 |
| Amend last commit | git commit --amend |
| Save work temporarily |
git stash / git stash pop
|
| Edit recent commits | git rebase -i HEAD~N |
| Find commit that added text | git log -S "text" |
| Compare branches | git diff main...feature |
| Clean merged branches | `git branch --merged \ |
| Safe force push | {% raw %}git push --force-with-lease
|
| Grab commit from other branch | git cherry-pick <sha> |
| Bisect to find bug commit | git bisect start/good/bad/reset |
Which Git command saved you the most time?
Follow @armorbreak for more practical developer guides.
Top comments (0)