---
name: ao-selective-branch
description: "Create clean git branches from feature work, excluding ao-ops files. Use for PR preparation."
category: git
version: 1.1.0
tier: 4
invokes: [ao-git, ao-interview]
invoked_by: [ao-branch-workflow]
state_files:
  read: [log/created-files.log]
  write: [log/selective-branch-*.log]
reference: [../../reference/selective-git-scripts.md, ../../reference/file-audit-trail.md]
---

# Selective Branch — Clean Branch Creation

> Create a clean git branch from feature work, excluding specific paths. Platform agnostic.

**Works with or without `aoc` CLI.** Uses standard git commands.

## Purpose

Create a new branch containing feature work while excluding agent/workflow files for clean PRs.

## CRITICAL: No Assumptions

> **NEVER assume. NEVER guess. ALWAYS ask.**

**Before creating ANY clean branch, confirm with user:**

| If unclear about... | ASK |
|---------------------|-----|
| Source branch | "Which branch contains your feature work?" |
| Clean branch name | "I'll create `{name}`. Does this look right?" |
| Base branch | "Which branch should excluded paths be restored from? (e.g., develop, main)" |
| What to exclude | "What paths should I exclude? (Default: .agent/ops/, .github/)" |

**NEVER:**
- Guess the base branch
- Assume exclusions without asking
- Create a branch without showing the user the exact name first
- Proceed if source branch is unclear

## Prerequisites

### MANDATORY: File Audit Trail

**The `.agent/ops/log/created-files.log` SHOULD exist before proceeding.**

**If present**: Use it for accurate change tracking
**If missing**: Fall back to git diff (see Fallback Strategy below)

### Fallback Strategy (when log is missing)

When `.agent/ops/log/created-files.log` is unavailable:

1. **Detect base branch** (develop, main, or merge-base)
2. **Use git diff** to identify all changed files:

**PowerShell:**
```powershell
$base = git merge-base HEAD develop 2>$null
if (-not $base) { $base = git merge-base HEAD main }

# Get all changed files with status
git diff --name-status $base..HEAD | ForEach-Object {
    $parts = $_ -split "`t"
    $status = $parts[0]
    $file = $parts[1]

    $action = switch ($status) {
        "A" { "CREATE" }
        "M" { "MODIFY" }
        "D" { "DELETE" }
        default { "MODIFY" }
    }

    # Get commit timestamp for this file
    $timestamp = git log -1 --format=%aI -- $file
    Write-Output "$timestamp|$action|$file"
}
```

**Bash:**
```bash
base=$(git merge-base HEAD develop 2>/dev/null || git merge-base HEAD main)

git diff --name-status $base..HEAD | while read status file; do
    timestamp=$(git log -1 --format=%aI -- "$file")
    case "$status" in
        A) action="CREATE" ;;
        M) action="MODIFY" ;;
        D) action="DELETE" ;;
        *) action="MODIFY" ;;
    esac
    echo "$timestamp|$action|$file"
done
```

3. **Warn user** that accuracy may be reduced:
```
⚠️ File audit trail (.agent/ops/log/created-files.log) not found.
Using git diff fallback — this identifies changed files but may be less accurate
for determining which files were created by ao-ops vs. user.

Recommend: Enable file logging in ao-implementation for future work.
```

## Invocation

User says:
- "Create a clean branch for PR"
- "Make a branch without .agent and .github changes"
- "Prepare my feature for code review"

## Arguments

| Argument | Description | Default |
|----------|-------------|---------|
| `source_branch` | Feature branch with work | Current branch |
| `new_branch` | Name for clean branch | `{source_branch}-clean` |
| `base_branch` | Branch to restore excluded paths from | Auto-detect |
| `exclusions` | Paths/patterns to exclude | Prompt user |

## Workflow

### 1. Gather Requirements

**If not provided, ask:**

1. **Source branch** (default: current)
2. **New branch name** (default: `{current}-clean`)
3. **Base branch** — try auto-detect first:

> See [selective-git-scripts.md](../../reference/selective-git-scripts.md#1-detect-base-branch) for detection script

4. **Exclusions** — if not specified, prompt user for preset selection

### 2. Check and Generate Audit Trail

> See [selective-git-scripts.md](../../reference/selective-git-scripts.md#2-check-audit-trail-exists) for check script
> See [selective-git-scripts.md](../../reference/selective-git-scripts.md#3-generate-audit-trail-from-git-history) for generation script

**Check if audit trail exists:**

```bash
if [ -f ".agent/ops/log/created-files.log" ]; then
    echo "✅ Audit trail found"
    AUDIT_SOURCE="log"
else
    echo "⚠️ Audit trail missing — using git diff fallback"
    AUDIT_SOURCE="git"
fi
```

**If `.agent/ops/log/created-files.log` is missing:**

1. Find branch point: `git merge-base HEAD {base_branch}`
2. Generate file list from git diff (see Fallback Strategy above)
3. **Present to user for validation** (MANDATORY)
4. Proceed only after user confirms the file list is accurate

**User validation prompt:**
```
📋 Generated file list from git history:

Created:
- src/new_module.py
- tests/test_new_module.py

Modified:
- src/existing.py
- README.md

Is this list accurate? [Y]es / [E]dit / [A]bort
```

### 3. Read Audit Trail

> See [selective-git-scripts.md](../../reference/selective-git-scripts.md#5-read-audit-trail) for script

Extract files created by ao-ops from `.agent/ops/log/created-files.log`.

### 4. Execute (Git-Based)

#### Step 1: Create worktree with new branch

> See [selective-git-scripts.md](../../reference/selective-git-scripts.md#6-create-worktree) for script

```bash
git worktree add -b {new_branch} ../{new_branch} HEAD
cd ../{new_branch}
```

#### Step 2: Restore excluded directories from base branch

> See [selective-git-scripts.md](../../reference/selective-git-scripts.md#7-restore-exclusions-from-base) for script

```bash
git checkout {base_branch} -- .github .agent
```

#### Step 3: Remove NEW files that don't exist in base

> See [selective-git-scripts.md](../../reference/selective-git-scripts.md#8-remove-new-files-not-in-base) for script

For each file in audit trail:
- If exists in base -> restore from base
- If new (not in base) -> `git rm --cached`

#### Step 4: Commit the exclusions

```bash
git add -A
git commit -m "chore: prepare clean branch for PR (exclude ao-ops files)"
```

#### Step 5: Create Exclusion Log

> See [selective-git-scripts.md](../../reference/selective-git-scripts.md#10-create-exclusion-log) for script

Create `.agent/ops/log/selective-branch-{branch}-{timestamp}.log` with metadata and exclusion entries.

### 5. Validate Results (MANDATORY)

> See [selective-git-scripts.md](../../reference/selective-git-scripts.md#9-validation-script) for script

Validation checks:
- All feature files present in clean branch
- No ao-ops files leaked

### 6. Report to User

```
✅ Clean branch created: {new_branch}

Location: {worktree_path}

Excluded:
- .github/ (restored from {base_branch})
- .agent/ops/ (restored from {base_branch})
- {N} files from audit trail

Next steps:
1. Review changes: cd {worktree_path} && git log --oneline {base_branch}..HEAD
2. Push for PR: git push -u origin {new_branch}
3. Cleanup when done: git worktree remove {worktree_path}
```

## Cleanup

> See [selective-git-scripts.md](../../reference/selective-git-scripts.md#11-cleanup) for script

When done with the clean branch:
```bash
git worktree remove ../{new_branch}
git branch -D {new_branch}
```

## Common Exclusion Presets

| Preset | Directories | Files |
|--------|-------------|-------|
| **Clean PR** (Recommended) | .github, .agent | All from audit trail |
| **Feature Only** | .github, .agent, .vscode, docs | *.md at root, audit trail |
| **Minimal** | .agent | None |

## Error Handling

| Error | Solution |
|-------|----------|
| "fatal: not a git repository" | Must run from git repo |
| "error: branch already exists" | Use different name or delete existing |
| "fatal: worktree already exists" | Remove existing worktree first |
| "error: pathspec did not match" | Path doesn't exist in base branch (ok to skip) |

## Related Skills

- `ao-selective-merge` — Update clean branch after feedback
- `ao-git` — General git operations
- `ao-implementation` — Creates files that get logged
