Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
288 changes: 148 additions & 140 deletions .claude/skills/git-workflow/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,210 +5,218 @@ description: Git workflow standards - branch management, commit conventions, and

# Git Workflow and Conventions

Standard Git workflow including branching strategy, commit message format, and pull request creation.
Worktree-aware Git workflow using `mise run git:*` tasks.

## Quick Start Workflow
## Quick Reference

```sh
# Step 1: Setup
git fetch --prune
# Basic operations
mise run git:status # Show current state + next action
mise run git:home # Switch to home branch + sync with origin/main
mise run git:new <branch> # Create new branch from origin/main
mise run git:cleanup [branch] # Delete merged branch + return to home

# PR lifecycle (CI wait -> browser open -> merge watch -> cleanup)
mise run git:open-pr <pr#> # All-in-one: CI -> open -> watch -> cleanup

# Pause / discard / undo
mise run git:pause [message] # WIP commit + return to home (for switching tasks)
mise run git:abandon # Discard all changes + return to home
mise run git:undo # Soft reset HEAD~1 (undo last commit)

# Stacked PRs
mise run git:sync # Sync current branch after base PR merge
```

> **Note**: These tasks use the `gw` Rust CLI ([crates.io](https://crates.io/crates/git-workflow)). Install with `cargo install git-workflow`.

# Step 2: Create feature branch
git switch -c feature/your-branch-name origin/main
> **Pitfalls**
> - **Do not run `git checkout main`** — use `mise run git:home` instead (worktree conflict)
> - **Do not use `git stash`** — use `mise run git:pause` instead (creates WIP commit for safer worktree switching)
> - **Do not manually rebase stacked PRs** — use `mise run git:sync` instead (updates GitHub PR base + rebases)

# Step 3: Make changes and commit
git add [<files>]
git commit -m "[commit message]"
git push --set-upstream origin feature/your-branch-name
## Standard Workflow: Code -> PR

# Step 4: Create Pull Request
gh pr create -a "@me" -t "[title]"
**Every code change should become a PR.** Follow this flow:

# Step 5: Check CI Status
gh pr checks --watch
```
1. Branch -> mise run git:new -- feature/your-feature
2. Code -> make changes
3. Commit -> git add -A && git commit -m "feat: ..."
4. Push -> git push -u origin feature/your-feature
5. PR -> gh pr create -a "@me" -t "feat: ..."
6. Open -> mise run git:open-pr <pr#> (CI wait -> browser -> merge watch -> cleanup)
7. Cleanup -> (auto: merge detected -> git:cleanup runs)
```

# Step 6: Open PR in browser for review
gh pr view --web
### git:open-pr — PR Lifecycle Management (Claude Code Background Task)

# Step 7: After merging, clean up branches
# Standard:
git switch main && git pull
git branch -d <branch_name>
# Worktree (when main is used elsewhere):
git switch <worktree-branch> && git pull origin main
git branch -d <branch_name>
After creating a PR, run in background:

```
Claude: [Bash(run_in_background=true)] mise run git:open-pr -- <pr#>
```

## Branching Strategy
3 phases run automatically:
1. **CI wait** — `gh pr checks --watch` waits for CI to pass
2. **Open in browser** — Opens PR page in default browser
3. **Merge watch** — Polls PR state every 30s
- MERGED -> macOS notification + `mise run git:cleanup` -> exit
- CLOSED -> message -> exit

**Claude behavior**: When background task output arrives via `<system-reminder>`, Claude MUST:
1. Read the output file with `TaskOutput` or `Read`
2. Report the result to the user immediately
3. Show key information: merged/closed status, cleanup success/failure

### Always Branch from `origin/main`
**Run `mise run git:status` at any point to see what to do next.**

Create all feature branches from the latest `origin/main`:
### If you have uncommitted changes on home branch

This happens when you made changes before creating a branch. Fix it:

```sh
git fetch --prune
git switch -c feature/your-branch-name origin/main
# 1. Create branch (keeps your changes)
mise run git:new -- feature/your-feature

# 2. Now follow git:status
mise run git:status
# -> Will suggest: commit, push, create PR
```

### Git Worktree Support
## Proactive Workflow

When working in a git worktree (e.g., `wt-2` directory), the `main` branch is used by another worktree and cannot be checked out directly. In this case:
**Always run `mise run git:status` and follow the "Next:" action.**

1. **The directory name (e.g., `wt-2`) acts as the local main branch equivalent**
2. **Always branch from `origin/main`** (not local main)
3. **After merge, update with**: `git pull origin main` (instead of `git switch main && git pull`)
The status command automatically detects:
- Working directory state (clean/uncommitted changes)
- Sync state with upstream (pushed/unpushed/behind)
- PR state (none/open/merged/closed)

```sh
# In worktree environment - post-merge cleanup:
git switch <worktree-branch> # e.g., wt-2
git pull origin main
git branch -d <merged-branch-name>
```
And suggests the appropriate next action:

### Branch Naming Convention
| Status Output | Action |
|--------------|--------|
| `Next: start new work` | `mise run git:new -- feature/...` |
| `Next: commit changes` | `git add -A && git commit -m "..."` |
| `Next: push to remote` | `git push -u origin <branch>` |
| `Next: create pull request` | `gh pr create -a "@me" -t "..."` |
| `Waiting: PR #N in review` | Wait for CI/review, or start parallel work |
| `Next: cleanup merged branch` | `mise run git:cleanup` |
| `Next: rebase on latest main` | `git fetch && git rebase origin/main` |
| `Next: sync (base 'X' was merged)` | `mise run git:sync` |

## Branch Naming Convention

- `feature/` - New features
- `fix/` - Bug fixes
- `chore/` - Maintenance tasks
- `docs/` - Documentation updates
- `refactor/` - Code refactoring
- `test/` - Test additions or fixes

## Commit Message Format

Use Conventional Commits format:
Use Conventional Commits (one-line only):

```
<type>[optional scope]: <description>

[optional body]

[optional footer]
```

### Commit Types
### Types

- **fix**: Patches a bug in your codebase
- **feat**: Introduces a new feature to the codebase
- **chore**: Maintenance tasks (dependencies, configs, etc.)
- **feat**: New feature
- **fix**: Bug fix
- **chore**: Maintenance tasks
- **docs**: Documentation changes
- **style**: Code style changes (formatting, white-space, etc.)
- **refactor**: Code refactoring without changing functionality
- **refactor**: Code refactoring
- **perf**: Performance improvements
- **test**: Adding or modifying tests

### Commit Examples

**No body**:
### Examples

```
docs: correct spelling of CHANGELOG
feat(providers): add Gemini log parser
fix: correct token count in session summary
chore: bump version to 0.8.0
```

**With scope**:

```
feat(api): add user authentication endpoint
```
## PR Standards

**With body and footer**:
- **Language**: English
- **Title**: Descriptive. Use commit message if single commit
- **Body**: Explain changes and context
- **Size**: Keep PRs small and focused

```
fix: correct minor typos in code
## About Worktrees

see the issue for details on the typos fixed
This project uses git worktree. Each worktree has a **home branch**.

closes issue #12
```
- Home branch = directory name (e.g., `agtrace-2/` -> `agtrace-2` branch)
- Never checkout `main` directly (used by another worktree)
- Always branch from `origin/main`

## Pull Request Creation
The `mise run git:*` tasks handle this automatically.

### PR Standards
## Workflow: Stacked PRs

- **Language**: English
- **Title**: Descriptive of changes. Use commit message if branch has 1 commit
- **Body**: Explain changes, why they were made, and any relevant context
- **Keep PRs small and focused**: Easy to review and test
- **Keep PR Body up to date**: Reflect current state of changes
When working on features that depend on unmerged work:

### Create PR with GitHub CLI
### Creating Stacked PRs

```sh
# Basic PR creation
gh pr create -a "@me" -t "[title]"

# Wait for CI checks to complete
gh pr checks --watch

# Open in browser for review
gh pr view --web
# 1. Create base PR (depends on main)
mise run git:new -- feature/base
# ... commit, push, create PR ...

# 2. Create child PR (depends on base)
git checkout feature/base
git checkout -b feature/child
# ... commit, push ...
gh pr create --base feature/base -t "feat: child feature"
```

## Post-Merge Cleanup
### After Base is Merged

After PR is merged:
When the base PR is merged, `gw status` will detect this and suggest syncing:

```sh
# Standard environment:
git switch main
git pull
git branch -d <merged-branch-name>

# Git worktree environment (when main is used by another worktree):
git switch <worktree-branch> # e.g., wt-2
git pull origin main
git branch -d <merged-branch-name>
```
Base PR: #123 [MERGED]
-> Next: sync (base 'feature/base' was merged)

## Workflow: Incidental Refactoring (Yak Shaving Protocol)
mise run git:sync
```

When you identify necessary refactoring while working on a feature branch (but it's outside the scope or too large):
Run `mise run git:sync` to:
1. Update child PR's base to `main`
2. Rebase child branch on `origin/main`
3. Force push the updated branch

**Do not mix refactoring into the feature branch.** Use a Draft PR as your "base camp" to avoid getting lost in Yak Shaving.
**Do not manually `git rebase`** — always use `git:sync` to keep GitHub PR base and local branch in sync.

### Why Draft PR as Base Camp?
## Workflow: Incidental Refactoring (Yak Shaving Protocol)

- **Outsource memory to GitHub**: Free your brain's stack by writing down what you're doing
- **Always have a way back**: No matter how deep the refactoring rabbit hole, your Draft PR anchors you
- **Terminal-first**: Use `gh` commands to stay focused without browser context-switching
When you discover necessary refactoring during feature work, **don't mix it into the feature branch**.

### The Flow

1. **Anchor the Context (Don't forget why!)**:
Before leaving, ensure a Draft PR exists for your current feature and document what you were doing.
```sh
# If PR doesn't exist yet, create a Draft PR as a notepad
gh pr create --draft -a "@me" -t "WIP: [Current Feature]" -b "- [ ] Implement X (Paused for refactoring Y)"

# If PR exists, add a comment about the distraction
gh pr comment --body "Paused to refactor [Component Y]. Will resume after merging that."
```

2. **Stash current changes**:
```sh
git stash -u -m "Paused: [Current Feature] - waiting for refactor"
```

3. **Create & Ship Refactor** (works in both standard and worktree environments):
```sh
git fetch --prune
git switch -c refactor/descriptive-name origin/main
# ... Implementation ...
git push --set-upstream origin refactor/descriptive-name
gh pr create -a "@me" -t "refactor: [description]"
```

4. **Resume Feature Work**:
```sh
git switch feature/original-branch
# Option A: Rebase onto the refactor branch to use it immediately
git rebase refactor/descriptive-name
# Option B: Wait for merge, then rebase on main
# git fetch --prune && git rebase origin/main
git stash pop
```

5. **Review the Anchor**:
Check your Draft PR to remember the original goal.
```sh
gh pr view --web
```
1. **Pause current work** (WIP commit + return to home):
```sh
mise run git:pause -- "waiting for refactor Y"
# Creates WIP commit, comments on PR if exists, switches to home
```

2. **Create & ship the refactor**:
```sh
mise run git:new -- refactor/descriptive-name
# ... implement the fix ...
mise run git:status # Follow the "Next:" action
# ... commit, push, PR, merge, cleanup ...
```

3. **Resume feature work**:
```sh
git checkout feature/original-branch
mise run git:undo # Undo the WIP commit (changes return to staged area)
mise run git:status # Continue from where you left off
```
Loading