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