Most Git workflow problems come from not understanding what the tools actually do, not from choosing the wrong strategy. Learn the mechanics and the strategy becomes obvious.
Branching model
Use a simple trunk-based workflow:
main ← production-ready
└── feature/short-description ← your work
mainis always deployable- Feature branches are short-lived (hours to days, not weeks)
- Delete branches after merge
- Never commit directly to
main
Branch naming: type/short-description
feat/user-avatar-upload
fix/checkout-timeout
chore/update-deps
Merge vs rebase
Rebase to clean up your local commits before sharing:
git rebase -i main
This rewrites history on your branch only. Safe because nobody else has your commits yet.
Merge to bring feature branches together:
git merge feature/branch
Creates a merge commit that ties the histories together.
The rule: rebase your own unpushed commits, merge everything else.
Never rebase commits that are already on main or shared with others.
Interactive rebase
Clean up a messy branch before opening a PR:
git rebase -i HEAD~5
Common operations:
pick→ keep the commit as-issquash→ combine with the previous commitfixup→ like squash but discard the commit messagereword→ keep the commit, edit the messagedrop→ remove the commit entirely
Workflow:
- Squash “WIP” and “fix typo” commits into the meaningful ones
- Rewrite commit messages to follow conventions
- Reorder commits so the logical flow is clear
Stashing
Save work-in-progress without committing:
git stash push -m "WIP: halfway through refactor"
git stash list
git stash pop
Use stashes for context switches, not long-term storage. If a stash exists for more than a day, it should be a commit or thrown away.
Recovery
Undo a commit (keep changes):
git reset --soft HEAD~1
Undo a commit (discard changes):
git reset --hard HEAD~1
Recover a deleted branch:
git reflog
git checkout -b recovered-branch <sha>
Undo a bad rebase:
git reflog
git reset --hard <pre-rebase-sha>
The reflog is your safety net. Almost nothing is permanently lost in Git.
See references/interactive-rebase.md for more rebase patterns.
When it triggers
- merging branches
- rebasing onto main
- cleaning up commit history
- recovering from a bad rebase