You know git add, commit, push, and pull. That gets you through 90% of daily work. But the remaining 10%—untangling merge conflicts, finding bug introductions, managing multiple branches simultaneously—requires deeper knowledge.

Interactive Rebase

The most powerful tool for cleaning up history before sharing.

1
2
3
4
5
# Rebase last 5 commits
git rebase -i HEAD~5

# Rebase onto main
git rebase -i main

The editor opens with commits listed oldest-first:

pppppiiiiiccccckkkkkadgjmbehkncfilo15937260483715948260AFAWAdidIddxdPdutudusysesepeberorurgmicgtonoiednnseutgtlsrseorllmeordel

Commands:

  • pick — keep commit as-is
  • reword — edit commit message
  • edit — stop to amend commit
  • squash — combine with previous commit
  • fixup — combine with previous, discard message
  • drop — remove commit

Clean Up Before PR

pfpdpiiiricxcockukpkpagjmbdhknceilo1f9372504836159472608AAWAdFdIddidPdxuudustseseyeberprurogmcgtoioiednnnsetgtlurssoelrlemrodel

Result: 3 clean commits instead of 5 messy ones.

Auto-Squash

Mark commits for automatic squashing:

1
2
3
4
5
# Create a fixup commit
git commit --fixup abc1234

# Later, auto-squash during rebase
git rebase -i --autosquash main

Git Bisect

Find exactly which commit introduced a bug using binary search.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# Start bisecting
git bisect start

# Mark current commit as bad
git bisect bad

# Mark known good commit
git bisect good v1.0.0

# Git checks out middle commit. Test it, then:
git bisect good  # if bug not present
git bisect bad   # if bug present

# Repeat until Git finds the culprit
# When done:
git bisect reset

Automated Bisect

1
2
3
4
5
# Run a test script automatically
git bisect start HEAD v1.0.0
git bisect run ./test-for-bug.sh

# Script should exit 0 for good, 1 for bad

Example test script:

1
2
3
#!/bin/bash
# test-for-bug.sh
make build && ./myapp --test-case | grep -q "expected output"

Worktrees

Work on multiple branches simultaneously without stashing or cloning.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Create worktree for a branch
git worktree add ../myproject-feature feature-branch

# Create worktree with new branch
git worktree add -b hotfix ../myproject-hotfix main

# List worktrees
git worktree list

# Remove worktree
git worktree remove ../myproject-feature

Use cases:

  • Review PR while working on your own feature
  • Run tests on one branch while developing on another
  • Compare behavior between branches side-by-side

Reflog: Your Safety Net

Git keeps a log of every HEAD movement. Accidentally deleted a branch? Reset too hard? Reflog has your back.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# View reflog
git reflog

# Output:
# abc1234 HEAD@{0}: reset: moving to HEAD~3
# def5678 HEAD@{1}: commit: Add feature
# ghi9012 HEAD@{2}: checkout: moving from main to feature

# Recover "lost" commits
git checkout HEAD@{1}
git branch recovered-branch HEAD@{1}

# Undo a reset
git reset --hard HEAD@{1}

Reflog entries expire (default 90 days), so act quickly for recovery.

Cherry-Pick

Apply specific commits from one branch to another.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Single commit
git cherry-pick abc1234

# Multiple commits
git cherry-pick abc1234 def5678

# Range of commits
git cherry-pick abc1234^..ghi9012

# Without committing (stage changes only)
git cherry-pick -n abc1234

Handling Conflicts

1
2
3
4
5
6
7
git cherry-pick abc1234
# CONFLICT - resolve files
git add resolved-file.txt
git cherry-pick --continue

# Or abort
git cherry-pick --abort

Stash Techniques

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# Basic stash
git stash

# Stash with message
git stash push -m "WIP: feature work"

# Stash including untracked files
git stash -u

# Stash including ignored files
git stash -a

# List stashes
git stash list

# Apply most recent stash (keep in list)
git stash apply

# Apply and remove from list
git stash pop

# Apply specific stash
git stash apply stash@{2}

# Show stash contents
git stash show -p stash@{0}

# Create branch from stash
git stash branch new-branch stash@{0}

# Drop specific stash
git stash drop stash@{0}

# Clear all stashes
git stash clear

Partial Stash

1
2
# Interactively select hunks to stash
git stash -p

Advanced Log

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# Graph view
git log --oneline --graph --all

# Search commit messages
git log --grep="bug fix"

# Search code changes
git log -S"functionName"

# Commits touching specific file
git log -- path/to/file.py

# Commits by author
git log --author="Alice"

# Commits in date range
git log --since="2024-01-01" --until="2024-06-01"

# Pretty format
git log --pretty=format:"%h %an %s" --date=short

# Show files changed
git log --stat

# Show patch (diff)
git log -p

# Commits on branch A not on B
git log main..feature

# Commits on either branch but not both
git log main...feature

Blame and History

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# Who changed each line
git blame file.py

# Ignore whitespace changes
git blame -w file.py

# Show original commit (before moves/copies)
git blame -C file.py

# Blame specific lines
git blame -L 10,20 file.py

# Show when lines were deleted
git log -p -S"deleted text" -- file.py

Rewriting History

Amend Last Commit

1
2
3
4
5
6
# Change message
git commit --amend -m "New message"

# Add forgotten files
git add forgotten.txt
git commit --amend --no-edit

Change Author

1
2
3
4
5
6
7
8
# Last commit
git commit --amend --author="Name <email@example.com>"

# Multiple commits (interactive rebase + edit)
git rebase -i HEAD~5
# Mark commits as 'edit', then for each:
git commit --amend --author="Name <email>"
git rebase --continue

Filter-Branch (Nuclear Option)

Remove sensitive data from entire history:

1
2
3
4
5
6
7
8
# Remove file from all history
git filter-branch --force --index-filter \
  "git rm --cached --ignore-unmatch secrets.txt" \
  --prune-empty --tag-name-filter cat -- --all

# Better alternative: git-filter-repo
pip install git-filter-repo
git filter-repo --path secrets.txt --invert-paths

Warning: This rewrites all commit hashes. Coordinate with your team.

Submodules

Include other repositories within yours.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# Add submodule
git submodule add https://github.com/user/repo libs/repo

# Clone repo with submodules
git clone --recurse-submodules https://github.com/user/main-repo

# Initialize submodules after clone
git submodule update --init --recursive

# Update submodules to latest
git submodule update --remote

# Run command in all submodules
git submodule foreach 'git checkout main && git pull'

Hooks

Automate tasks at various Git events.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# Hooks live in .git/hooks/
ls .git/hooks/

# Example: pre-commit hook
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/bash
# Run tests before commit
npm test
if [ $? -ne 0 ]; then
    echo "Tests failed, commit aborted"
    exit 1
fi
EOF
chmod +x .git/hooks/pre-commit

Common hooks:

  • pre-commit — run linters, tests
  • commit-msg — validate commit message format
  • pre-push — run full test suite
  • post-merge — install dependencies after pull

For team-wide hooks, use tools like husky or pre-commit.

Aliases

Add to ~/.gitconfig:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
[alias]
    # Short commands
    co = checkout
    br = branch
    ci = commit
    st = status
    
    # Useful logs
    lg = log --oneline --graph --all --decorate
    hist = log --pretty=format:'%h %ad | %s%d [%an]' --date=short
    
    # Undo last commit (keep changes)
    undo = reset HEAD~1 --soft
    
    # Amend without editing message
    amend = commit --amend --no-edit
    
    # Show branches with last commit
    branches = branch -v
    
    # Clean merged branches
    cleanup = "!git branch --merged | grep -v '\\*\\|main\\|master' | xargs -n 1 git branch -d"
    
    # What did I do today?
    today = log --since=midnight --author='Your Name' --oneline

Troubleshooting

Undo Almost Anything

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# Undo last commit, keep changes staged
git reset --soft HEAD~1

# Undo last commit, keep changes unstaged
git reset HEAD~1

# Undo last commit, discard changes
git reset --hard HEAD~1

# Undo a pushed commit (creates new commit)
git revert abc1234

# Undo merge
git reset --hard ORIG_HEAD

Fix Detached HEAD

1
2
3
4
# You're on a detached HEAD and want to keep changes
git branch my-work
git checkout main
git merge my-work

Resolve Merge Conflicts

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# See conflict markers
git diff

# Use ours/theirs
git checkout --ours file.txt
git checkout --theirs file.txt

# Abort merge
git merge --abort

# After resolving
git add file.txt
git merge --continue

Clean Up

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Remove untracked files (dry run)
git clean -n

# Remove untracked files
git clean -f

# Remove untracked files and directories
git clean -fd

# Remove ignored files too
git clean -fdx

These tools transform Git from a simple backup system into a powerful history manipulation toolkit. Interactive rebase alone will change how you think about commits.

Start with git reflog—knowing your safety net exists makes experimentation less scary. Then practice interactive rebase on a throwaway branch until it feels natural.

The goal isn’t to memorize commands. It’s to know what’s possible so you can look up the syntax when you need it.