
Git Workflow
- 24 installs
- 213 repo stars
- Updated August 4, 2026
- yonatangross/skillforge-claude-plugin
This is a copy of git-workflow by yonatangross - installs and ranking accrue to the original listing.
Helps with automation & workflows tasks.
About
git-workflow is a Claude Code skill for automation & workflows. It helps solo builders move faster with AI-assisted coding.
- git-workflow
- Automation & Workflows
- AI-coding skill
Git Workflow by the numbers
- 24 all-time installs (skills.sh)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/yonatangross/skillforge-claude-plugin --skill git-workflowAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 24 |
|---|---|
| repo stars | ★ 213 |
| Last updated | August 4, 2026 |
| Repository | yonatangross/skillforge-claude-plugin ↗ |
What it does
Helps with automation & workflows tasks.
Files
Git Workflow
Complete git workflow patterns: GitHub Flow branching, atomic commits, and recovery operations. Essential for maintaining clean, reviewable history.
Argument Resolution
SUBCOMMAND = "$ARGUMENTS[0]" # Optional subcommand, e.g., "recovery", "branch", "stacked"
# If no arguments, show full workflow reference.
# $ARGUMENTS is the full string (CC 2.1.59 indexed access)Branch Naming Convention
# Feature branches (link to issue)
issue/<number>-<brief-description>
issue/123-add-user-auth
# When no issue exists
feature/<description>
fix/<description>
hotfix/<description>Branch Rules: 1. main is always deployable 2. Branch from main, PR back to main 3. Branches live < 1-3 days 4. Delete branch after merge
---
Atomic Commit Checklist
[ ] Does ONE logical thing
[ ] Leaves codebase working (tests pass)
[ ] Message doesn't need "and" in title
[ ] Can be reverted independently
[ ] Title < 50 chars, body wraps at 72Interactive Staging
# Stage changes hunk-by-hunk
git add -p
# Options:
# y - stage this hunk
# n - skip this hunk
# s - split into smaller hunks
# e - manually edit the hunk
# q - quit
# Review what's staged
git diff --staged # What will be committed
git diff # What won't be committedCommit Patterns
# Separate concerns
git add -p && git commit -m "refactor: Extract database pool"
git add -p && git commit -m "feat(#456): Add query caching"
# Never combine unrelated changes
# BAD: "feat: Add auth and fix formatting"
# GOOD: Two separate commits---
Recovery Quick Reference
The Safety Net
# ALWAYS check reflog first - it has everything
git reflog
# Shows ALL recent HEAD movements
# Even "deleted" commits live here for 90 daysCommon Recovery Scenarios
| Scenario | Not Pushed | Already Pushed |
|---|---|---|
| Undo commit | git reset --soft HEAD~1 | git revert HEAD |
| Wrong branch | cherry-pick + reset | cherry-pick + revert |
| Lost commits | git reset --hard HEAD@{N} | N/A |
| Bad rebase | git rebase --abort or reflog | reflog + force-with-lease |
Quick Recovery Commands
# Undo last commit, keep changes staged
git reset --soft HEAD~1
# Find lost commits
git reflog | grep "your message"
# Recover to previous state
git reset --hard HEAD@{1}
# Safe force push (feature branches only)
git push --force-with-lease---
Standard Workflow
# 1. Start fresh
git checkout main && git pull origin main
git checkout -b issue/123-my-feature
# 2. Work with atomic commits
git add -p
git commit -m "feat(#123): Add User model"
# 3. Stay updated
git fetch origin && git rebase origin/main
# 4. Push and PR
git push -u origin issue/123-my-feature
gh pr create --fill
# 5. Cleanup after merge
git checkout main && git pull
git branch -d issue/123-my-feature---
Anti-Patterns
Avoid:
- Long-lived branches (> 1 week)
- Merging main into feature (use rebase)
- Direct commits to main
- Force push to shared branches
- Commits that need "and" in message
- Committing broken code---
Best Practices Summary
1. Branch from main - Always start fresh 2. Stage interactively - Use git add -p 3. One thing per commit - If you say "and", split it 4. Rebase, don't merge - Keep history clean 5. Check reflog first - When something goes wrong 6. Force-with-lease - Safer than force push 7. Delete after merge - No stale branches
Related Skills
ork:commit- Create commits with conventional format and pre-commit validationgit-recovery- Quick recovery from common git mistakes using reflog operationsstacked-prs- Multi-PR development for large features with dependent PRsork:create-pr- Comprehensive PR creation with proper formatting
Key Decisions
| Decision | Choice | Rationale |
|---|---|---|
| Branching model | GitHub Flow | Simple single-branch workflow, main is always deployable |
| Merge strategy | Rebase over merge | Keeps history clean and linear, easier to bisect |
| Branch naming | issue/<number>-<desc> | Links work to tracking, enables automation |
| Commit granularity | Atomic (one thing) | Independent revert, clear history, easier review |
| Force push | --force-with-lease only | Prevents overwriting others' work on shared branches |
Rules
Each category has individual rule files in rules/ loaded on-demand:
| Category | Rule | Impact | Key Pattern |
|---|---|---|---|
| Branch Protection | ${CLAUDE_PLUGIN_ROOT}/skills/git-workflow/rules/branch-protection.md | CRITICAL | Protected branches, required PR workflow |
| Merge Strategy | ${CLAUDE_PLUGIN_ROOT}/skills/git-workflow/rules/merge-strategy.md | HIGH | Rebase-first, conflict resolution, force-with-lease |
| History Hygiene | ${CLAUDE_PLUGIN_ROOT}/skills/git-workflow/rules/history-hygiene.md | HIGH | Squash WIP, fixup commits, clean history |
| Recovery | ${CLAUDE_PLUGIN_ROOT}/skills/git-workflow/rules/recovery-reflog.md | CRITICAL | Reflog recovery for lost commits and branches |
| Recovery | ${CLAUDE_PLUGIN_ROOT}/skills/git-workflow/rules/recovery-reset.md | CRITICAL | Safe vs dangerous reset modes |
| Recovery | ${CLAUDE_PLUGIN_ROOT}/skills/git-workflow/rules/recovery-stash.md | HIGH | Stash management and dropped stash recovery |
| Stacked PRs | ${CLAUDE_PLUGIN_ROOT}/skills/git-workflow/rules/stacked-pr-workflow.md | HIGH | Stack planning, PR creation, dependency tracking |
| Stacked PRs | ${CLAUDE_PLUGIN_ROOT}/skills/git-workflow/rules/stacked-pr-rebase.md | HIGH | Rebase management, force-with-lease, retargeting |
| Monorepo | ${CLAUDE_PLUGIN_ROOT}/skills/git-workflow/rules/monorepo-context.md | MEDIUM | --add-dir, per-service CLAUDE.md, workspace detection |
Total: 9 rules across 6 categories
References
Load on demand with Read("${CLAUDE_PLUGIN_ROOT}/skills/git-workflow/references/<file>"):
| File | Content |
|---|---|
github-flow.md | GitHub Flow branching guide |
interactive-staging.md | Interactive staging patterns |
reflog-recovery.md | Reflog recovery techniques |
recovery-decision-tree.md | Recovery scenario decision tree |
Checklists
Load on demand with Read("${CLAUDE_PLUGIN_ROOT}/skills/git-workflow/checklists/<file>"):
| File | Content |
|---|---|
branch-checklist.md | Pre-flight checks before creating branches |
pre-commit-checklist.md | Validation before committing |
Branch Checklist
Pre-flight checks before creating and working with branches.
Before Creating a Branch
[ ] main is up to date (`git pull origin main`)
[ ] No uncommitted changes (`git status` is clean)
[ ] Issue/ticket exists for the work
[ ] Branch name follows conventionBranch Naming Validation
# Valid patterns
issue/123-add-user-auth # Linked to issue (preferred)
feature/oauth-integration # No issue, feature work
fix/null-pointer-api # Bug fix
hotfix/security-patch # Urgent production fix
# Invalid patterns
my-branch # No prefix
ISSUE-123 # Wrong format
feature/Add_User_Auth # No underscores/capitalsQuick Validation
# Check branch name format
BRANCH=$(git branch --show-current)
if [[ ! "$BRANCH" =~ ^(issue|feature|fix|hotfix|release)/ ]]; then
echo "WARNING: Branch '$BRANCH' doesn't follow naming convention"
fiBefore First Commit
[ ] Correct branch (not main/dev)
[ ] Branch tracks remote (`git push -u origin <branch>`)
[ ] Working directory is clean except intended changesBefore Push
[ ] All tests pass locally
[ ] No debug code (console.log, print, debugger)
[ ] No secrets or credentials
[ ] Commits are atomic (one logical change each)
[ ] Commit messages follow conventional formatBefore PR
[ ] Branch rebased on latest main
[ ] No merge conflicts
[ ] CI passing on branch
[ ] Self-reviewed the diff
[ ] Issue linked in PR descriptionBranch Lifecycle
1. Create → git checkout -b issue/123-feature
2. Work → atomic commits, frequent pushes
3. Sync → git fetch && git rebase origin/main
4. PR → gh pr create
5. Review → address feedback
6. Merge → squash or rebase merge
7. Cleanup → git branch -d issue/123-featureEmergency: Wrong Branch
# Accidentally committed to main?
# 1. Create branch from current state
git branch fix/my-changes
# 2. Reset main to origin
git reset --hard origin/main
# 3. Switch to new branch
git checkout fix/my-changesRelated
- GitHub Flow
- Recovery Decision Tree
Pre-Commit Checklist
Validation steps before creating a commit.
Atomic Commit Check
[ ] Does ONE logical thing (no "and" in description)
[ ] Can be reverted independently
[ ] Leaves codebase in working state
[ ] Tests pass after this commitSigns of Non-Atomic Commits
BAD: "Add auth and fix typos" → Split into 2 commits
BAD: "Refactor users, update tests" → Split into 2 commits
BAD: "WIP" → Finish or stash
GOOD: "feat(auth): Add JWT validation" → Single concernStaged Changes Review
# What's staged (will be committed)
git diff --staged
# What's NOT staged (will NOT be committed)
git diff
# Files overview
git statusInteractive Staging
# Stage hunks selectively
git add -p
# Keybindings:
# y = stage this hunk
# n = skip this hunk
# s = split into smaller hunks
# e = edit hunk manually
# q = quit (staged so far remains)Commit Message Format
<type>(<scope>): <description>
[optional body]
[optional footer]Valid Types
| Type | Use For |
|---|---|
feat | New feature |
fix | Bug fix |
docs | Documentation only |
style | Formatting (no code change) |
refactor | Code change (no feature/fix) |
test | Adding/fixing tests |
chore | Build, deps, tooling |
Message Rules
[ ] Title < 50 characters
[ ] Title uses imperative mood ("Add" not "Added")
[ ] Title doesn't end with period
[ ] Body wraps at 72 characters
[ ] Body explains WHY, not WHAT
[ ] Footer references issues (Closes #123)Examples
# Good
git commit -m "feat(api): Add rate limiting to /users endpoint"
# With body (use editor or heredoc)
git commit -m "$(cat <<'EOF'
fix(auth): Handle expired refresh tokens gracefully
Previously, expired refresh tokens caused 500 errors. Now returns
401 with clear error message and invalidates the session.
Closes #456
EOF
)"Final Checks
# Verify staged content is correct
git diff --staged --stat
# Verify not committing to protected branch
BRANCH=$(git branch --show-current)
if [[ "$BRANCH" =~ ^(main|master|dev|develop)$ ]]; then
echo "ERROR: Cannot commit directly to $BRANCH"
exit 1
fi
# Check for debug code
git diff --staged | grep -E "(console\.log|debugger|print\(|pdb)" && \
echo "WARNING: Debug code detected"
# Check for secrets
git diff --staged | grep -iE "(password|secret|api.?key|token)" && \
echo "WARNING: Possible secrets detected"Quick Commit Flow
# 1. Review changes
git status
git diff
# 2. Stage selectively
git add -p
# 3. Verify staged
git diff --staged
# 4. Commit with message
git commit -m "feat(scope): Description"
# 5. Verify commit
git log --oneline -1
git show --statUndo Last Commit
# Keep changes staged
git reset --soft HEAD~1
# Keep changes unstaged
git reset HEAD~1
# Discard everything (DANGEROUS)
git reset --hard HEAD~1Related
- Interactive Staging
- Recovery Decision Tree
GitHub Flow Guide
The recommended branching strategy for most teams in 2026.
Core Principles
1. main is always deployable 2. Branch for every change 3. Short-lived branches (< 3 days) 4. PR for all changes 5. Delete after merge
Workflow Diagram
main ─────●───────●───────●───────●───────●──────
\ / \ / \ / \ /
●───● ●───● ●───● ●───●
issue/ fix/ feat/ hotfix/
123 456 789 critical
1-2 0.5 2-3 0.5
days days days daysDaily Workflow
Morning
git checkout main
git pull origin main
git checkout -b issue/123-my-taskDuring Day
# Make changes, commit atomically
git add -p
git commit -m "feat(#123): Part 1"
# Stay updated with main
git fetch origin
git rebase origin/mainEnd of Day (or when ready)
# Push and create PR
git push -u origin issue/123-my-task
gh pr create --fillAfter Merge
git checkout main
git pull origin main
git branch -d issue/123-my-taskWhy Not GitFlow?
| GitFlow | GitHub Flow |
|---|---|
| develop + main + release + hotfix | Just main |
| Complex merging | Simple merging |
| Scheduled releases | Continuous deployment |
| Merge conflicts | Few conflicts |
| Weeks-long branches | Days-long branches |
When to Use Release Branches
Only for:
- Supporting multiple versions (v1.x, v2.x)
- Regulatory compliance requiring sign-off
- Mobile apps with app store review cycles
# Create release branch only when needed
git checkout -b release/v1.2 main
# Cherry-pick specific fixes
git cherry-pick abc1234Feature Flags Integration
When feature takes > 3 days:
// Merge incomplete work behind flag
if (process.env.FF_NEW_FEATURE) {
return <NewFeature />;
}
return <CurrentFeature />;This allows:
- Merging to main daily
- Testing in production (flag off)
- Gradual rollout (flag percentage)
- Instant rollback (disable flag)
Interactive Staging with git add -p
Master git add -p (patch mode) for precise, atomic commits.
Basic Usage
git add -p # Stage all modified files interactively
git add -p file.ts # Stage specific file interactivelyPrompt Options
When Git shows each hunk, you can respond with:
| Key | Action |
|---|---|
y | Stage this hunk |
n | Don't stage this hunk |
s | Split into smaller hunks |
e | Manually edit the hunk |
q | Quit (keeps already staged) |
a | Stage this and all remaining hunks in file |
d | Don't stage this or any remaining hunks in file |
? | Help |
Example Session
$ git add -p
diff --git a/src/auth.ts b/src/auth.ts
@@ -10,6 +10,10 @@ export function login(user: string) {
+ // Validate input
+ if (!user) throw new Error('User required');
+
const token = generateToken(user);
+ logAudit('login', user); // Added for audit
return token;
}
Stage this hunk [y,n,q,a,d,s,e,?]? s # Split it!
# Now shows smaller hunks...
@@ -10,6 +10,8 @@
+ // Validate input
+ if (!user) throw new Error('User required');
Stage this hunk? y # Stage validation
@@ -14,6 +16,7 @@
+ logAudit('login', user); # Added for audit
Stage this hunk? n # Skip audit (different commit)Editing Hunks
Use e to manually edit when Git can't split small enough:
Stage this hunk? e
# Opens editor with:
# -context line
# +added line
# +another added line
# Delete lines you DON'T want staged
# Keep lines you DO want staged
# Save and exitViewing What's Staged
# What will be committed
git diff --staged
# What won't be committed
git diff
# Summary
git statusTips
1. Commit after staging: Don't stage more until you commit 2. Review before commit: Always git diff --staged 3. Use `s` liberally: Split whenever possible 4. Use `e` for precision: Edit when split isn't enough 5. Stage by file: git add -p file.ts for focused work
Recovery Decision Tree
Quick reference for choosing the right recovery approach.
Decision Tree
What happened?
│
├─ Committed to wrong branch?
│ ├─ Not pushed → cherry-pick + reset
│ └─ Pushed → cherry-pick + revert
│
├─ Need to undo commit?
│ ├─ Keep changes → git reset --soft HEAD~1
│ ├─ Discard changes → git reset --hard HEAD~1
│ └─ Already pushed → git revert HEAD
│
├─ Lost commits?
│ └─ Check reflog → git reset --hard HEAD@{N}
│
├─ Deleted branch?
│ └─ Check reflog → git checkout -b name SHA
│
├─ Bad merge?
│ ├─ Not pushed → git reset --hard HEAD~1
│ └─ Pushed → git revert -m 1 SHA
│
└─ Rebase disaster?
├─ Still rebasing → git rebase --abort
└─ Completed → reflog → resetDetailed Recovery Commands
Undo Last Commit
# Keep changes staged
git reset --soft HEAD~1
# Keep changes unstaged
git reset --mixed HEAD~1
# Discard changes completely (DANGER)
git reset --hard HEAD~1
# Already pushed - create reverting commit
git revert HEADCommitted to Wrong Branch
Not pushed:
# Note the commit SHA
git log -1 # abc1234
# Undo on wrong branch
git reset --hard HEAD~1
# Apply to correct branch
git checkout correct-branch
git cherry-pick abc1234Already pushed:
# Cherry-pick to correct branch
git checkout correct-branch
git cherry-pick abc1234
git push origin correct-branch
# Revert on wrong branch
git checkout wrong-branch
git revert abc1234
git push origin wrong-branchRecover Lost Commits
# Find in reflog
git reflog
# Reset to before the bad operation
git reset --hard HEAD@{N}
# Or cherry-pick specific commits
git cherry-pick abc1234Recover Deleted Branch
# Find branch's last commit
git reflog | grep "checkout: moving from deleted-branch"
# Recreate branch
git checkout -b recovered-branch abc1234Fix Rebase Disasters
Mid-rebase:
# Abort and start over
git rebase --abort
# Skip problematic commit
git rebase --skip
# Continue after fixing conflicts
git add .
git rebase --continueAfter rebase completed:
# Find pre-rebase state in reflog
git reflog
# Reset to before rebase
git reset --hard HEAD@{N}
# Force push if needed (feature branches only!)
git push --force-with-leaseUndo Merge
Not pushed:
git reset --hard HEAD~1Already pushed:
# -m 1 keeps first parent (your branch)
git revert -m 1 <merge-commit-sha>
git pushRecover Stashed Changes
# List stashes
git stash list
# Apply most recent
git stash pop
# Apply specific stash
git stash apply stash@{2}
# Recover dropped stash (search reflog)
git reflog | grep "WIP on"Prevention Tips
# Backup before dangerous operations
git branch backup-before-rebase
# Use safer force push
git push --force-with-lease
# Commit early, commit often
# More recovery points = easier recoveryKey Principle
Stay calm - Git almost never loses data permanently. The reflog keeps everything for 90 days.
Reflog Recovery
The reflog is Git's safety net. It tracks every HEAD movement for ~90 days.
What Reflog Captures
Every time HEAD changes, reflog records it:
- Commits
- Checkouts
- Resets
- Rebases
- Merges
- Cherry-picks
- Pulls
Reading the Reflog
$ git reflog
abc1234 HEAD@{0}: commit: feat: Add auth
def5678 HEAD@{1}: checkout: moving from main to feature
ghi9012 HEAD@{2}: pull: Fast-forward
jkl3456 HEAD@{3}: reset: moving to HEAD~3
mno7890 HEAD@{4}: rebase: (finish)
pqr2345 HEAD@{5}: rebase: (start)Format Explained
abc1234 HEAD@{0}: commit: feat: Add auth
─────── ──────── ─────── ──────────────
│ │ │ │
│ │ │ └── Description
│ │ └───────────── Action type
│ └─────────────────────── Position (0 = most recent)
└──────────────────────────────── Commit SHACommon Recovery Patterns
Find Lost Commit
# Search by message
git reflog | grep "important feature"
# Search by date
git reflog --since="2 hours ago"
# Search by author action
git reflog | grep "commit:"Recover After Bad Reset
$ git reflog
abc1234 HEAD@{0}: reset: moving to HEAD~5 # Bad reset!
def5678 HEAD@{1}: commit: Important work # Lost commit
$ git reset --hard HEAD@{1} # Recovered!Recover After Bad Rebase
$ git reflog
abc1234 HEAD@{0}: rebase (finish)
def5678 HEAD@{1}: rebase (pick)
ghi9012 HEAD@{2}: rebase (start) # Find pre-rebase state
jkl3456 HEAD@{3}: commit: My work # This is what we want
$ git reset --hard HEAD@{3} # Back to pre-rebaseFind Deleted Branch
# Find last commit on deleted branch
git reflog | grep "checkout: moving from deleted-branch"
# Recreate branch
git checkout -b recovered abc1234Branch-Specific Reflog
# Reflog for specific branch
git reflog show feature-branch
# Reflog for remote tracking
git reflog show origin/mainReflog Expiration
# Default: 90 days for reachable, 30 days for unreachable
git config gc.reflogExpire # Default: 90.days
git config gc.reflogExpireUnreachable # Default: 30.days
# Keep forever (not recommended)
git config gc.reflogExpire neverPro Tips
1. Check reflog FIRST when something goes wrong 2. Use HEAD@{n} syntax in any git command 3. Branch before dangerous ops: git branch backup 4. Reflog is local only - not pushed to remote 5. Each repo has separate reflog
Rule Categories
1. Branch Protection (protection) — CRITICAL — 1 rule
Protected branch rules that prevent direct commits to main/dev. Violations can break deployments and lose team work.
branch-protection.md— Protected branches, required workflows, emergency procedures
2. Merge Strategy (merge) — HIGH — 1 rule
When to rebase vs merge, how to handle conflicts, and keeping history clean.
merge-strategy.md— Rebase-first workflow, merge commit rules, conflict resolution
3. History Hygiene (hygiene) — HIGH — 1 rule
Maintaining a clean, useful git history for debugging (bisect) and code review.
history-hygiene.md— Squashing, fixup commits, interactive rebase, history cleanup
4. Recovery (recovery) — CRITICAL — 3 rules
Git recovery patterns using reflog, reset modes, and stash management.
recovery-reflog.md— Reflog-based recovery of lost commits, deleted branches, undone rebasesrecovery-reset.md— Safe (--soft/--mixed) vs dangerous (--hard) reset, pushed vs unpushedrecovery-stash.md— Named stashes, context switching, recovering dropped stashes via fsck
5. Stacked PRs (stacked) -- HIGH -- 2 rules
Break large features into small, reviewable, dependent PRs that merge in sequence.
stacked-pr-workflow.md-- Stack planning, PR creation, dependency tracking, numberingstacked-pr-rebase.md-- Rebase management, force-with-lease, retargeting after merge
6. Monorepo (monorepo) -- MEDIUM -- 1 rule
Multi-directory context patterns for monorepo workflows.
monorepo-context.md-- --add-dir, per-service CLAUDE.md, workspace detection
[Rule Name]
[Brief description — 1-2 sentences.]
Incorrect:
// Bad patternCorrect:
// Good patternKey rules:
- [Rule 1]
- [Rule 2]
- [Rule 3]
Reference: [link]
Branch Protection Rules
Protected branches are the deployment pipeline. Never commit or push directly to them.
Protected Branches
| Branch | Purpose | Direct Commit | Force Push |
|---|---|---|---|
main | Production-ready code | BLOCKED | BLOCKED |
master | Legacy production | BLOCKED | BLOCKED |
dev | Integration branch | BLOCKED | BLOCKED |
release/* | Release candidates | BLOCKED | BLOCKED |
Required Workflow
# 1. Create feature branch FROM main
git checkout main && git pull
git checkout -b issue/123-add-feature
# 2. Work on feature branch
git add -p && git commit -m "feat(#123): Add feature"
# 3. Push feature branch
git push -u origin issue/123-add-feature
# 4. Create PR targeting main (or dev)
gh pr create --base main
# 5. Merge via PR only (after review + CI)Branch Naming Convention
# Issue-linked (preferred)
issue/<number>-<brief-description>
issue/123-add-user-auth
# Type-based (when no issue exists)
feature/<description>
fix/<description>
hotfix/<description> # For urgent production fixes
docs/<description>
refactor/<description>
test/<description>
chore/<description>Emergency Procedures
For production hotfixes that need to bypass normal flow:
# Create hotfix branch from main
git checkout main && git pull
git checkout -b hotfix/critical-fix
# Fix, test, push
git add . && git commit -m "fix: Resolve critical auth bypass"
git push -u origin hotfix/critical-fix
# Create PR with expedited review
gh pr create --base main --title "HOTFIX: Critical auth bypass"Incorrect — Direct commit to main:
# Bypasses code review and CI
git checkout main
git commit -m "quick fix"
git push origin mainCorrect — Feature branch workflow:
# PR-based deployment
git checkout -b fix/issue-123
git commit -m "fix(#123): Resolve auth bug"
git push -u origin fix/issue-123
gh pr create --base mainKey Rules
- Never commit directly to main, dev, or release branches
- Always use feature branches with descriptive names
- All changes reach protected branches through PRs only
- Force push is only allowed on your own feature branches with
--force-with-lease - Delete feature branches after merge
History Hygiene Rules
A clean git history makes debugging (bisect), code review, and onboarding dramatically easier.
Before Pushing: Clean Up
# Squash WIP commits before pushing
git rebase -i HEAD~3
# In the editor:
pick abc1234 feat(#123): Add user validation
fixup def5678 WIP: more validation
fixup ghi9012 fix typo
# Result: One clean commit instead of three messy onesFixup Commits (During Development)
Use --fixup to mark commits that should be squashed later:
# Initial commit
git commit -m "feat(#123): Add user model"
# Later fixes to the same work
git commit --fixup HEAD # Auto-squash into previous
git commit --fixup HEAD~2 # Auto-squash into specific commit
# Before pushing, auto-squash all fixups
git rebase -i --autosquash HEAD~5What to Squash
| Squash | Keep Separate |
|---|---|
| WIP commits | Each logical feature |
| "Fix typo" after feature | Bug fixes (different concern) |
| "Address review feedback" | Refactoring (different intent) |
| Multiple attempts at same thing | Test additions (reviewable unit) |
| Formatting fixes mixed with logic | Documentation updates |
Commit Message Quality
# BAD history
abc1234 WIP
def5678 stuff
ghi9012 fix
jkl3456 more fixes
mno7890 finally works
# GOOD history
abc1234 feat(#123): Add user validation with Zod schemas
def5678 test(#123): Add validation edge case tests
ghi9012 docs(#123): Document validation error codesInteractive Rebase Commands
| Command | Effect |
|---|---|
pick | Keep commit as-is |
reword | Change commit message |
squash | Merge into previous, combine messages |
fixup | Merge into previous, discard message |
drop | Remove commit entirely |
Incorrect — Dirty WIP history:
# Pushed without cleanup
abc1234 WIP
def5678 fix
ghi9012 more fixes
jkl3456 finally worksCorrect — Cleaned history:
# Squashed before pushing
git rebase -i --autosquash HEAD~4
# Result: One clean commit
abc1234 feat(#123): Add user validation with edge case handlingKey Rules
- Clean up history before pushing — squash WIP and fixup commits
- Each commit in final history should be meaningful and atomic
- Use
--fixupduring development,--autosquashbefore pushing - Never rewrite published history (commits others have pulled)
- Commit messages should explain WHY, not just WHAT
Merge Strategy Rules
Use rebase-first workflow to maintain clean, linear history on feature branches.
Decision Table
| Scenario | Strategy | Command |
|---|---|---|
| Update feature branch with main | Rebase | git rebase origin/main |
| Merge PR into main | Squash merge or merge commit | Via GitHub PR |
| Resolve diverged branches | Rebase onto target | git rebase origin/main |
| Shared feature branch | Merge (preserve history) | git merge origin/main |
| Release branch | Merge commit | Via GitHub PR |
Rebase-First Workflow
# Keep feature branch up to date
git fetch origin
git rebase origin/main
# If conflicts arise
# 1. Resolve conflicts in each file
# 2. Stage resolved files
git add <resolved-files>
# 3. Continue rebase
git rebase --continue
# If rebase goes wrong
git rebase --abort # Start overWhen NOT to Rebase
DO NOT rebase if:
- Branch is shared with other developers (changes published history)
- You've already pushed and others have pulled
- Working on a release branch
USE merge instead:
git merge origin/mainConflict Resolution
# 1. Understand the conflict
git diff # Shows conflict markers
# 2. Resolve by choosing correct code
# <<<<<<< HEAD ← your changes
# ...
# =======
# ... ← incoming changes
# >>>>>>> main
# 3. Test after resolution
npm test # Verify nothing broke
# 4. Continue
git add <resolved-files>
git rebase --continueForce Push Safety
# SAFE: Force push your own feature branch
git push --force-with-lease origin issue/123-feature
# DANGEROUS: Never force push protected branches
git push --force origin main # NEVER DO THIS
# --force-with-lease prevents overwriting others' pushes
# It fails if remote has commits you don't have locallyIncorrect — Merge main into feature:
# Creates noisy merge commits
git checkout feature-branch
git merge origin/main # Creates "Merge branch 'main' into feature" commitCorrect — Rebase onto main:
# Linear history
git checkout feature-branch
git rebase origin/main # Replays feature commits on top of main
git push --force-with-leaseKey Rules
- Rebase feature branches onto main — don't merge main into feature branches
- Use
--force-with-leaseinstead of--forcefor rebased branches - Resolve conflicts during rebase, not with merge commits
- Test after every conflict resolution
- Abort rebase if unsure — you can always start over
Monorepo Context Patterns
Configure Claude Code for monorepo workflows with per-service CLAUDE.md and multi-directory context.
Incorrect — single flat context for entire monorepo:
# WRONG: Claude Code only sees root, misses service-specific patterns
claude # From monorepo root — no service contextCorrect — multi-directory context with --add-dir:
# Start Claude Code with additional service context
claude --add-dir ../shared
claude --add-dir ../shared --add-dir ../web
# Enable CLAUDE.md loading from added directories
export CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1Per-service CLAUDE.md structure:
monorepo/
CLAUDE.md # Root: workspace-wide rules
packages/
api/
CLAUDE.md # API: FastAPI patterns, test commands
package.json
web/
CLAUDE.md # Web: Next.js patterns, component library
package.json
shared/
CLAUDE.md # Shared: library API, versioning rules
package.jsonRoot CLAUDE.md (workspace-wide):
# Monorepo Root
## Conventions
- Commit format: conventional commits
- Branch naming: issue/<number>-<desc>
- CI: Turborepo pipeline, affected-only builds
## Cross-Service Rules
- Shared types live in packages/shared
- API changes require web compatibility checkService CLAUDE.md (service-specific):
# API Service
## Stack
- FastAPI 0.115+, Python 3.12+
- SQLAlchemy 2.x async
## Test Commands
npm run test:api # Unit tests
npm run test:api:e2e # Integration tests
## Patterns
- All endpoints return RFC 9457 errors
- Use dependency injection via FastAPI Depends()Monorepo detection indicators:
| Indicator | Tool |
|---|---|
pnpm-workspace.yaml | pnpm |
lerna.json | Lerna |
nx.json | Nx |
turbo.json | Turborepo |
rush.json | Rush |
3+ nested package.json | Generic |
Key rules:
- Root CLAUDE.md: workspace conventions, cross-service rules, CI pipeline
- Service CLAUDE.md: framework patterns, test commands, API contracts
- Use
--add-dirwhen working across service boundaries - Set
CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1for full context loading - Keep service CLAUDE.md focused — avoid duplicating root-level rules
Reflog Recovery
Use git reflog to recover lost commits, deleted branches, and botched rebases.
Incorrect — assuming commits are gone after reset:
git reset --hard HEAD~3 # "Oh no, those commits are lost forever\!"
# Wrong — reflog still has themCorrect — reflog finds everything:
# View all recent HEAD movements
git reflog --date=relative
# Find lost commits by message
git reflog | grep "search-term"
# Show reflog for specific branch
git reflog show branch-name
# Once found (e.g., abc1234), recover:
git branch recovered-work abc1234
# Or cherry-pick specific commits:
git cherry-pick abc1234Recover deleted branch:
# Find the branch last commit
git reflog | grep -i "branch-name"
# Or check all recent activity:
git reflog --all | head -30
# Recreate the branch at that commit
git checkout -b recovered-branch abc1234
# Verify
git log --oneline -5Undo a bad rebase:
# Find the pre-rebase state in reflog
git reflog | head -20
# Look for: "rebase (start): checkout main"
# The entry BEFORE that is your pre-rebase state
# Alternative: ORIG_HEAD is set before rebase
git reset --hard ORIG_HEAD
# WARNING: ORIG_HEAD is overwritten by other operations
# Use reflog if ORIG_HEAD might be staleKey rules:
- Reflog keeps entries for ~90 days by default — rarely truly "lost"
- Always check reflog before assuming data is gone
ORIG_HEADis a shortcut but can be overwritten — reflog is more reliable- Reflog is local only — not shared with remotes
Reset and Restore
Undo commits and restore files safely using the right reset mode.
Incorrect — hard reset without backup:
git reset --hard HEAD~1 # Changes gone, no backup reference saved
# If this was wrong, recovery requires digging through reflogCorrect — always save a backup reference first:
# Save backup before destructive operation
BACKUP_REF=$(git rev-parse HEAD)
echo "Backup ref: $BACKUP_REF"
# Show what will be lost
git show HEAD --stat
# Then execute
git reset --hard HEAD~1
# Recovery if needed:
git reset --hard $BACKUP_REFReset modes — choose carefully:
| Mode | Commits | Staging | Working Dir | Use Case |
|---|---|---|---|---|
--soft | Undo | Keep staged | Keep | Amend/recombine commits |
--mixed (default) | Undo | Unstage | Keep | Re-stage selectively |
--hard | Undo | Discard | Discard | Throw everything away |
Undo last commit, keep changes:
git reset --soft HEAD~1
git status # Changes are still stagedRestore single file (non-destructive to other files):
# Show changes to file first
git diff path/to/file
# Restore using modern git (2.23+)
git restore path/to/file
# Or older syntax
git checkout HEAD -- path/to/fileUnstage files (keep changes in working directory):
# Modern syntax
git restore --staged path/to/file
# Older syntax
git reset HEAD path/to/filePushed vs not-pushed decision:
| Scenario | Not Pushed | Already Pushed |
|---|---|---|
| Undo commit | git reset --soft HEAD~1 | git revert HEAD |
| Wrong branch | cherry-pick + reset | cherry-pick + revert |
| Bad merge | git reset --hard ORIG_HEAD | git revert -m 1 <merge> |
Key rules:
- Always save a backup ref before
--hardreset - Prefer
--softwhen you want to re-commit differently - Use
git revert(not reset) for commits already pushed to shared branches git restoreis the modern replacement forgit checkout -- file
Stash Recovery
Save and recover work-in-progress using git stash safely.
Incorrect — unnamed stash that gets lost:
git stash # Generic "WIP on main" message
git stash # Another generic stash
git stash pop # Which one was it? Wrong one applied
git stash drop # Lost the other oneCorrect — named stashes with safe recovery:
# Save with descriptive name
git stash push -m "auth-flow: halfway through token refresh"
# List stashes to find the right one
git stash list
# stash@{0}: On main: auth-flow: halfway through token refresh
# stash@{1}: On main: fix: database connection pooling
# Apply specific stash (keeps it in stash list)
git stash apply stash@{1}
# Apply and remove from list
git stash pop stash@{0}Recover a dropped stash:
# Stash entries appear in reflog briefly
git fsck --no-reflog | grep commit
# Once found, apply it:
git stash apply <commit-hash>Stash specific files:
# Stash only specific files
git stash push -m "partial work" -- path/to/file1 path/to/file2
# Stash including untracked files
git stash push -u -m "including new files"Key rules:
- Always use
-mwith a descriptive message when stashing - Prefer
git stash applyoverpopuntil you verify the result is correct - Dropped stashes can be recovered via
git fsckbut only before garbage collection - Use
git stash push -- <files>to stash specific files, not everything - Stash includes staged changes by default; use
--keep-indexto stash only unstaged
Stacked PR Rebase Management
Keep stacked PR branches synchronized after feedback, merges, or base branch changes.
Incorrect — merging main into feature branches:
# WRONG: Merge commits pollute history
git checkout feature/auth-service
git merge main # Creates unnecessary merge commit
git merge feature/auth-base # More merge commits
# History becomes unreadable messCorrect — rebase after base PR feedback:
# When base PR (auth-base) gets review feedback:
git checkout feature/auth-base
git add -p && git commit -m "fix: Address review feedback"
git push
# Rebase dependent branches in order:
git checkout feature/auth-service
git rebase feature/auth-base
git push --force-with-lease # Safe: won't overwrite others' work
git checkout feature/auth-ui
git rebase feature/auth-service
git push --force-with-leaseAfter base PR merges to main:
# PR #1 merged to main
git checkout main && git pull origin main
# Retarget PR #2 to main (via GitHub CLI)
gh pr edit 102 --base main
# Rebase PR #2 on updated main
git checkout feature/auth-service
git rebase main
git push --force-with-lease
# After PR #2 merges, repeat for PR #3Automation script for rebasing entire stack:
#!/bin/bash
# stack-rebase.sh — Rebase entire stack in sequence
STACK=(
"feature/auth-base"
"feature/auth-service"
"feature/auth-ui"
)
BASE="main"
for branch in "${STACK[@]}"; do
echo "Rebasing $branch onto $BASE..."
git checkout "$branch"
git rebase "$BASE" || { echo "Conflict in $branch! Resolve and re-run."; exit 1; }
git push --force-with-lease
BASE="$branch"
done
echo "Stack rebased successfully!"Key rules:
- Always rebase, never merge main into feature branches
- Use
--force-with-lease(never--force) to prevent overwriting others' work - Rebase in dependency order: base first, then each dependent branch
- After a base PR merges, retarget the next PR to
mainviagh pr edit - If rebase conflicts occur, resolve in the lowest branch first, then cascade
- Never force push to already-approved PRs without re-requesting review
Stacked PR Workflow
Break large features into small, dependent PRs that merge in sequence for faster reviews and cleaner history.
Incorrect — single massive PR:
# WRONG: One 1500-line PR that takes days to review
git checkout -b feature/auth
# ... 3 days of work, 40 files changed ...
gh pr create --title "feat: Add complete auth system"
# Reviewer: "This is too large to review effectively"Correct — stacked PRs with clear dependencies:
# PR 1: User model (base) — targets main
git checkout main && git pull origin main
git checkout -b feature/auth-base
git add -p && git commit -m "feat(#100): Add User model"
git push -u origin feature/auth-base
gh pr create --base main --title "feat(#100): Add User model [1/3]" \
--body "## Stack
- **PR 1/3: User model (this PR)**
- PR 2/3: Auth service (depends on this)
- PR 3/3: Login UI (depends on #2)
## Changes
- Add User model with validation
- Add database migrations"
# PR 2: Auth service — targets PR 1's branch
git checkout -b feature/auth-service # branches from auth-base
git add -p && git commit -m "feat(#100): Add auth service"
git push -u origin feature/auth-service
gh pr create --base feature/auth-base \
--title "feat(#100): Add auth service [2/3]" \
--body "**Depends on #101** — merge that first"
# PR 3: Login UI — targets PR 2's branch
git checkout -b feature/auth-ui
git commit -m "feat(#100): Add login form"
git push -u origin feature/auth-ui
gh pr create --base feature/auth-service \
--title "feat(#100): Add login UI [3/3]"Stack visualization in PR body:
## PR Stack for Auth Feature (#100)
| Order | PR | Status | Branch |
|-------|-----|--------|--------|
| 1 | #101 | Merged | feature/auth-base |
| 2 | #102 | Review | feature/auth-service |
| 3 | #103 | Draft | feature/auth-ui |
**Merge order**: #101 -> #102 -> #103Key rules:
- Keep each PR under 400 lines for effective review
- Number PRs clearly:
[1/3],[2/3],[3/3] - Each PR should be independently reviewable and leave tests passing
- Use draft PRs for incomplete stack items
- Do not stack more than 4-5 PRs deep
- Never merge out of order
{
"skill": "git-workflow",
"version": "1.0.0",
"testCases": [
{
"id": "branching-strategy",
"rule": "branch-protection",
"query": "Set up a branching strategy for our new project",
"expectedBehavior": [
"Recommends GitHub Flow branching model for continuous delivery workflows",
"Uses issue/<number>-<description> branch naming convention for traceability",
"Enforces that the main branch is always in a deployable state",
"Requires PR workflow for protected branches"
]
},
{
"id": "stash-recovery",
"rule": "recovery-stash",
"query": "I accidentally dropped my stash, how do I recover it?",
"expectedBehavior": [
"Uses git reflog to find the dropped stash",
"Provides step-by-step stash recovery commands using git fsck",
"Explains stash management best practices including naming and cleanup",
"Shows how to avoid future stash loss"
]
},
{
"id": "rebase-workflow",
"rule": "merge-strategy",
"query": "Should I merge or rebase my feature branch?",
"expectedBehavior": [
"Recommends rebase over merge for clean history",
"Explains conflict resolution strategies during interactive rebase operations",
"Uses force-with-lease for safe pushing after rebase",
"Warns against rebasing shared branches that others have pulled"
]
},
{
"id": "cherry-pick-recovery",
"rule": "recovery-reflog",
"query": "I committed to the wrong branch, how do I move it?",
"expectedBehavior": [
"Uses reflog to find the commit",
"Recommends cherry-pick to move the commit to the correct branch",
"Provides reset to remove from wrong branch",
"Distinguishes pushed vs unpushed commits with appropriate recovery strategies"
]
},
{
"id": "history-hygiene",
"rule": "history-hygiene",
"query": "My branch has WIP and fixup commits, how do I clean up before pushing?",
"expectedBehavior": [
"Uses interactive rebase to squash WIP and fixup commits into clean atomic commits",
"Shows git commit --fixup and --autosquash workflow for incremental development cleanup",
"Keeps each final commit meaningful with a message explaining why not just what",
"Warns against rewriting published history that other developers have already pulled"
]
},
{
"id": "monorepo-context",
"rule": "monorepo-context",
"query": "How do I configure Claude Code for a monorepo with separate API and web services?",
"expectedBehavior": [
"Uses --add-dir flag to include additional service directories in Claude Code context",
"Creates per-service CLAUDE.md files with framework patterns and test commands",
"Sets CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD environment variable for full context loading",
"Keeps root CLAUDE.md for workspace-wide conventions and cross-service rules"
]
},
{
"id": "recovery-reset",
"rule": "recovery-reset",
"query": "I need to undo my last commit but keep the changes staged for a different commit",
"expectedBehavior": [
"Uses git reset --soft HEAD~1 to undo the commit while keeping changes staged",
"Saves a backup reference with git rev-parse HEAD before any hard reset operation",
"Explains the three reset modes: soft keeps staged, mixed unstages, hard discards everything",
"Recommends git revert instead of reset for commits already pushed to shared branches"
]
},
{
"id": "stacked-pr-rebase",
"rule": "stacked-pr-rebase",
"query": "My base PR got review feedback and now the dependent PRs are out of sync, how do I fix them?",
"expectedBehavior": [
"Rebases dependent branches in dependency order starting from the base branch first",
"Uses --force-with-lease instead of --force to prevent overwriting collaborators work",
"Retargets the next PR to main via gh pr edit after a base PR merges",
"Resolves rebase conflicts in the lowest branch first then cascades through the stack"
]
},
{
"id": "stacked-pr-workflow",
"rule": "stacked-pr-workflow",
"query": "I need to implement a large auth feature but want small reviewable PRs, how do I split it?",
"expectedBehavior": [
"Breaks the feature into stacked PRs each under 400 lines targeting the previous PR branch",
"Numbers PRs clearly in titles like 1/3, 2/3, 3/3 for ordering visibility",
"Creates each PR with --base set to the previous PR branch for proper dependency chain",
"Includes a stack visualization table in the PR body showing order, status, and merge sequence"
]
}
]
}