| name | git-advanced |
| description | Use when performing complex git operations -- rebasing, cherry-picking, resolving merge conflicts, bisecting bugs, managing stashes, cleaning history, or working with monorepos. Goes beyond basic commit/push/pull. |
Advanced Git Patterns
Quick Reference
| Task | Command |
|---|
| Rebase onto main | git rebase main |
| Interactive rebase (squash) | git rebase -i HEAD~N |
| Cherry-pick a commit | git cherry-pick <sha> |
| Find bug introduction | git bisect start |
| Stash with name | git stash push -m "description" |
| Undo last commit (keep changes) | git reset --soft HEAD~1 |
| See what changed in a file | git log -p -- path/to/file |
| Find who changed a line | git blame path/to/file |
Rebase Workflows
Rebase feature branch onto main
git checkout feature-branch
git fetch origin
git rebase origin/main
git push --force-with-lease
Use --force-with-lease instead of --force -- it refuses to push if someone else has pushed to the branch since your last fetch.
Interactive Rebase (clean up commits)
git rebase -i HEAD~5
In the editor:
pick abc1234 feat: add user model
squash def5678 fix typo in user model
squash ghi9012 more fixes
pick jkl3456 feat: add user routes
fixup mno7890 cleanup
| Command | Effect |
|---|
pick | Keep commit as-is |
squash | Merge into previous, combine messages |
fixup | Merge into previous, discard message |
reword | Keep commit, edit message |
drop | Remove commit entirely |
When to Rebase vs Merge
| Rebase | Merge |
|---|
| Your feature branch behind main | Integrating shared branches |
| Cleaning up local commits before PR | Preserving branch history matters |
| Linear history preferred | Multiple people on same branch |
| Your own branches only | Never on shared/public branches |
Conflict Resolution
Workflow
<<<<<<< HEAD
current changes
=======
incoming changes
>>>>>>> branch-name
# After resolving each file:
git add resolved-file.py
git rebase --continue # or git merge --continue
Strategy
- Read both sides -- understand what each change is trying to do
- Check the base --
git diff HEAD...branch to see the original intent
- Keep both when changes are in different logical sections
- Choose one when changes are mutually exclusive
- Rewrite when neither side is correct after the merge
- Run tests after resolving before continuing
Abort if stuck
git rebase --abort
git merge --abort
Cherry-Pick
Copy a specific commit to current branch:
git cherry-pick abc1234
git cherry-pick --no-commit abc1234
git cherry-pick abc1234..def5678
Use cases: hotfix from main to release branch, backport a fix.
Git Bisect (find bug introduction)
git bisect start
git bisect bad
git bisect good v1.0.0
git bisect good
git bisect bad
git bisect reset
Automate with a test script:
git bisect start HEAD v1.0.0
git bisect run pytest tests/test_broken.py
Stash Management
git stash push -m "WIP: auth refactor"
git stash list
git stash apply
git stash pop
git stash apply stash@{2}
git stash push -m "partial" -- file1.py file2.py
git stash branch new-branch stash@{0}
Undo Operations
| Want to Undo | Command | Destructive? |
|---|
| Last commit (keep changes staged) | git reset --soft HEAD~1 | No |
| Last commit (keep changes unstaged) | git reset HEAD~1 | No |
| Last commit (discard changes) | git reset --hard HEAD~1 | YES |
| Staged file | git restore --staged file | No |
| Unstaged changes to a file | git restore file | YES |
| A pushed commit | git revert <sha> | No (creates new commit) |
| A bad rebase | git reflog then git reset --hard <sha> | Recoverable |
Always prefer git revert over git reset for pushed commits. Revert creates a new commit that undoes the change, preserving history.
Reflog (emergency recovery)
git reflog
git reset --hard ghi9012
The reflog keeps ~90 days of history. If you lost something, it's probably here.
History Exploration
git log --oneline -- path/to/file
git log --grep="fix login"
git log -S "functionName" --oneline
git blame path/to/file
git blame -w -M path/to/file
git diff main...feature-branch
Anti-Patterns
| Don't | Do Instead |
|---|
git push --force on shared branches | git push --force-with-lease on your own branches only |
| Rebase public/shared branches | Only rebase your own feature branches |
| Resolve conflicts by accepting "ours" blindly | Read both sides and merge intentionally |
| Stash and forget | Name stashes, clean up regularly with git stash drop |
git reset --hard without checking reflog | Use --soft first, escalate to --hard only when sure |
| Giant squash of entire branch | Squash related commits, keep logical units separate |