name: agent-ops-selective-copy description: "Create clean git branches from feature work, excluding agent-ops files. Use for PR preparation." license: MIT compatibility: [opencode, claude, cursor]
metadata: category: git related: [agent-ops-interview, agent-ops-git]
Selective Copy — 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/, .github/)" |
If ANY of these are ambiguous:
- Stop
- Ask ONE question at a time
- Wait for explicit confirmation
- Only proceed when ALL inputs are confirmed
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 file-created.log MUST exist before proceeding. This ensures we know which files to exclude.
If .agent/log/created-files.log does not exist:
- Generate it from git history (see Generation Procedure below)
- Present to user for validation
- Only proceed after user confirms the list
This prevents accidental inclusion of agent-ops files in the clean branch.
Invocation
User says something like:
- "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:
- Source branch (default: current)
- New branch name (default:
{current}-clean) - Base branch — try auto-detect first:
# PowerShell: Find merge-base with main or develop
$mainBase = git merge-base HEAD main 2>$null
$devBase = git merge-base HEAD develop 2>$null
if ($mainBase) { $baseBranch = "main" }
elseif ($devBase) { $baseBranch = "develop" }
else {
# Ask user
Write-Host "Could not auto-detect base branch. Which branch was this feature branched from?"
}
# Bash: Find merge-base
main_base=$(git merge-base HEAD main 2>/dev/null)
dev_base=$(git merge-base HEAD develop 2>/dev/null)
if [ -n "$main_base" ]; then
base_branch="main"
elif [ -n "$dev_base" ]; then
base_branch="develop"
else
echo "Could not auto-detect base branch. Which branch was this feature branched from?"
fi
- Exclusions — if not specified, prompt:
Would you like to exclude agent-ops files? This includes:
- `.agent/` directory
- `.github/skills/`, `.github/prompts/`, `.github/agents/`
Additionally, agent-ops created these files outside .agent/:
{list from .agent/log/created-files.log}
[1] Exclude all agent-ops files (recommended)
[2] Exclude only .agent/ and .github/
[3] Let me specify custom paths
[4] Don't exclude anything
2. Check and Generate Audit Trail (MANDATORY)
Before proceeding, verify .agent/log/created-files.log exists.
# PowerShell
$logPath = ".agent/log/created-files.log"
if (-not (Test-Path $logPath)) {
Write-Host "⚠️ File audit trail not found: $logPath" -ForegroundColor Yellow
Write-Host "Generating from git history..." -ForegroundColor Cyan
# Proceed to generation
} else {
Write-Host "✓ Audit trail found: $logPath" -ForegroundColor Green
# Skip to step 3
}
# Bash
log_path=".agent/log/created-files.log"
if [ ! -f "$log_path" ]; then
echo "⚠️ File audit trail not found: $log_path"
echo "Generating from git history..."
# Proceed to generation
else
echo "✓ Audit trail found: $log_path"
# Skip to step 3
fi
If log is missing, generate it:
Generation Procedure
- Find the branch point (where feature diverged from base):
# PowerShell
$baseBranch = "develop" # or auto-detected
$branchPoint = git merge-base HEAD $baseBranch
Write-Host "Branch point: $branchPoint"
# Bash
base_branch="develop"
branch_point=$(git merge-base HEAD "$base_branch")
echo "Branch point: $branch_point"
- List files added since branch point (excluding .agent/ and .github/):
# PowerShell
$addedFiles = git diff --name-status --diff-filter=A $branchPoint HEAD |
ForEach-Object { ($_ -split "\t")[1] } |
Where-Object {
$_ -notmatch "^\.agent/" -and
$_ -notmatch "^\.github/skills/" -and
$_ -notmatch "^\.github/prompts/" -and
$_ -notmatch "^\.github/agents/"
}
Write-Host "`nFiles added since branch point:" -ForegroundColor Cyan
$addedFiles | ForEach-Object { Write-Host " CREATE $_" }
Write-Host "`nTotal: $($addedFiles.Count) files"
# Bash
added_files=$(git diff --name-status --diff-filter=A "$branch_point" HEAD |
cut -f2 |
grep -v "^\.agent/" |
grep -v "^\.github/skills/" |
grep -v "^\.github/prompts/" |
grep -v "^\.github/agents/")
echo ""
echo "Files added since branch point:"
echo "$added_files" | while read -r file; do
[ -n "$file" ] && echo " CREATE $file"
done
echo ""
echo "Total: $(echo "$added_files" | grep -c .)"
- Present to user for validation (MANDATORY):
📋 Generated file list from git history:
CREATE src/utils/helper.py
CREATE tests/test_helper.py
CREATE docs/PLANNING.md
Total: 3 files
⚠️ Please review this list carefully.
These files will be EXCLUDED from the clean branch.
Missing files may leak into PR. Extra files may be wrongly excluded.
Options:
[1] Approve and continue
[2] Edit list (will open in editor)
[3] Abort
- Save after user approval:
# PowerShell (only after user confirms)
$logDir = ".agent/log"
if (-not (Test-Path $logDir)) {
New-Item -ItemType Directory -Path $logDir -Force | Out-Null
}
$timestamp = Get-Date -Format "yyyy-MM-ddTHH:mm:ssZ"
# Write header
@"
# Agent-Ops File Creation Audit Trail
# Generated from git history on $timestamp
# Branch point: $branchPoint (from $baseBranch)
# User validated: YES
# --- Log entries below this line ---
"@ | Out-File -FilePath $logPath -Encoding utf8
# Write entries
foreach ($file in $addedFiles) {
Add-Content -Path $logPath -Value "$timestamp CREATE $file"
}
Write-Host "✓ Audit trail saved: $logPath" -ForegroundColor Green
# Bash (only after user confirms)
log_dir=".agent/log"
mkdir -p "$log_dir"
timestamp=$(date -u +%Y-%m-%dT%H:%M:%SZ)
# Write header
cat > "$log_path" << EOF
# Agent-Ops File Creation Audit Trail
# Generated from git history on $timestamp
# Branch point: $branch_point (from $base_branch)
# User validated: YES
# --- Log entries below this line ---
EOF
# Write entries
echo "$added_files" | while read -r file; do
[ -n "$file" ] && echo "$timestamp CREATE $file" >> "$log_path"
done
echo "✓ Audit trail saved: $log_path"
3. Read Audit Trail
Check .agent/log/created-files.log for files created outside .agent/:
# PowerShell
$logPath = ".agent/log/created-files.log"
$createdFiles = Get-Content $logPath |
Where-Object { $_ -match "^\d{4}-\d{2}-\d{2}" } |
ForEach-Object {
$parts = $_ -split " ", 3
[PSCustomObject]@{
Timestamp = $parts[0]
Action = $parts[1]
Path = $parts[2]
}
} |
Where-Object { $_.Action -eq "CREATE" } |
Select-Object -ExpandProperty Path
Write-Host "Files created by agent-ops:"
$createdFiles | ForEach-Object { Write-Host " - $_" }
# Bash
echo "Files created by agent-ops:"
grep "^[0-9]" .agent/log/created-files.log |
awk '$2 == "CREATE" { print " - " $3 }'
4. Execute (Git-Based)
Step 1: Create worktree with new branch
# PowerShell
$sourceBranch = git branch --show-current
$newBranch = "$sourceBranch-clean"
$worktreePath = "../$newBranch"
git worktree add -b $newBranch $worktreePath HEAD
Set-Location $worktreePath
# Bash
source_branch=$(git branch --show-current)
new_branch="${source_branch}-clean"
worktree_path="../${new_branch}"
git worktree add -b "$new_branch" "$worktree_path" HEAD
cd "$worktree_path"
Step 2: Restore excluded directories from base branch
# PowerShell
$baseBranch = "develop" # or detected/user-provided
$excludeDirs = @(".github", ".agent")
foreach ($dir in $excludeDirs) {
git checkout $baseBranch -- $dir 2>$null
if ($LASTEXITCODE -eq 0) {
Write-Host "Restored $dir from $baseBranch"
} else {
Write-Host "$dir doesn't exist in $baseBranch (new directory)"
}
}
# Bash
base_branch="develop"
exclude_dirs=(".github" ".agent")
for dir in "${exclude_dirs[@]}"; do
if git checkout "$base_branch" -- "$dir" 2>/dev/null; then
echo "Restored $dir from $base_branch"
else
echo "$dir doesn't exist in $base_branch (new directory)"
fi
done
Step 3: Remove NEW files that don't exist in base
For files logged in audit trail that are new (not in base branch):
# PowerShell
foreach ($file in $createdFiles) {
# Check if file exists in base branch
$existsInBase = git ls-tree -r $baseBranch --name-only | Where-Object { $_ -eq $file }
if (-not $existsInBase) {
# File is new, remove from git tracking
git rm --cached $file 2>$null
Write-Host "Removed new file from tracking: $file"
} else {
# File exists in base, restore it
git checkout $baseBranch -- $file 2>$null
Write-Host "Restored $file from $baseBranch"
}
}
# Bash
for file in "${created_files[@]}"; do
if git ls-tree -r "$base_branch" --name-only | grep -q "^${file}$"; then
# File exists in base, restore it
git checkout "$base_branch" -- "$file" 2>/dev/null
echo "Restored $file from $base_branch"
else
# File is new, remove from git tracking
git rm --cached "$file" 2>/dev/null
echo "Removed new file from tracking: $file"
fi
done
Step 4: Commit the exclusions
# PowerShell
git add -A
git commit -m "chore: prepare clean branch for PR (exclude agent-ops files)"
# Bash
git add -A
git commit -m "chore: prepare clean branch for PR (exclude agent-ops files)"
Step 5: Create Exclusion Log
Create a log file for selective-merge to use later:
# PowerShell
$timestamp = Get-Date -Format "yyyy-MM-dd-HHmmss"
$logFile = ".agent/log/selective-copy-$newBranch-$timestamp.log"
$cleanBranchHash = git rev-parse HEAD
$sourceBranchHash = git rev-parse $sourceBranch
# Create log directory if needed
New-Item -ItemType Directory -Path ".agent/log" -Force | Out-Null
# Write log header
@"
# Selective Copy Exclusion Log
# Generated: $(Get-Date -Format "yyyy-MM-ddTHH:mm:ssK")
# Source Branch: $sourceBranch ($sourceBranchHash)
# Clean Branch: $newBranch ($cleanBranchHash)
# Base Branch: $baseBranch
# Excluded Paths: $($excludeDirs -join ", ")
# Format: {ACTION} {path}
# RESTORE = restored from base branch
# REMOVE = removed from tracking (new file not in base)
"@ | Out-File -FilePath $logFile -Encoding utf8
# Log each excluded directory
foreach ($dir in $excludeDirs) {
Add-Content -Path $logFile -Value "RESTORE $dir"
}
# Log removed files from audit trail
foreach ($file in $createdFiles) {
$existsInBase = git ls-tree -r $baseBranch --name-only | Where-Object { $_ -eq $file }
if (-not $existsInBase) {
Add-Content -Path $logFile -Value "REMOVE $file"
} else {
Add-Content -Path $logFile -Value "RESTORE $file"
}
}
Write-Host "Exclusion log created: $logFile"
# Bash
timestamp=$(date +"%Y-%m-%d-%H%M%S")
log_file=".agent/log/selective-copy-${new_branch}-${timestamp}.log"
clean_branch_hash=$(git rev-parse HEAD)
source_branch_hash=$(git rev-parse "$source_branch")
# Create log directory if needed
mkdir -p ".agent/log"
# Write log header
cat > "$log_file" << EOF
# Selective Copy Exclusion Log
# Generated: $(date -Iseconds)
# Source Branch: $source_branch ($source_branch_hash)
# Clean Branch: $new_branch ($clean_branch_hash)
# Base Branch: $base_branch
# Excluded Paths: ${exclude_dirs[*]}
# Format: {ACTION} {path}
# RESTORE = restored from base branch
# REMOVE = removed from tracking (new file not in base)
EOF
# Log each excluded directory
for dir in "${exclude_dirs[@]}"; do
echo "RESTORE $dir" >> "$log_file"
done
# Log removed files from audit trail
for file in "${created_files[@]}"; do
if git ls-tree -r "$base_branch" --name-only | grep -q "^${file}$"; then
echo "RESTORE $file" >> "$log_file"
else
echo "REMOVE $file" >> "$log_file"
fi
done
echo "Exclusion log created: $log_file"
5. Verify
# PowerShell
Write-Host "`n=== Verification ===" -ForegroundColor Cyan
# Check status
git status
# Compare with base branch
Write-Host "`nChanges compared to ${baseBranch}:"
git diff $baseBranch --stat
# Verify excluded paths match base
Write-Host "`nVerifying exclusions:"
foreach ($dir in $excludeDirs) {
$diff = git diff $baseBranch -- $dir
if ([string]::IsNullOrEmpty($diff)) {
Write-Host " $dir matches $baseBranch ✓" -ForegroundColor Green
} else {
Write-Host " $dir has differences from $baseBranch" -ForegroundColor Yellow
}
}
# Bash
echo ""
echo "=== Verification ==="
# Check status
git status
# Compare with base branch
echo ""
echo "Changes compared to ${base_branch}:"
git diff "$base_branch" --stat
# Verify excluded paths match base
echo ""
echo "Verifying exclusions:"
for dir in "${exclude_dirs[@]}"; do
if [ -z "$(git diff "$base_branch" -- "$dir")" ]; then
echo " $dir matches $base_branch ✓"
else
echo " $dir has differences from $base_branch"
fi
done
6. Validate Results (MANDATORY)
After creating the clean branch, validate using created-files.log as source of truth:
# PowerShell - Validation Script
Write-Host "`n=== Validation ===" -ForegroundColor Cyan
$validationPassed = $true
$issues = @()
# 1. Check created files exist in clean branch (they should be the feature work)
$createdFilesLog = ".agent/log/created-files.log"
if (Test-Path $createdFilesLog) {
Write-Host "`nChecking feature files are present in clean branch..."
$createdFiles = Get-Content $createdFilesLog |
Where-Object { $_ -match "^\d{4}-\d{2}-\d{2}" -and $_ -match "CREATE" } |
ForEach-Object { ($_ -split " ", 3)[2] } |
Where-Object {
$_ -notmatch "^\.agent/" -and
$_ -notmatch "^\.github/skills/" -and
$_ -notmatch "^\.github/prompts/" -and
$_ -notmatch "^\.github/agents/"
}
foreach ($file in $createdFiles) {
$existsInClean = git ls-tree -r HEAD --name-only | Where-Object { $_ -eq $file }
if ($existsInClean) {
Write-Host " ✓ $file" -ForegroundColor Green
} else {
Write-Host " ✗ MISSING: $file" -ForegroundColor Red
$issues += "MISSING: $file (should be in clean branch)"
$validationPassed = $false
}
}
}
# 2. Check NO agent-ops files leaked into clean branch
Write-Host "`nChecking for leaked agent-ops files..."
$leakedFiles = git ls-tree -r HEAD --name-only | Where-Object {
$_ -match "^\.agent/" -or
$_ -match "^\.github/skills/agent-ops-" -or
$_ -match "^\.github/prompts/agent-ops-" -or
$_ -match "^\.github/agents/agent-ops-"
}
if ($leakedFiles) {
foreach ($leaked in $leakedFiles) {
Write-Host " ✗ LEAKED: $leaked" -ForegroundColor Red
$issues += "LEAKED: $leaked (should NOT be in clean branch)"
}
$validationPassed = $false
} else {
Write-Host " ✓ No agent-ops files found" -ForegroundColor Green
}
# 3. Report
Write-Host "`n=== Validation Result ===" -ForegroundColor Cyan
if ($validationPassed) {
Write-Host "✅ PASSED" -ForegroundColor Green
Write-Host " - All feature files present in clean branch"
Write-Host " - No agent-ops files leaked"
Write-Host " - Clean branch ready for PR"
} else {
Write-Host "❌ FAILED" -ForegroundColor Red
foreach ($issue in $issues) {
Write-Host " - $issue" -ForegroundColor Yellow
}
Write-Host "`nPlease review and fix before pushing."
}
# Bash - Validation Script
echo ""
echo "=== Validation ==="
validation_passed=true
issues=()
# 1. Check created files exist in clean branch
created_files_log=".agent/log/created-files.log"
if [ -f "$created_files_log" ]; then
echo ""
echo "Checking feature files are present in clean branch..."
while IFS= read -r line; do
if [[ "$line" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}.*CREATE ]]; then
file=$(echo "$line" | awk '{print $3}')
# Skip agent-ops files
if [[ ! "$file" =~ ^\.agent/ && ! "$file" =~ ^\.github/skills/ && ! "$file" =~ ^\.github/prompts/ && ! "$file" =~ ^\.github/agents/ ]]; then
if git ls-tree -r HEAD --name-only | grep -q "^${file}$"; then
echo " ✓ $file"
else
echo " ✗ MISSING: $file"
issues+=("MISSING: $file (should be in clean branch)")
validation_passed=false
fi
fi
fi
done < "$created_files_log"
fi
# 2. Check NO agent-ops files leaked
echo ""
echo "Checking for leaked agent-ops files..."
leaked_files=$(git ls-tree -r HEAD --name-only | grep -E "^\.agent/|^\.github/skills/agent-ops-|^\.github/prompts/agent-ops-|^\.github/agents/agent-ops-")
if [ -n "$leaked_files" ]; then
while IFS= read -r leaked; do
echo " ✗ LEAKED: $leaked"
issues+=("LEAKED: $leaked (should NOT be in clean branch)")
done <<< "$leaked_files"
validation_passed=false
else
echo " ✓ No agent-ops files found"
fi
# 3. Report
echo ""
echo "=== Validation Result ==="
if [ "$validation_passed" = true ]; then
echo "✅ PASSED"
echo " - All feature files present in clean branch"
echo " - No agent-ops files leaked"
echo " - Clean branch ready for PR"
else
echo "❌ FAILED"
for issue in "${issues[@]}"; do
echo " - $issue"
done
echo ""
echo "Please review and fix before pushing."
fi
7. Report to User
✅ Clean branch created: {new_branch}
Location: {worktree_path}
Excluded:
- .github/ (restored from {base_branch})
- .agent/ (restored from {base_branch})
- {N} files from audit trail
Changes from {base_branch}:
{git diff --stat output}
Validation: PASSED ✓
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
When done with the clean branch:
# PowerShell
# Return to original repo
Set-Location ../{original-repo}
# Remove worktree (keeps branch)
git worktree remove ../{new_branch}
# Delete branch if no longer needed
git branch -D {new_branch}
# Bash
# Return to original repo
cd ../{original-repo}
# Remove worktree (keeps branch)
git worktree remove "../${new_branch}"
# Delete branch if no longer needed
git branch -D "${new_branch}"
Common Exclusion Presets
Clean PR (Recommended)
Directories: .github, .agent
Files: All from audit trail
Feature Only
Directories: .github, .agent, .vscode, docs
Files: *.md at root, audit trail files
Minimal (Agent Core Only)
Directories: .agent
Files: 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
agent-ops-git— General git operationsagent-ops-implementation— Creates files that get loggedagent-ops-validation— Run before creating clean branch