agile-workflow
npx skills add https://github.com/yabasha/agile-workflow --skill agile-workflow
Agent 安装分布
Skill 文档
Agile Development & Repository Management
You are an agile team lead and repository manager. This skill covers the full lifecycle of agile software development â from sprint planning through issue resolution, code review, release management, and repository maintenance. Follow the relevant module based on user intent.
| Key | Value |
|---|---|
| Version | 2.0.0 |
| Author | Bashar Ayyash (Yabasha.dev) |
| License | MIT |
| Tools Required | bash, git, gh (GitHub CLI) |
| Platforms | Claude Code, Cursor, Windsurf, Copilot, Codex, OpenClaw, Aider, any LLM coding assistant with shell access |
Module Dispatcher
Route the user’s intent to the correct module:
| User Intent | Module |
|---|---|
| “fix issues”, “resolve issues”, “tackle issues”, “batch fix” | Part 1: Issue Resolution Pipeline |
| “plan sprint”, “create sprint”, “sprint planning” | Sprint Planning |
| “groom backlog”, “create issue”, “label issues” | Backlog Management |
| “estimate”, “story points”, “size issues” | Story Point Estimation |
| “triage issues”, “prioritize issues” | Issue Triage & Auto-labeling |
| “retrospective”, “retro”, “sprint review” | Sprint Retrospectives |
| “kanban”, “board”, “project board” | Kanban Board Management |
| “epic”, “milestone”, “roadmap” | Epic & Milestone Tracking |
| “standup”, “status report”, “daily report” | Status Reports & Standups |
| “branch strategy”, “gitflow”, “trunk-based” | Branch Strategy |
| “commit convention”, “conventional commits” | Conventional Commits |
| “release”, “bump version”, “changelog”, “tag” | Release Management |
| “set up repo”, “configure repo”, “repo setup” | Repository Setup & Configuration |
| “repo health”, “stale branches”, “cleanup repo” | Repository Health |
| “monorepo”, “workspaces”, “changesets” | Monorepo Management |
| “git hooks”, “husky”, “lint-staged” | Git Hooks & Automation |
| “rebase”, “cherry-pick”, “bisect”, “worktree” | Advanced Git Operations |
| “CI/CD”, “github actions”, “pipeline” | Part 4: CI/CD & Quality |
| “code review”, “review PR” | Part 5: Code Review Standards |
| “svn to git”, “migrate from svn” | SVN-to-Git Migration |
| “git error”, “undo commit”, “recover branch” | Git Error Recovery |
| “resolve pr comments”, “fix review comments” | Phase 3: PR Review Comment Resolution |
| “merge PRs”, “merge all” | Phase 4: Merge All PRs |
If intent is unclear, ask the user which module they need.
Part 1: Issue Resolution Pipeline
End-to-end workflow: detect open issues â prioritize â fix in parallel â create PRs â resolve review comments â merge â clean up.
Phase 1: Issue Discovery & Prioritization
1.1 Fetch all open issues
gh issue list --state open --json number,title,labels,body,assignees,milestone
1.2 Auto-categorize by labels
Scan issue titles and bodies for keywords and apply labels automatically:
# Create standard labels if they don't exist
gh label create "priority:critical" --color "B60205" --description "Production blocker" --force
gh label create "priority:high" --color "D93F0B" --description "Must fix this sprint" --force
gh label create "priority:medium" --color "FBCA04" --description "Should fix soon" --force
gh label create "priority:low" --color "0E8A16" --description "Nice to have" --force
gh label create "type:bug" --color "D73A4A" --description "Something isn't working" --force
gh label create "type:feature" --color "0075CA" --description "New functionality" --force
gh label create "type:chore" --color "CFD3D7" --description "Maintenance task" --force
gh label create "type:docs" --color "0075CA" --description "Documentation" --force
gh label create "type:security" --color "B60205" --description "Security issue" --force
Keyword-to-label mapping:
| Keywords in Title/Body | Label |
|---|---|
| crash, broken, error, fail, bug, not working | type:bug |
| feature, add, implement, support, request | type:feature |
| refactor, cleanup, chore, update deps, migrate | type:chore |
| docs, documentation, readme, typo | type:docs |
| security, vulnerability, CVE, XSS, injection | type:security |
| critical, production, outage, data loss | priority:critical |
| urgent, ASAP, blocker | priority:high |
# Apply label to issue
gh issue edit {number} --add-label "type:bug,priority:high"
1.3 Detect stale issues
Find issues with no activity in the last 30 days:
gh issue list --state open --json number,title,updatedAt \
--jq '[.[] | select(.updatedAt < (now - 2592000 | todate))] | .[] | "#\(.number) \(.title) (last updated: \(.updatedAt))"'
1.4 Prioritize into tiers
| Tier | Priority | Examples |
|---|---|---|
| Tier 1 | Critical â do first | Production blockers, security vulnerabilities, data loss, launch blockers |
| Tier 2 | High | Important features, significant bugs, DX improvements |
| Tier 3 | Medium | Enhancements, documentation, minor bugs |
| Tier 4 | Low | Nice-to-haves, cosmetic fixes, minor refactors |
1.5 Map dependencies
Build a dependency graph. Issues that must be done before others are blockers. Independent issues can run in parallel.
Example:
#3 (Testing) ââ> #7 (CI/CD) ââ> #8 (Infrastructure)
All others: independent
1.6 Group by area & file conflicts
Issues that modify the same files MUST go to the same developer to avoid merge conflicts. Signals:
- Same directory or file paths listed in the issue
- Same component, module, or page
- Layout/config files shared across features (e.g.,
layout.tsx,package.json,config.yml)
Phase 2: Parallel Execution
2.1 Concurrency limits
- Maximum parallel developers: 3â5 (to avoid resource exhaustion and merge conflict cascading)
- Queue strategy: Start Tier 1 issues first, then backfill with Tier 2/3 as slots open
- Shared file rule: Issues touching the same files go to the same developer â never parallelize overlapping file sets
2.2 Create isolated branches
Each issue (or issue group) gets its own branch:
fix/{issue-number}-short-description
Examples: fix/11-output-expiry-cleanup, fix/5-13-landing-page
2.3 Set up worktrees for isolation
# Create worktree for each developer
git worktree add ../worktree-issue-{number} -b fix/{number}-{slug} origin/main
# List active worktrees
git worktree list
# Clean up after done
git worktree remove ../worktree-issue-{number}
git worktree prune
2.4 Spawn parallel developers
Each developer works in an isolated environment (git worktree, separate clone, or sandboxed workspace) to avoid conflicts.
Developer prompt template:
You are a senior {specialty} developer. Implement GitHub Issue #{number}: {title}.
## Branch
Create and work on branch: `fix/{number}-{slug}`
## What to implement
{Full issue details and acceptance criteria}
## Files to read first
{List key files to understand before making changes}
## Verification
{Project-specific test/build/lint commands}
## Rules
- Read existing code FIRST before making changes
- Follow project conventions (read CLAUDE.md or CONTRIBUTING.md)
- Run {formatter} before committing
- Create a PR with `gh pr create` including "Closes #{number}" in the body
- Do NOT create a new PR if one already exists â push to the existing branch
2.5 Developer specialties
Match developers to issue domains:
| Specialty | Typical Issues |
|---|---|
| Backend | API endpoints, database, auth, jobs, queues |
| Frontend | UI components, pages, styling, client-side logic |
| DevOps | CI/CD, infrastructure, deployment, monitoring |
| Core/Engine | Libraries, algorithms, data processing |
| Testing | Test suites, fixtures, coverage |
2.6 Failure recovery
If a developer fails or produces incorrect output:
Decision Tree:
âââ Build/test failure?
â âââ Missing dependency â Install and retry
â âââ Type error â Read error output, fix types, retry
â âââ Test failure â Read test output, fix implementation, retry
âââ Merge conflict?
â âââ Rebase onto latest main
â âââ If conflict is in shared file â pause, merge other PR first, then rebase
âââ Developer produced wrong output?
â âââ Misunderstood issue â Respawn with clearer instructions
â âââ Partial fix â Resume from where they stopped
âââ Developer hung/timed out?
âââ Kill, review partial work, respawn or fix manually
2.7 Wait for all developers
Track each developer’s progress. As each completes:
- Collect the PR URL
- Verify the PR was created with
Closes #Nin the body - Verify build/tests pass
- Shut down the developer
Phase 3: PR Review Comment Resolution
3.1 Fetch review comments for all PRs
# For each PR number
gh api repos/{owner}/{repo}/pulls/{pr_number}/comments \
--jq '.[] | "ID:\(.id) [\(.path):\(.line // .original_line)] \(.body)"'
Skip PRs with no actionable comments (bot headers without suggestions are not actionable).
3.2 Review comment decision tree
For each comment:
âââ Is it a valid suggestion/required change?
â âââ Yes â Fix it (step 3.3)
âââ Is it a nitpick or style preference?
â âââ Fix if trivial, otherwise reply explaining project convention
âââ Is it a question, not a change request?
â âââ Reply with explanation, no code change needed
âââ Is the comment incorrect or outdated?
â âââ Reply explaining why, with evidence (code references, docs)
âââ Is it out of scope?
âââ Reply acknowledging, create a follow-up issue if warranted
3.3 Fix each comment
For each PR with actionable comments, spawn a fix agent that:
- Checks out the existing PR branch (does NOT create a new branch)
- Reads the commented file to understand current code
- Applies the fix
- Runs verification (tests, build, lint)
- Commits and pushes to the same branch
3.4 Reply to each comment
After fixes are pushed, reply to every comment confirming the fix:
gh api repos/{owner}/{repo}/pulls/{pr_number}/comments/{comment_id}/replies \
-f body="Fixed â {description of what was changed}. See commit {short_hash}."
3.5 Resolve review threads
# Step 1: Get unresolved thread IDs
gh api graphql -f query='
query {
repository(owner: "{owner}", name: "{repo}") {
pullRequest(number: {pr_number}) {
reviewThreads(first: 50) {
nodes {
id
isResolved
comments(first: 1) {
nodes { path body }
}
}
}
}
}
}' --jq '.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false) | .id'
# Step 2: Resolve each thread
gh api graphql -f query='
mutation {
resolveReviewThread(input: { threadId: "{thread_id}" }) {
thread { isResolved }
}
}'
3.6 Iterate
If new comments appear after pushing fixes, repeat Phase 3.
Phase 4: Merge All PRs
4.1 Merge in dependency order
Merge independent PRs first. PRs that depend on others merge after their dependencies.
gh pr merge {number} --squash --delete-branch
4.2 Handle merge conflicts
After each merge, subsequent PRs may conflict with the updated main. Rebase them:
git fetch origin main
git fetch origin {branch}
git checkout {branch}
git rebase origin/main
git push origin {branch} --force-with-lease
Wait 3â5 seconds for GitHub to recalculate mergeability, then retry.
4.3 Handle stale worktrees
If rebase fails because a branch is locked by a worktree:
git worktree remove {worktree_path} --force
git worktree prune
# Then retry the rebase
4.4 Verify all issues closed
gh issue list --state open --json number,title
Phase 5: Cleanup
# 1. Prune stale remote tracking refs
git remote prune origin
# 2. Delete leftover local branches
git branch | grep -v '^\* main$' | grep -v '^ main$' | xargs -r git branch -D
# 3. Clean up worktrees
git worktree prune
git worktree list # Should show only the main worktree
# 4. Final verification
git checkout main
git pull origin main
git status # Should be clean
git branch # Should only show main
Part 2: Agile Process Management
Sprint Planning & Backlog Management
Create a milestone (sprint)
# Create milestone with due date
gh api repos/{owner}/{repo}/milestones \
-f title="Sprint 1" \
-f description="Sprint goal: {goal}" \
-f due_on="2025-02-14T23:59:59Z" \
-f state="open"
# List milestones
gh api repos/{owner}/{repo}/milestones --jq '.[] | "#\(.number) \(.title) â due \(.due_on) (\(.open_issues) open, \(.closed_issues) closed)"'
Assign issues to a sprint
# Batch assign issues to milestone
for issue in 1 2 3 4 5; do
gh issue edit "$issue" --milestone "Sprint 1"
done
Capacity planning
| Factor | Adjustment |
|---|---|
| Base velocity | Average story points completed in last 3 sprints |
| PTO / holidays | Reduce by percentage of team-days lost |
| New team member | Reduce by 20â30% for onboarding |
| Tech debt sprint | Reduce feature capacity by 30â50% |
| Bug-heavy backlog | Reserve 20% buffer for unplanned bug fixes |
| Sprint length | 2 weeks recommended; 1 week for high-urgency projects |
Sprint goal template
## Sprint {N} Goal
**Duration:** {start_date} â {end_date}
**Theme:** {one-line theme}
### Committed Stories
| # | Title | Points | Assignee |
|---|-------|--------|----------|
| {number} | {title} | {points} | {assignee} |
### Sprint Goal
{2-3 sentences describing the primary objective and what "done" looks like}
### Stretch Goals
- {optional items if capacity allows}
### Risks / Dependencies
- {known blockers or external dependencies}
Issue creation templates
Bug report:
gh issue create --title "Bug: {short description}" \
--body "## Description
{What happened}
## Expected Behavior
{What should happen}
## Steps to Reproduce
1. {step}
## Environment
- OS: {os}
- Version: {version}
## Screenshots / Logs
{attach if applicable}" \
--label "type:bug"
Feature request:
gh issue create --title "Feature: {short description}" \
--body "## Summary
{What and why}
## User Story
As a {role}, I want {capability} so that {benefit}.
## Acceptance Criteria
- [ ] {criterion 1}
- [ ] {criterion 2}
## Design Notes
{Optional technical approach or mockup}" \
--label "type:feature"
Chore:
gh issue create --title "Chore: {short description}" \
--body "## Description
{What needs to be done and why}
## Tasks
- [ ] {task 1}
- [ ] {task 2}
## Notes
{Any relevant context}" \
--label "type:chore"
Spike (research/investigation):
gh issue create --title "Spike: {question to answer}" \
--body "## Objective
{What we need to learn}
## Time Box
{max hours/days}
## Key Questions
1. {question}
## Expected Output
{Document, POC, recommendation, etc.}" \
--label "type:spike"
Complete label taxonomy
# Priority labels
gh label create "priority:critical" --color "B60205" --description "Production blocker â drop everything" --force
gh label create "priority:high" --color "D93F0B" --description "Must fix this sprint" --force
gh label create "priority:medium" --color "FBCA04" --description "Should fix soon" --force
gh label create "priority:low" --color "0E8A16" --description "Nice to have" --force
# Type labels
gh label create "type:bug" --color "D73A4A" --description "Something isn't working" --force
gh label create "type:feature" --color "0075CA" --description "New functionality" --force
gh label create "type:chore" --color "CFD3D7" --description "Maintenance / housekeeping" --force
gh label create "type:docs" --color "0075CA" --description "Documentation only" --force
gh label create "type:security" --color "B60205" --description "Security issue" --force
gh label create "type:spike" --color "D4C5F9" --description "Research / investigation" --force
gh label create "type:test" --color "BFD4F2" --description "Test improvements" --force
# Size labels (T-shirt sizing)
gh label create "size:XS" --color "EDEDED" --description "< 1 hour" --force
gh label create "size:S" --color "D4C5F9" --description "1â4 hours" --force
gh label create "size:M" --color "BFD4F2" --description "Half day to 1 day" --force
gh label create "size:L" --color "FBCA04" --description "1â3 days" --force
gh label create "size:XL" --color "D93F0B" --description "3+ days â consider splitting" --force
# Area labels (customize per project)
gh label create "area:frontend" --color "61DAFB" --description "UI / client-side" --force
gh label create "area:backend" --color "3572A5" --description "API / server-side" --force
gh label create "area:infra" --color "E99695" --description "Infrastructure / DevOps" --force
gh label create "area:database" --color "F9D0C4" --description "Database / migrations" --force
gh label create "area:auth" --color "FBCA04" --description "Authentication / authorization" --force
# Status labels
gh label create "status:blocked" --color "B60205" --description "Blocked by external dependency" --force
gh label create "status:in-review" --color "FBCA04" --description "PR open, awaiting review" --force
gh label create "status:ready" --color "0E8A16" --description "Groomed and ready to pick up" --force
gh label create "status:needs-info" --color "D4C5F9" --description "Needs more information" --force
gh label create "status:wontfix" --color "FFFFFF" --description "Decided not to fix" --force
gh label create "status:duplicate" --color "CFD3D7" --description "Duplicate of another issue" --force
Backlog grooming process
# 1. Find ungroomed issues (no priority or size label)
gh issue list --state open --json number,title,labels \
--jq '[.[] | select((.labels | map(.name) | any(startswith("priority:"))) | not)] | .[] | "#\(.number) \(.title)"'
# 2. For each ungroomed issue:
# a. Read the issue body
# b. Verify acceptance criteria exist
# c. Apply type, priority, and size labels
# d. Assign to milestone if sprint-ready
# 3. Find issues missing acceptance criteria
gh issue list --state open --json number,title,body \
--jq '[.[] | select(.body | test("acceptance|criteria|\\[[ x]\\]") | not)] | .[] | "#\(.number) \(.title)"'
Issue linking and dependencies
# Reference dependencies in issue body using keywords:
# "Depends on #X" or "Blocked by #X" in the issue body
# "Part of #X" for epic relationships
# GitHub auto-links these in the timeline
# Query issues that reference a specific issue
gh api graphql -f query='
query {
repository(owner: "{owner}", name: "{repo}") {
issue(number: {number}) {
timelineItems(first: 50, itemTypes: [CROSS_REFERENCED_EVENT]) {
nodes {
... on CrossReferencedEvent {
source {
... on Issue { number title state }
... on PullRequest { number title state }
}
}
}
}
}
}
}'
Story Point Estimation
Fibonacci scale
| Points | Complexity | Duration (solo dev) | Examples |
|---|---|---|---|
| 1 | Trivial | < 1 hour | Typo fix, copy change, config tweak |
| 2 | Simple | 1â4 hours | Add a field, simple UI change, add test |
| 3 | Small | Half day | New API endpoint, simple component, bug fix with known cause |
| 5 | Medium | 1â2 days | Feature with multiple files, integration work, moderate refactor |
| 8 | Large | 2â4 days | Cross-cutting feature, complex algorithm, significant refactor |
| 13 | Very large | 1 week+ | Major feature, architectural change â consider splitting |
| 21 | Epic-sized | 2+ weeks | Too large for a single story â MUST split |
Programmatic estimation algorithm
INPUT: issue description, codebase context
1. Count files to change
- 1 file = base 1
- 2â3 files = base 2
- 4â6 files = base 3
- 7+ files = base 5
2. Estimate lines of code
- < 20 lines = +0
- 20â100 lines = +1
- 100â300 lines = +2
- 300+ lines = +3
3. Dependency factor
- No new dependencies = +0
- Uses existing internal APIs = +1
- Requires new dependency or external API = +2
- Requires database migration = +3
4. Test requirement
- No tests needed = +0
- Unit tests only = +1
- Integration tests = +2
- E2E tests = +3
5. Risk/uncertainty
- Well-understood domain = +0
- Some unknowns = +1
- Significant unknowns (spike first) = +3
SUM all factors, then map to nearest Fibonacci:
1â2 â 1 point
3â4 â 2 points
5â6 â 3 points
7â9 â 5 points
10â12 â 8 points
13â16 â 13 points
17+ â 21 points (split the story)
Apply estimates as labels
# Add story point label
gh issue edit {number} --add-label "points:5"
# Create point labels if needed
for pts in 1 2 3 5 8 13 21; do
gh label create "points:$pts" --color "C5DEF5" --description "$pts story points" --force
done
Issue Triage & Auto-labeling
Triage decision tree
New issue arrives:
âââ Is it a duplicate?
â âââ Yes â Label "status:duplicate", comment referencing original, close
â âââ No â continue
âââ Is it actionable?
â âââ No (vague, no repro steps) â Label "status:needs-info", comment asking for details
â âââ Yes â continue
âââ What type is it?
â âââ Bug â "type:bug"
â âââ Feature â "type:feature"
â âââ Security â "type:security" + "priority:critical"
â âââ Documentation â "type:docs"
â âââ Maintenance â "type:chore"
âââ What priority?
â âââ Production broken / security / data loss â "priority:critical"
â âââ Significant user impact â "priority:high"
â âââ Moderate impact â "priority:medium"
â âââ Minor / cosmetic â "priority:low"
âââ Assign area label based on files/components mentioned
Priority SLAs
| Priority | Response Time | Resolution Target |
|---|---|---|
| Critical | < 1 hour | < 4 hours |
| High | < 4 hours | < 2 days |
| Medium | < 1 day | < 1 sprint |
| Low | < 1 week | Next sprint or backlog |
Auto-labeling script
# Fetch unlabeled issues and apply labels based on content
gh issue list --state open --json number,title,body,labels \
--jq '[.[] | select(.labels | length == 0)]' | \
while read -r issue; do
number=$(echo "$issue" | jq -r '.number')
title=$(echo "$issue" | jq -r '.title' | tr '[:upper:]' '[:lower:]')
body=$(echo "$issue" | jq -r '.body' | tr '[:upper:]' '[:lower:]')
content="$title $body"
labels=""
# Type detection
if echo "$content" | grep -qE "bug|broken|error|crash|fail|not working"; then
labels="type:bug"
elif echo "$content" | grep -qE "feature|add|implement|support|request"; then
labels="type:feature"
elif echo "$content" | grep -qE "security|vulnerability|cve|xss|injection"; then
labels="type:security,priority:critical"
elif echo "$content" | grep -qE "docs|documentation|readme|typo"; then
labels="type:docs"
elif echo "$content" | grep -qE "refactor|cleanup|chore|update dep|migrate"; then
labels="type:chore"
fi
if [ -n "$labels" ]; then
gh issue edit "$number" --add-label "$labels"
fi
done
Sprint Retrospectives
Automated metrics collection
# Sprint velocity (closed issues with points in milestone)
gh issue list --state closed --milestone "Sprint 1" --json number,labels \
--jq '[.[] | .labels[] | select(.name | startswith("points:")) | .name | ltrimstr("points:") | tonumber] | add'
# Average PR merge time (time from open to merge)
gh pr list --state merged --json number,createdAt,mergedAt \
--jq '[.[] | ( (.mergedAt | fromdateiso8601) - (.createdAt | fromdateiso8601) ) / 3600] | (add / length) | round | "\(.) hours avg"'
# PR count
gh pr list --state merged --search "milestone:\"Sprint 1\"" --json number --jq 'length'
# Bug escape rate (bugs found after release vs total issues)
gh issue list --state closed --milestone "Sprint 1" --label "type:bug" --json number --jq 'length'
# Issues that missed the sprint (still open in milestone)
gh issue list --state open --milestone "Sprint 1" --json number,title \
--jq '.[] | "#\(.number) \(.title)"'
Retro report template
## Sprint {N} Retrospective
**Date:** {date}
**Duration:** {start} â {end}
### Metrics
| Metric | Value | Trend |
|--------|-------|-------|
| Velocity (points) | {pts} | {âââ} |
| Issues completed | {count} | |
| PRs merged | {count} | |
| Avg PR merge time | {hours}h | |
| Bug escape rate | {percent}% | |
| Missed issues | {count} | |
### What Went Well
- {item}
### What Didn't Go Well
- {item}
### Action Items
- [ ] {action} â Owner: {name} â Due: {date}
### Shoutouts
- {recognition}
Action item tracking
# Create action items as issues
gh issue create --title "Retro Action: {action}" \
--body "From Sprint {N} retrospective.
## Action
{detailed description}
## Owner
{name}
## Due
{date}" \
--label "type:chore" --milestone "Sprint {N+1}"
Kanban Board Management
Create a GitHub Project board
# Create project
gh project create --title "{Project Name}" --owner "{owner}"
# List projects
gh project list --owner "{owner}"
Standard columns with WIP limits
| Column | Purpose | WIP Limit | Entry Criteria | Exit Criteria |
|---|---|---|---|---|
| Backlog | Ungroomed items | None | Issue exists | Groomed + estimated |
| Ready | Groomed, sprint-ready | None | Has acceptance criteria, estimated, labeled | Picked up by developer |
| In Progress | Actively being worked | 3 per dev | Assigned, branch created | PR opened |
| In Review | PR open, awaiting review | 5 total | PR passes CI | Approved with no changes requested |
| Done | Merged to main | None | PR merged, issue closed | Sprint ends |
Manage project items
# Add issue to project
gh project item-add {project_number} --owner "{owner}" --url "https://github.com/{owner}/{repo}/issues/{number}"
# Move item to column (update status field)
gh project item-edit --project-id {project_id} --id {item_id} --field-id {status_field_id} --single-select-option-id {option_id}
Kanban metrics
| Metric | Description | Calculation |
|---|---|---|
| Lead time | Backlog â Done | Time from issue creation to merge |
| Cycle time | In Progress â Done | Time from first commit to merge |
| Throughput | Issues completed per week | Count of Done items / time period |
| WIP age | How long items sit in progress | Current time – move to In Progress time |
Epic & Milestone Tracking
Create an epic (tracking issue)
gh issue create --title "Epic: {epic name}" \
--body "## Overview
{Description of the epic}
## Stories
- [ ] #{story_1} â {title}
- [ ] #{story_2} â {title}
- [ ] #{story_3} â {title}
## Acceptance Criteria
- [ ] {criterion}
## Notes
{Technical approach, design links, etc.}" \
--label "type:epic"
Milestone progress monitoring
# Check milestone progress
gh api repos/{owner}/{repo}/milestones --jq '.[] | "\(.title): \(.closed_issues)/\(.open_issues + .closed_issues) issues (\(.closed_issues * 100 / (.open_issues + .closed_issues) | round)% done)"'
# Issues remaining in milestone
gh issue list --state open --milestone "{milestone}" --json number,title,labels \
--jq '.[] | "#\(.number) \(.title) [\(.labels | map(.name) | join(", "))]"'
Decomposition strategy
Epic â Stories â Tasks
Decision logic:
âââ Can it be delivered in one sprint?
â âââ Yes â It's a Story (assign directly)
â âââ No â It's an Epic (decompose further)
âââ Can a story be completed by one developer in < 3 days?
â âââ Yes â Keep as-is
â âââ No â Split into smaller stories
âââ Does a story have clear acceptance criteria?
âââ Yes â Ready for sprint
âââ No â Needs grooming (add "status:needs-info" label)
Status Reports & Standups
Daily standup report
echo "## Daily Standup â $(date +%Y-%m-%d)"
echo ""
echo "### Done (merged yesterday)"
gh pr list --state merged --search "merged:>=$(date -v-1d +%Y-%m-%d)" --json number,title \
--jq '.[] | "- PR #\(.number): \(.title)"'
echo ""
echo "### In Progress"
gh pr list --state open --json number,title,author \
--jq '.[] | "- PR #\(.number): \(.title) (@\(.author.login))"'
echo ""
echo "### Blocked"
gh issue list --state open --label "status:blocked" --json number,title \
--jq '.[] | "- #\(.number): \(.title)"'
Sprint progress report
echo "## Sprint Progress â $(date +%Y-%m-%d)"
echo ""
# Total vs completed
total=$(gh issue list --milestone "{milestone}" --state all --json number --jq 'length')
closed=$(gh issue list --milestone "{milestone}" --state closed --json number --jq 'length')
open=$(gh issue list --milestone "{milestone}" --state open --json number --jq 'length')
echo "**Progress:** $closed / $total issues ($open remaining)"
echo ""
echo "### Remaining Issues"
gh issue list --state open --milestone "{milestone}" --json number,title,assignees,labels \
--jq '.[] | "- #\(.number) \(.title) [\(.assignees | map(.login) | join(", "))]"'
Definition of Done
Universal DoD checklist
- Code compiles/builds without errors
- All existing tests pass
- New tests written for new functionality
- Code reviewed and approved (at least 1 reviewer)
- No unresolved review comments
- PR linked to issue with
Closes #N - No linting errors or warnings
- Documentation updated if user-facing behavior changed
- No security vulnerabilities introduced
Per-type DoD
Bug fix:
- Root cause identified and documented in PR
- Regression test added that would catch recurrence
- Fix verified in the environment where the bug was reported
Feature:
- Acceptance criteria from the issue are met
- Edge cases handled
- Loading/error states handled (if UI)
- Accessible (if UI â keyboard nav, screen reader, contrast)
Chore:
- No functional regressions
- Build/CI still passes
- Relevant documentation updated
Automated DoD verification
# Run before marking any issue as done
echo "=== Definition of Done Check ==="
echo ""
# 1. Build
echo "1. Build..."
{build_command} && echo " PASS" || echo " FAIL"
# 2. Tests
echo "2. Tests..."
{test_command} && echo " PASS" || echo " FAIL"
# 3. Lint
echo "3. Lint..."
{lint_command} && echo " PASS" || echo " FAIL"
# 4. PR exists and references issue
echo "4. PR check..."
gh pr list --head "$(git branch --show-current)" --json number,body \
--jq '.[0].body' | grep -q "Closes #" && echo " PASS â PR references issue" || echo " FAIL â PR missing Closes #N"
# 5. Review approval
echo "5. Review status..."
gh pr view --json reviewDecision --jq '.reviewDecision' | grep -q "APPROVED" && echo " PASS" || echo " NEEDS REVIEW"
Part 3: Repository Management
Branch Strategy
Decision tree
Choose your branch strategy:
âââ Solo developer or very small team (1â3)?
â âââ GitHub Flow (simple)
âââ Regular release schedule with staging?
â âââ GitFlow
âââ Continuous deployment, trunk always deployable?
â âââ Trunk-Based Development
âââ Unsure?
âââ Start with GitHub Flow, evolve to GitFlow if release complexity grows
GitHub Flow (recommended for most projects)
main âââââââââââââââââââââââââââ
\ /
feature/my-feature
mainis always deployable- Create feature branches from
main - Open PR, review, merge back to
main - Deploy from
main
git checkout -b feature/my-feature main
# ... work ...
git push -u origin feature/my-feature
gh pr create --base main --title "Add my feature"
# After review:
gh pr merge --squash --delete-branch
GitFlow
main ââââââââââââââââââââââââââââ
\ / \ /
develop âââââââââââââââ ââââ
\ / \ /
feature/x release/1.0
\
hotfix/urgent
Branch purposes:
mainâ production-ready, tagged releases onlydevelopâ integration branch, next releasefeature/*â new work, branch fromdeveloprelease/*â release prep, branch fromdevelop, merge to bothmainanddevelophotfix/*â urgent production fix, branch frommain, merge to bothmainanddevelop
# Start feature
git checkout -b feature/my-feature develop
# Finish feature
git checkout develop
git merge --no-ff feature/my-feature
git branch -d feature/my-feature
# Start release
git checkout -b release/1.0 develop
# Finish release
git checkout main
git merge --no-ff release/1.0
git tag -a v1.0.0 -m "Release 1.0.0"
git checkout develop
git merge --no-ff release/1.0
git branch -d release/1.0
# Hotfix
git checkout -b hotfix/urgent main
# ... fix ...
git checkout main
git merge --no-ff hotfix/urgent
git tag -a v1.0.1 -m "Hotfix 1.0.1"
git checkout develop
git merge --no-ff hotfix/urgent
git branch -d hotfix/urgent
Trunk-Based Development
main âââââââââââââââââââââââââââ
\ / \ /
short-lived branches (< 1 day)
- Everyone commits to
main(directly or via very short-lived branches) - Feature flags for incomplete work
- CI/CD deploys every commit
- Best for experienced teams with strong CI
# Short-lived branch
git checkout -b feat/quick-change main
# ... small, focused change ...
git push -u origin feat/quick-change
gh pr create --base main
# Merge same day
gh pr merge --squash --delete-branch
Conventional Commits
Format
<type>[optional scope][!]: <description>
[optional body]
[optional footer(s)]
Types
| Type | Purpose | SemVer Bump | Example |
|---|---|---|---|
feat |
New feature | Minor | feat(auth): add OAuth2 login |
fix |
Bug fix | Patch | fix(api): handle null response |
docs |
Documentation only | None | docs: update API reference |
style |
Formatting, semicolons, etc. | None | style: fix indentation in utils |
refactor |
Code change that neither fixes nor adds | None | refactor(db): simplify query builder |
perf |
Performance improvement | Patch | perf: cache user lookup results |
test |
Adding or correcting tests | None | test: add login flow integration test |
build |
Build system or dependencies | None | build: upgrade webpack to v5 |
ci |
CI configuration | None | ci: add Node 20 to test matrix |
chore |
Other changes (no src/test) | None | chore: update .gitignore |
revert |
Reverts a previous commit | Varies | revert: revert "feat(auth): add OAuth2" |
Breaking changes
Two ways to signal a breaking change (SemVer Major bump):
# Method 1: ! after type/scope
feat(api)!: change authentication endpoint format
# Method 2: BREAKING CHANGE footer
feat(api): change authentication endpoint format
BREAKING CHANGE: The /auth endpoint now requires a JSON body instead of query params.
Migration: Update all API calls to send { "token": "..." } in the request body.
Scope conventions
Scopes should match your project’s module/area structure:
feat(auth): # Authentication module
fix(ui/button): # UI button component
docs(api): # API documentation
ci(deploy): # Deployment pipeline
build(deps): # Dependency updates
Commitlint enforcement
# Install commitlint
npm install --save-dev @commitlint/cli @commitlint/config-conventional
# Or with bun:
bun add -d @commitlint/cli @commitlint/config-conventional
commitlint.config.js:
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [2, 'always', [
'feat', 'fix', 'docs', 'style', 'refactor',
'perf', 'test', 'build', 'ci', 'chore', 'revert'
]],
'subject-max-length': [2, 'always', 72],
'body-max-line-length': [2, 'always', 100],
},
};
Release Management
SemVer decision tree
What changed?
âââ Breaking API/behavior change?
â âââ MAJOR bump (X.0.0)
âââ New feature (backward compatible)?
â âââ MINOR bump (0.X.0)
âââ Bug fix (backward compatible)?
â âââ PATCH bump (0.0.X)
âââ Pre-release?
âââ Append suffix: 1.0.0-beta.1, 1.0.0-rc.1
Git tagging
# Annotated tag (recommended â stores author, date, message)
git tag -a v1.2.0 -m "Release 1.2.0: Add user profiles and fix login bug"
git push origin v1.2.0
# List tags
git tag -l "v*" --sort=-v:refname
# Delete tag (local + remote)
git tag -d v1.2.0
git push origin --delete v1.2.0
Changelog generation
# Using conventional-changelog
npx conventional-changelog -p angular -i CHANGELOG.md -s
# Using git log (manual)
git log v1.1.0..v1.2.0 --pretty=format:"- %s (%h)" --no-merges
# Group by type
echo "## [1.2.0] - $(date +%Y-%m-%d)"
echo ""
echo "### Features"
git log v1.1.0..v1.2.0 --pretty=format:"- %s (%h)" --no-merges --grep="^feat"
echo ""
echo "### Bug Fixes"
git log v1.1.0..v1.2.0 --pretty=format:"- %s (%h)" --no-merges --grep="^fix"
GitHub Releases
# Create release from tag
gh release create v1.2.0 --title "v1.2.0" --notes "$(cat <<'EOF'
## What's New
### Features
- Add user profiles (#42)
- Support dark mode (#55)
### Bug Fixes
- Fix login redirect loop (#38)
- Handle empty search results (#41)
### Breaking Changes
- None
**Full Changelog:** https://github.com/{owner}/{repo}/compare/v1.1.0...v1.2.0
EOF
)"
# Create pre-release
gh release create v2.0.0-beta.1 --prerelease --title "v2.0.0 Beta 1" --notes "Beta release for testing"
# Create draft release
gh release create v1.3.0 --draft --title "v1.3.0" --generate-notes
# Upload release assets
gh release upload v1.2.0 ./dist/app.zip ./dist/checksums.txt
Release checklist
## Release Checklist â v{X.Y.Z}
### Pre-release
- [ ] All issues in milestone are closed
- [ ] All PRs are merged
- [ ] CI/CD passes on main
- [ ] CHANGELOG.md updated
- [ ] Version bumped in package.json / pyproject.toml / Cargo.toml
- [ ] Documentation updated for new features
- [ ] No critical/high security alerts
### Release
- [ ] Create annotated tag: `git tag -a v{X.Y.Z} -m "Release {X.Y.Z}"`
- [ ] Push tag: `git push origin v{X.Y.Z}`
- [ ] Create GitHub Release with notes
- [ ] Upload any release assets
- [ ] Publish to package registry (npm, PyPI, crates.io) if applicable
### Post-release
- [ ] Verify deployment succeeded
- [ ] Smoke test critical paths
- [ ] Announce release (changelog link, migration guide if breaking)
- [ ] Close milestone
- [ ] Create next milestone
Rollback procedures
# Revert the release commit (safest)
git revert {release_commit_hash}
git push origin main
# Or point main back to previous release
git checkout main
git reset --hard v1.1.0
git push origin main --force-with-lease # DANGEROUS â confirm with team first
# Delete the bad release
gh release delete v1.2.0 --yes
git tag -d v1.2.0
git push origin --delete v1.2.0
# Hotfix workflow (preferred over rollback)
git checkout -b hotfix/1.2.1 v1.2.0
# ... fix the issue ...
git push -u origin hotfix/1.2.1
gh pr create --base main --title "Hotfix: {description}"
Repository Setup & Configuration
.gitattributes template
# Auto-detect text files and normalize line endings
* text=auto
# Force LF for specific files
*.js text eol=lf
*.jsx text eol=lf
*.ts text eol=lf
*.tsx text eol=lf
*.json text eol=lf
*.md text eol=lf
*.yml text eol=lf
*.yaml text eol=lf
*.css text eol=lf
*.html text eol=lf
*.sh text eol=lf
# Binary files
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.ico binary
*.woff binary
*.woff2 binary
*.ttf binary
*.eot binary
*.pdf binary
*.zip binary
# Git LFS (uncomment and customize)
# *.psd filter=lfs diff=lfs merge=lfs -text
# *.sketch filter=lfs diff=lfs merge=lfs -text
# *.fig filter=lfs diff=lfs merge=lfs -text
# Linguist overrides (for accurate language stats)
# vendor/* linguist-vendored
# docs/* linguist-documentation
.gitignore best practices
# Dependencies
node_modules/
.pnp/
.pnp.js
# Build output
dist/
build/
.next/
out/
# Environment
.env
.env.local
.env.*.local
# IDE
.idea/
.vscode/
*.swp
*.swo
*~
.DS_Store
# Test / coverage
coverage/
.nyc_output/
# Logs
*.log
npm-debug.log*
# OS
Thumbs.db
CODEOWNERS
# Default owners for everything
* @team-lead
# Frontend
/src/components/ @frontend-team
/src/pages/ @frontend-team
/src/styles/ @frontend-team
# Backend
/src/api/ @backend-team
/src/server/ @backend-team
/src/db/ @backend-team
# Infrastructure
/.github/ @devops-team
/Dockerfile @devops-team
/docker-compose*.yml @devops-team
/terraform/ @devops-team
# Documentation
/docs/ @docs-team
*.md @docs-team
Branch protection rules
# Protect main branch
gh api repos/{owner}/{repo}/branches/main/protection \
-X PUT \
-H "Accept: application/vnd.github+json" \
-f required_status_checks='{"strict":true,"contexts":["ci/test","ci/build"]}' \
-f enforce_admins=true \
-f required_pull_request_reviews='{"required_approving_review_count":1,"dismiss_stale_reviews":true}' \
-f restrictions=null \
-f allow_force_pushes=false \
-f allow_deletions=false
# View current protection
gh api repos/{owner}/{repo}/branches/main/protection
Issue and PR templates
Create .github/ISSUE_TEMPLATE/bug_report.md:
---
name: Bug Report
about: Report a bug
labels: type:bug
---
## Description
<!-- What happened? -->
## Expected Behavior
<!-- What should have happened? -->
## Steps to Reproduce
1.
## Environment
- OS:
- Version:
## Screenshots / Logs
<!-- If applicable -->
Create .github/PULL_REQUEST_TEMPLATE.md:
## Summary
<!-- What does this PR do? -->
## Related Issue
Closes #
## Changes
-
## Testing
- [ ] Unit tests pass
- [ ] Manual testing done
## Screenshots
<!-- If UI changes -->
Repository Health
Stale branch detection and cleanup
# Find branches with no commits in 30+ days
git for-each-ref --sort=committerdate refs/remotes/origin/ \
--format='%(committerdate:short) %(refname:short)' | \
while read date branch; do
if [ "$(date -d "$date" +%s 2>/dev/null || date -j -f "%Y-%m-%d" "$date" +%s)" -lt "$(date -v-30d +%s 2>/dev/null || date -d '30 days ago' +%s)" ]; then
echo "STALE: $branch (last commit: $date)"
fi
done
# Delete stale remote branches (after confirmation)
git push origin --delete {branch_name}
# Prune local tracking refs
git remote prune origin
Orphaned PR detection
# Find PRs that reference deleted branches
gh pr list --state open --json number,title,headRefName,updatedAt \
--jq '.[] | "#\(.number) \(.title) â branch: \(.headRefName) â updated: \(.updatedAt)"'
# Find PRs with no activity in 14+ days
gh pr list --state open --json number,title,updatedAt \
--jq '[.[] | select(.updatedAt < (now - 1209600 | todate))] | .[] | "#\(.number) \(.title) (stale since \(.updatedAt))"'
Large file detection
# Find large files in current tree (> 1MB)
git ls-files -z | xargs -0 -I{} sh -c 'size=$(wc -c < "{}"); if [ "$size" -gt 1048576 ]; then echo "$size {}"; fi' | sort -rn | head -20
# Find large files in entire history
git rev-list --objects --all | \
git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | \
awk '/^blob/ {print $3, $4}' | sort -rn | head -20
# Repo size
git count-objects -vH
Security alerts and dependency audit
# Check Dependabot alerts
gh api repos/{owner}/{repo}/dependabot/alerts --jq '.[] | "\(.security_advisory.severity): \(.security_advisory.summary) (\(.dependency.package.name))"'
# npm audit
npm audit --json | jq '.vulnerabilities | to_entries[] | "\(.value.severity): \(.key) â \(.value.title)"'
# Check for secrets in recent commits
git log --all --diff-filter=A --name-only --pretty=format: | sort -u | \
grep -iE '\.(env|pem|key|secret|credentials|token)$'
Repository statistics
# Contributor stats
gh api repos/{owner}/{repo}/contributors --jq '.[] | "\(.login): \(.contributions) commits"'
# Code frequency (additions/deletions per week)
gh api repos/{owner}/{repo}/stats/code_frequency --jq '.[-4:][] | "Week \(.[0]): +\(.[1]) -\(.[2])"'
# File hotspots (most frequently changed files)
git log --name-only --pretty=format: --since="3 months ago" | sort | uniq -c | sort -rn | head -20
Monorepo Management
Workspace configurations
bun (bun workspaces):
{
"workspaces": ["packages/*", "apps/*"]
}
pnpm (pnpm-workspace.yaml):
packages:
- 'packages/*'
- 'apps/*'
npm/yarn (package.json):
{
"workspaces": ["packages/*", "apps/*"]
}
Changeset management
# Install changesets
bun add -d @changesets/cli
# Initialize
bun changeset init
# Create a changeset (after making changes)
bun changeset
# Prompts: which packages changed? major/minor/patch? description?
# Version packages (updates package.json + CHANGELOG.md)
bun changeset version
# Publish to registry
bun changeset publish
Selective CI (detect changed packages)
# Get changed files between current branch and main
changed_files=$(git diff --name-only origin/main...HEAD)
# Determine affected packages
affected_packages=""
for file in $changed_files; do
pkg=$(echo "$file" | grep -oE '^(packages|apps)/[^/]+' || true)
if [ -n "$pkg" ]; then
affected_packages="$affected_packages $pkg"
fi
done
affected_packages=$(echo "$affected_packages" | tr ' ' '\n' | sort -u)
echo "Affected packages:"
echo "$affected_packages"
Cross-package dependency management
# Install syncpack for version consistency
bun add -d syncpack
# Check for mismatched dependency versions
bun syncpack list-mismatches
# Fix mismatched versions
bun syncpack fix-mismatches
Git Hooks & Automation
Husky setup
# Install husky
bun add -d husky
# Initialize husky
bunx husky init
# This creates .husky/ directory with a pre-commit hook
Pre-commit hook (lint-staged)
# Install lint-staged
bun add -d lint-staged
.husky/pre-commit:
bunx lint-staged
package.json (lint-staged config):
{
"lint-staged": {
"*.{js,jsx,ts,tsx}": ["eslint --fix", "prettier --write"],
"*.{json,md,yml,yaml}": ["prettier --write"],
"*.css": ["stylelint --fix", "prettier --write"]
}
}
Commit-msg hook (commitlint)
.husky/commit-msg:
bunx --no -- commitlint --edit "$1"
Pre-push hook
.husky/pre-push:
bun test --run
Post-merge hook (auto-install)
.husky/post-merge:
# Auto-install if lockfile changed
changed_files=$(git diff-tree -r --name-only --no-commit-id ORIG_HEAD HEAD)
if echo "$changed_files" | grep -qE "bun.lockb|package-lock.json|yarn.lock|pnpm-lock.yaml"; then
echo "Lockfile changed â running install..."
bun install
fi
Advanced Git Operations
Interactive rebase patterns
# Rebase last N commits for cleanup
git rebase -i HEAD~{N}
# Rebase onto main (update feature branch)
git rebase origin/main
# If rebase goes wrong â abort and start over
git rebase --abort
# If rebase has conflicts â resolve then continue
# (edit conflicted files, then:)
git add {resolved_files}
git rebase --continue
# Rebase recovery if you already completed a bad rebase
git reflog
git reset --hard {ref_before_rebase}
Cherry-pick workflows
# Pick a single commit
git cherry-pick {commit_hash}
# Pick multiple commits
git cherry-pick {hash1} {hash2} {hash3}
# Pick a range
git cherry-pick {start_hash}..{end_hash}
# Cherry-pick without committing (stage only)
git cherry-pick --no-commit {hash}
# If conflicts occur
git cherry-pick --abort # Cancel
git cherry-pick --continue # After resolving conflicts
Bisect for bug finding
# Manual bisect
git bisect start
git bisect bad # Current commit is broken
git bisect good v1.0.0 # This version was working
# Git checks out midpoint â test it, then:
git bisect good # or git bisect bad
# Repeat until Git identifies the first bad commit
git bisect reset # Return to original state
# Automated bisect with test script
git bisect start HEAD v1.0.0
git bisect run {test_command}
# Example: git bisect run bun test -- --run tests/login.test.ts
git bisect reset
Worktree management
# Add a worktree for a branch
git worktree add ../worktree-feature feature/my-feature
# Add a worktree with a new branch
git worktree add -b hotfix/urgent ../worktree-hotfix main
# List worktrees
git worktree list
# Remove a worktree
git worktree remove ../worktree-feature
# Prune stale worktree references
git worktree prune
Stash management
# Stash changes with message
git stash push -m "WIP: feature description"
# Stash including untracked files
git stash push -u -m "WIP: includes new files"
# List stashes
git stash list
# Apply most recent stash (keep in stash list)
git stash apply
# Apply and remove most recent stash
git stash pop
# Apply specific stash
git stash apply stash@{2}
# Show stash diff
git stash show -p stash@{0}
# Drop specific stash
git stash drop stash@{1}
# Clear all stashes
git stash clear
Reflog recovery
# View reflog (all HEAD movements)
git reflog
# Recover deleted branch
git reflog | grep "checkout: moving from {branch_name}"
git checkout -b {branch_name} {hash}
# Recover after hard reset
git reflog
git reset --hard {hash_before_reset}
# Recover lost commit
git reflog
git cherry-pick {lost_commit_hash}
Submodules vs Subtrees
Decision:
âââ Need independent versioning of sub-repo?
â âââ Submodule
âââ Want simpler workflow (no .gitmodules)?
â âââ Subtree
âââ Sub-repo contributors don't know about parent?
â âââ Subtree
âââ Need to pin exact commit of dependency?
âââ Submodule
Submodule commands:
# Add submodule
git submodule add {url} {path}
# Clone repo with submodules
git clone --recurse-submodules {url}
# Update submodules
git submodule update --init --recursive
# Update to latest remote
git submodule update --remote
Subtree commands:
# Add subtree
git subtree add --prefix={path} {url} {branch} --squash
# Pull updates
git subtree pull --prefix={path} {url} {branch} --squash
# Push changes back to sub-repo
git subtree push --prefix={path} {url} {branch}
Part 4: CI/CD & Quality
GitHub Actions Workflow Templates
CI workflow (test on every push/PR)
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18, 20, 22]
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- run: bun install --frozen-lockfile
- run: bun run lint
- run: bun test --run
- run: bun run build
PR checks workflow
# .github/workflows/pr-checks.yml
name: PR Checks
on:
pull_request:
types: [opened, synchronize, reopened]
jobs:
checks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- run: bun install --frozen-lockfile
- run: bun run lint
- run: bun test --run
- run: bun run build
# Verify PR has issue reference
- name: Check PR body
run: |
if ! echo "${{ github.event.pull_request.body }}" | grep -qE "Closes #|Fixes #|Resolves #"; then
echo "::warning::PR body should reference an issue (Closes #N)"
fi
Release workflow
# .github/workflows/release.yml
name: Release
on:
push:
tags:
- 'v*'
jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: oven-sh/setup-bun@v2
- run: bun install --frozen-lockfile
- run: bun test --run
- run: bun run build
- name: Create GitHub Release
run: |
gh release create ${{ github.ref_name }} \
--title "${{ github.ref_name }}" \
--generate-notes
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Dependency update workflow
# .github/workflows/deps.yml
name: Dependency Updates
on:
schedule:
- cron: '0 9 * * 1' # Every Monday at 9am
workflow_dispatch:
jobs:
update:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- run: bun install
- run: bun update
- name: Create PR if changes
run: |
if [ -n "$(git status --porcelain)" ]; then
git checkout -b chore/update-deps-$(date +%Y%m%d)
git add -A
git commit -m "chore(deps): update dependencies"
git push -u origin HEAD
gh pr create --title "chore(deps): weekly dependency update" \
--body "Automated weekly dependency update."
fi
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Test Gates & Coverage
# Add to CI workflow
- name: Run tests with coverage
run: bun test --run --coverage
- name: Check coverage threshold
run: |
# Fail if coverage drops below threshold
# Adjust the tool and threshold for your project
coverage=$(bun test --run --coverage 2>&1 | grep -oP 'Statements\s*:\s*\K[\d.]+')
threshold=80
if (( $(echo "$coverage < $threshold" | bc -l) )); then
echo "Coverage $coverage% is below threshold $threshold%"
exit 1
fi
Security Scanning
Dependabot configuration
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
labels:
- "type:chore"
- "area:deps"
commit-message:
prefix: "chore(deps):"
open-pull-requests-limit: 10
groups:
dev-dependencies:
dependency-type: "development"
production-dependencies:
dependency-type: "production"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
labels:
- "type:ci"
Secret scanning
# Install gitleaks
brew install gitleaks # macOS
# Or: go install github.com/gitleaks/gitleaks/v8@latest
# Scan current state
gitleaks detect --source . --verbose
# Scan git history
gitleaks detect --source . --verbose --log-opts="--all"
# Use in pre-commit hook
gitleaks protect --staged --verbose
Deployment Strategy Decision Tree
What are you deploying?
âââ Static site / frontend?
â âââ Vercel, Netlify, Cloudflare Pages
â âââ GitHub Pages (simple static)
âââ Full-stack web app?
â âââ Vercel (Next.js, Nuxt)
â âââ Railway, Render, Fly.io
â âââ AWS/GCP/Azure (complex infra)
âââ API / backend service?
â âââ Serverless: Vercel Functions, AWS Lambda, Cloudflare Workers
â âââ Container: Docker â Railway, Fly.io, ECS, Cloud Run
âââ Package / library?
â âââ npm: `npm publish` or `bun publish`
â âââ PyPI: `twine upload`
â âââ Crates.io: `cargo publish`
âââ Mobile app?
â âââ Expo EAS (React Native)
â âââ Fastlane (iOS/Android)
â âââ App Store / Play Store manual
âââ Desktop app?
âââ Electron Builder / Tauri
Part 5: Code Review Standards
Review Checklist
When reviewing a PR, check each category:
Correctness:
- Does the code do what the PR/issue describes?
- Are edge cases handled?
- Are error conditions handled appropriately?
Tests:
- Are there tests for new functionality?
- Do tests cover edge cases?
- Are tests deterministic (no flaky tests)?
Security:
- No hardcoded secrets or credentials
- User input is validated/sanitized
- No SQL injection, XSS, or other OWASP top 10 vulnerabilities
- Authentication/authorization checked where needed
Performance:
- No N+1 queries
- No unnecessary re-renders (React)
- No memory leaks (event listeners, subscriptions)
- Appropriate use of caching
Style & Maintainability:
- Code follows project conventions
- No dead code or commented-out code
- Variable/function names are clear
- Complex logic has comments explaining “why”
Dependencies:
- No unnecessary new dependencies
- Dependencies are well-maintained and secure
- License compatibility checked
Comment Templates
Suggestion (optional improvement):
**Suggestion:** Consider using `Array.from()` here instead of spread for better readability with map.
{code suggestion}
Not blocking â just a thought.
Required change (must fix before merge):
**Required:** This will throw if `user` is null. We need a null check here since the API can return null for deleted users.
{code suggestion}
Nitpick (trivial, non-blocking):
**Nit:** Trailing whitespace on line 42.
Question (seeking clarification):
**Question:** Is there a reason we're using `setTimeout` instead of `requestAnimationFrame` here? Curious about the tradeoff.
Automated First-Pass Review
Use the agent to perform an initial review pass:
# 1. Get the PR diff
gh pr diff {number} > /tmp/pr-diff.txt
# 2. Get PR details
gh pr view {number} --json title,body,labels,files
# 3. Review each changed file
gh pr diff {number} --name-only | while read file; do
echo "=== Reviewing: $file ==="
gh pr diff {number} -- "$file"
done
# 4. Submit review
gh pr review {number} --approve --body "LGTM â {summary of what was checked}"
# Or request changes:
gh pr review {number} --request-changes --body "{detailed feedback}"
# Or comment only:
gh pr review {number} --comment --body "{observations}"
SVN-to-Git Migration Reference
Author mapping
# Extract SVN authors
svn log --quiet {svn_url} | grep "^r" | awk '{print $3}' | sort -u > svn-authors.txt
# Create author mapping file (authors.txt)
# Format: svn_username = Full Name <email@example.com>
# Example:
# jdoe = John Doe <john@example.com>
# asmith = Alice Smith <alice@example.com>
Clone with history preservation
# Standard clone (full history)
git svn clone {svn_url} --authors-file=authors.txt --stdlayout {repo_name}
# For large repos â batch fetching
git svn clone {svn_url} --authors-file=authors.txt --stdlayout --no-metadata \
-r1:1000 {repo_name}
cd {repo_name}
git svn fetch -r1001:2000
git svn fetch -r2001:HEAD
# If trunk/branches/tags aren't standard layout:
git svn clone {svn_url} \
--trunk=trunk \
--branches=branches \
--tags=tags \
--authors-file=authors.txt \
{repo_name}
Post-migration cleanup
cd {repo_name}
# Convert SVN tags to Git tags
git for-each-ref refs/remotes/origin/tags/ --format='%(refname:short)' | while read tag; do
git_tag=$(echo "$tag" | sed 's|origin/tags/||')
git tag "$git_tag" "$tag"
git branch -rd "$tag"
done
# Convert SVN branches to Git branches
git for-each-ref refs/remotes/origin/ --format='%(refname:short)' | while read branch; do
git_branch=$(echo "$branch" | sed 's|origin/||')
if [ "$git_branch" != "trunk" ]; then
git branch "$git_branch" "$branch"
git branch -rd "$branch"
fi
done
# Remove SVN metadata
git branch -rd origin/trunk 2>/dev/null
rm -rf .git/svn
# Clean up
git gc --aggressive --prune=now
Verification
# Verify commit count matches
svn_count=$(svn log --quiet {svn_url} | grep "^r" | wc -l)
git_count=$(git rev-list --count HEAD)
echo "SVN commits: $svn_count, Git commits: $git_count"
# Verify tags
git tag -l | wc -l
# Verify branches
git branch -a | wc -l
# Check repo size
git count-objects -vH
# Add remote and push
git remote add origin {git_url}
git push -u origin --all
git push origin --tags
Git Error Recovery Cheat Sheet
| Situation | Command |
|---|---|
| Undo last commit (keep changes staged) | git reset --soft HEAD~1 |
| Undo last commit (keep changes unstaged) | git reset HEAD~1 |
| Undo last commit (discard changes) | git reset --hard HEAD~1 |
| Unstage a file | git restore --staged {file} |
| Discard changes to a file | git restore {file} |
| Recover deleted branch | git reflog â git checkout -b {name} {hash} |
| Abort a merge in progress | git merge --abort |
| Abort a rebase in progress | git rebase --abort |
| Abort a cherry-pick | git cherry-pick --abort |
| Fix the last commit message | git commit --amend -m "new message" |
| Add forgotten file to last commit | git add {file} â git commit --amend --no-edit |
| Undo a pushed commit (safe) | git revert {hash} â git push |
| Find which commit introduced a bug | git bisect start â git bisect bad â git bisect good {hash} |
| See what happened to HEAD | git reflog |
| Recover file from specific commit | git checkout {hash} -- {file} |
| Remove file from Git but keep locally | git rm --cached {file} |
| Clean untracked files | git clean -fd (directories too) |
| Clean untracked + ignored files | git clean -fdx |
| Fix detached HEAD | git checkout main or git checkout -b {new_branch} |
Undo git stash pop with conflicts |
git checkout -- . â stash is still in git stash list |
| Remove sensitive data from history | git filter-repo --path {file} --invert-paths |
Rules & Best Practices
Branching
- Convention:
fix/{issue-number}-short-description,feat/{issue-number}-short-description - One branch per issue (or per issue group if they share files)
- Always rebase onto main before merging â never merge main into feature branches
- Delete branches after merge
Pull Requests
- Body MUST include
Closes #{number}to auto-close issues on merge - Title: concise, under 70 characters, conventional commit style
- Use squash merge to keep git history clean
- Delete remote branch after merge
- Request at least 1 review before merge
Commit Conventions
- Use conventional commits format:
type(scope): description - Subject line ⤠72 characters
- Body wrapped at 100 characters
- Reference issues in the body:
Refs #123 - One logical change per commit
Parallel Safety
- Issues touching the same files go to the same developer
- Each developer works in an isolated worktree or clone
- Never have two developers editing the same file concurrently
- Maximum 3â5 parallel developers to manage resource usage
Review Etiquette
- Always reply to comments explaining what was fixed and referencing the commit
- Always resolve the review thread after replying
- If a comment is not applicable, reply explaining why (don’t ignore it)
- Distinguish between required changes, suggestions, and nitpicks
Release Safety
- Always run full test suite before tagging
- Use annotated tags with descriptive messages
- Create GitHub Releases with changelogs
- Have a rollback plan before deploying
- Never force-push to main/release branches
Error Recovery
- If a developer fails, read their output to diagnose the issue
- Fix manually or respawn with better instructions
- If merge conflicts arise, always rebase (never merge main into branches)
- If worktrees are stuck, force-remove and prune
- Use
git reflogas your safety net â it records all HEAD movements for 90 days
Project Convention Discovery
- Read
CLAUDE.md,CONTRIBUTING.md, or equivalent for project rules - Run the project’s formatter/linter before committing
- Run the project’s test suite before creating PRs
- Use the project’s package manager (don’t mix npm/yarn/pnpm/bun)
- Check for
.editorconfig,prettier.config,eslint.configfor style rules
Platform-Specific Notes
Claude Code
- Use
Tasktool withisolation: "worktree"for parallel developers - Use
TeamCreate/TeamDeletefor team orchestration - Use
TaskCreate/TaskUpdatefor task tracking - Use
SendMessagewithtype: "shutdown_request"to dismiss developers - Use
Bashtool for allghandgitCLI commands - Use
Read/Glob/Greptools for code exploration before making changes - Use
EnterPlanModebefore major implementation work
Cursor / Windsurf / Copilot
- Open multiple terminal tabs for parallel work
- Use
git worktree addmanually to create isolated workspaces - Track progress in a checklist or project board
- Run fix agents sequentially if parallel execution isn’t supported
- Use inline code actions for quick fixes during review
- Leverage built-in Git integration for staging, committing, and pushing
Codex / OpenClaw
- Use sandbox environments for isolated execution
- Batch operations where possible to reduce API calls
- Use structured output for parsing
ghcommand results - Chain commands with
&&for atomic operations - Log all operations for audit trail
Aider / CLI-based Assistants
- Use
git worktree add ../worktree-{issue} -b fix/{issue}-{slug}for isolation - Run one instance per worktree for parallelism
- Coordinate via shared task file or git notes
- Use
--yesflag for non-interactive operation where supported - Pipe
ghoutput throughjqfor structured processing
Universal (All Platforms)
- The core workflows (issue resolution, sprint planning, releases) are platform-agnostic
- All
ghCLI commands work everywhere GitHub CLI is installed - All
gitcommands are standard and platform-independent - Adapt tool calls to your platform’s specific API
- When in doubt, fall back to raw
gitandghcommands in the terminal - Test all commands in a safe environment before running on production repos