Overview
Consistent git workflow prevents merge conflicts, maintains clean history, and enables easy rollbacks. The convention: main is always deployable, feature branches are short-lived.
Branch Strategy
main # production-ready, protected, requires PR
├── staging # pre-production (optional for teams)
├── feature/add-stripe-billing
├── fix/payment-webhook-signature
├── chore/update-dependencies
└── refactor/auth-middleware
Branch naming: type/short-description where type is feature, fix, chore, refactor, docs.
Commit Convention
type: short description (max 72 chars)
Optional body explaining WHY, not what.
Optional footer: BREAKING CHANGE, closes #issue
Types: feat, fix, chore, refactor, docs, test, perf, style
git commit -m "feat: add Stripe subscription checkout flow"
git commit -m "fix: webhook signature verification failing on POST body"
git commit -m "chore: update Next.js to 15.1.2"
git commit -m "refactor: extract auth middleware to shared utility"
Feature Branch Workflow
# Start from fresh main
git checkout main && git pull origin main
# Create branch
git checkout -b feature/add-export-csv
# Work, commit often
git add src/app/api/export/route.ts
git commit -m "feat: add CSV export API route"
git add src/components/ExportButton.tsx
git commit -m "feat: add export button to dashboard"
# Before PR: rebase on main to avoid conflicts
git fetch origin
git rebase origin/main
# Push
git push origin feature/add-export-csv
# Open PR via GitHub CLI
gh pr create --title "Add CSV export" --body "Closes #42"
PR Process
# Review PR
gh pr view 42
gh pr diff 42
# Check out PR locally
gh pr checkout 42
# Approve and merge (squash for clean history)
gh pr merge 42 --squash --delete-branch
Merge vs Rebase
| Operation | Result | Use When |
|-----------|--------|----------|
| git merge main | Merge commit, preserves history | Team branches, shared work |
| git rebase main | Linear history, rebases commits | Personal feature branches before PR |
| git merge --squash | Single commit for entire branch | Squash PRs, clean main history |
Rule: rebase personal branches before opening PRs. Never rebase shared/published branches.
Stash Workflow
# Save work in progress
git stash push -m "WIP: export feature, need to fix bug first"
# Switch to fix something
git checkout fix/urgent-bug
# ... fix ...
git checkout feature/add-export-csv
# Restore
git stash pop # pop most recent
git stash list # see all stashes
git stash apply stash@{1} # apply specific stash
git stash drop stash@{0} # delete specific stash
Worktrees for Parallel Work
# Work on bug fix without leaving feature branch
git worktree add ../hotfix-branch fix/payment-bug
# Do the fix in a separate directory
cd ../hotfix-branch
# ... work ...
git commit -m "fix: payment webhook"
git push
# Clean up
cd ../main-project
git worktree remove ../hotfix-branch
Common Recovery Operations
# Undo last commit (keep changes staged)
git reset --soft HEAD~1
# Undo last commit (keep changes unstaged)
git reset --mixed HEAD~1
# Undo last commit (discard changes) — DESTRUCTIVE
git reset --hard HEAD~1
# Revert a specific commit (safe for shared branches)
git revert abc1234
# Find lost commit (after accidental reset)
git reflog
git checkout -b recovery-branch abc1234
# Undo a file to last commit state
git checkout -- src/app/api/route.ts
# Discard all unstaged changes — DESTRUCTIVE
git checkout -- .
Interactive Rebase (Cleanup Before PR)
# Squash last 3 commits into one
git rebase -i HEAD~3
# In editor, change to:
# pick abc1234 feat: initial implementation
# squash def5678 WIP: progress
# squash ghi9012 fix typo
# Then write a proper commit message
.gitignore Standard for Next.js
# Dependencies
node_modules/
# Build
.next/
out/
dist/
# Env
.env.local
.env.*.local
.env.production
# Debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# OS
.DS_Store
Thumbs.db
# IDE
.vscode/
.idea/
*.swp
# Testing
coverage/
# Vercel
.vercel/
# Types
*.tsbuildinfo
next-env.d.ts
Alias Shortcuts
# Add to ~/.gitconfig or ~/.zshrc
git config --global alias.st status
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.lg "log --oneline --graph --decorate"
git config --global alias.undo "reset --soft HEAD~1"
git config --global alias.save "stash push"
git config --global alias.pop "stash pop"
Git Safety Rules
- Never create
.gitin home dir, Desktop, or drive root - Never force-push to
main - Never commit
.env.localor files with real secrets - Always verify
git statusbeforegit add . - Always verify
git diff --stagedbeforegit commit - When in doubt,
git stashbefore trying anything destructive