# Selective Git Operations — Shell Scripts

> Shared shell scripts for `ao-selective-branch` and `ao-selective-merge` skills.

---

## 1. Detect Base Branch

```powershell
# PowerShell
$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 { Write-Host "Could not auto-detect base branch." }
```

```bash
# Bash
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."
fi
```

---

## 2. Check Audit Trail Exists

```powershell
# PowerShell
$logPath = ".agent/ops/log/created-files.log"
if (-not (Test-Path $logPath)) {
    Write-Host "⚠️ File audit trail not found: $logPath" -ForegroundColor Yellow
    # Proceed to generation
} else {
    Write-Host "✓ Audit trail found: $logPath" -ForegroundColor Green
}
```

```bash
# Bash
log_path=".agent/ops/log/created-files.log"
if [ ! -f "$log_path" ]; then
    echo "⚠️ File audit trail not found: $log_path"
else
    echo "✓ Audit trail found: $log_path"
fi
```

---

## 3. Generate Audit Trail from Git History

```powershell
# PowerShell
$branchPoint = git merge-base HEAD $baseBranch
$addedFiles = git diff --name-status --diff-filter=A $branchPoint HEAD |
    ForEach-Object { ($_ -split "\t")[1] } |
    Where-Object { 
        $_ -notmatch "^\.agent/ops/" -and 
        $_ -notmatch "^\.ao/skills/" -and 
        $_ -notmatch "^\.github/prompts/" -and 
        $_ -notmatch "^\.github/agents/"
    }

Write-Host "Files added since branch point:"
$addedFiles | ForEach-Object { Write-Host "  CREATE $_" }
```

```bash
# Bash
branch_point=$(git merge-base HEAD "$base_branch")
added_files=$(git diff --name-status --diff-filter=A "$branch_point" HEAD | 
    cut -f2 | grep -v "^\.agent/ops/" | grep -v "^\.ao/skills/" | 
    grep -v "^\.github/prompts/" | grep -v "^\.github/agents/")

echo "Files added since branch point:"
echo "$added_files" | while read -r file; do
    [ -n "$file" ] && echo "  CREATE $file"
done
```

---

## 4. Save Audit Trail

```powershell
# PowerShell
$logDir = ".agent/ops/log"
if (-not (Test-Path $logDir)) { New-Item -ItemType Directory -Path $logDir -Force | Out-Null }

$timestamp = Get-Date -Format "yyyy-MM-ddTHH:mm:ssZ"
$logPath = ".agent/ops/log/created-files.log"

@"
# ao-Ops File Creation Audit Trail
# Generated from git history on $timestamp
# Branch point: $branchPoint (from $baseBranch)
# User validated: YES
"@ | Out-File -FilePath $logPath -Encoding utf8

foreach ($file in $addedFiles) {
    Add-Content -Path $logPath -Value "$timestamp CREATE $file"
}
```

```bash
# Bash
mkdir -p ".agent/ops/log"
timestamp=$(date -u +%Y-%m-%dT%H:%M:%SZ)
log_path=".agent/ops/log/created-files.log"

cat > "$log_path" << EOF
# ao-Ops File Creation Audit Trail
# Generated from git history on $timestamp
# Branch point: $branch_point (from $base_branch)
# User validated: YES
EOF

echo "$added_files" | while read -r file; do
    [ -n "$file" ] && echo "$timestamp CREATE $file" >> "$log_path"
done
```

---

## 5. Read Audit Trail

```powershell
# PowerShell
$createdFiles = Get-Content ".agent/ops/log/created-files.log" | 
    Where-Object { $_ -match "^\d{4}-\d{2}-\d{2}" -and $_ -match "CREATE" } |
    ForEach-Object { ($_ -split " ", 3)[2] }
```

```bash
# Bash
created_files=$(grep "^[0-9]" .agent/ops/log/created-files.log | 
    awk '$2 == "CREATE" { print $3 }')
```

---

## 6. Create Worktree

```powershell
# PowerShell
$sourceBranch = git branch --show-current
$newBranch = "$sourceBranch-clean"
$worktreePath = "../$newBranch"

git worktree add -b $newBranch $worktreePath HEAD
Set-Location $worktreePath
```

```bash
# 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"
```

---

## 7. Restore Exclusions from Base

```powershell
# PowerShell
$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" }
}
```

```bash
# Bash
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"
    fi
done
```

---

## 8. Remove New Files Not in Base

```powershell
# PowerShell
foreach ($file in $createdFiles) {
    $existsInBase = git ls-tree -r $baseBranch --name-only | Where-Object { $_ -eq $file }
    
    if (-not $existsInBase) {
        git rm --cached $file 2>$null
        Write-Host "Removed from tracking: $file"
    } else {
        git checkout $baseBranch -- $file 2>$null
        Write-Host "Restored $file from $baseBranch"
    }
}
```

```bash
# Bash
for file in "${created_files[@]}"; do
    if git ls-tree -r "$base_branch" --name-only | grep -q "^${file}$"; then
        git checkout "$base_branch" -- "$file" 2>/dev/null
        echo "Restored $file from $base_branch"
    else
        git rm --cached "$file" 2>/dev/null
        echo "Removed from tracking: $file"
    fi
done
```

---

## 9. Validation Script

```powershell
# PowerShell - Validate clean branch
$validationPassed = $true
$issues = @()

# Check feature files present (non-agent files from audit trail)
$createdFilesLog = ".agent/ops/log/created-files.log"
if (Test-Path $createdFilesLog) {
    $featureFiles = Get-Content $createdFilesLog | 
        Where-Object { $_ -match "^\d{4}-\d{2}-\d{2}" -and $_ -match "CREATE" } |
        ForEach-Object { ($_ -split " ", 3)[2] } |
        Where-Object { 
            $_ -notmatch "^\.agent/ops/" -and $_ -notmatch "^\.ao/skills/" -and
            $_ -notmatch "^\.github/prompts/" -and $_ -notmatch "^\.github/agents/"
        }
    
    foreach ($file in $featureFiles) {
        $existsInClean = git ls-tree -r HEAD --name-only | Where-Object { $_ -eq $file }
        if (-not $existsInClean) {
            $issues += "MISSING: $file"
            $validationPassed = $false
        }
    }
}

# Check NO ao-ops files leaked
$leakedFiles = git ls-tree -r HEAD --name-only | Where-Object {
    $_ -match "^\.agent/ops/" -or $_ -match "^\.ao/skills/ao-" -or
    $_ -match "^\.github/prompts/ao-" -or $_ -match "^\.github/agents/ao-"
}
if ($leakedFiles) { $validationPassed = $false; $issues += $leakedFiles }

if ($validationPassed) { Write-Host "✅ PASSED" -ForegroundColor Green }
else { Write-Host "❌ FAILED" -ForegroundColor Red; $issues | ForEach-Object { Write-Host "  - $_" } }
```

```bash
# Bash - Validate clean branch
validation_passed=true
issues=()

# Check feature files present
created_files_log=".agent/ops/log/created-files.log"
if [ -f "$created_files_log" ]; then
    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}')
            if [[ ! "$file" =~ ^\.agent/ops/ && ! "$file" =~ ^\.ao/skills/ && 
                  ! "$file" =~ ^\.github/prompts/ && ! "$file" =~ ^\.github/agents/ ]]; then
                if ! git ls-tree -r HEAD --name-only | grep -q "^${file}$"; then
                    issues+=("MISSING: $file")
                    validation_passed=false
                fi
            fi
        fi
    done < "$created_files_log"
fi

# Check NO ao-ops files leaked
leaked=$(git ls-tree -r HEAD --name-only | grep -E "^\.agent/ops/|^\.ao/skills/ao-")
if [ -n "$leaked" ]; then validation_passed=false; issues+=("$leaked"); fi

if [ "$validation_passed" = true ]; then echo "✅ PASSED"
else echo "❌ FAILED"; for i in "${issues[@]}"; do echo "  - $i"; done; fi
```

---

## 10. Create Exclusion Log

```powershell
# PowerShell
$timestamp = Get-Date -Format "yyyy-MM-dd-HHmmss"
$logFile = ".agent/ops/log/selective-branch-$newBranch-$timestamp.log"

@"
# Selective Branch Exclusion Log
# Generated: $(Get-Date -Format "yyyy-MM-ddTHH:mm:ssK")
# Source Branch: $sourceBranch
# Clean Branch: $newBranch
# Base Branch: $baseBranch
"@ | Out-File -FilePath $logFile -Encoding utf8

foreach ($dir in $excludeDirs) { Add-Content -Path $logFile -Value "RESTORE $dir" }
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" }
}
```

```bash
# Bash
timestamp=$(date +"%Y-%m-%d-%H%M%S")
log_file=".agent/ops/log/selective-branch-${new_branch}-${timestamp}.log"

cat > "$log_file" << EOF
# Selective Branch Exclusion Log
# Generated: $(date -Iseconds)
# Source Branch: $source_branch
# Clean Branch: $new_branch
# Base Branch: $base_branch
EOF

for dir in "${exclude_dirs[@]}"; do echo "RESTORE $dir" >> "$log_file"; done
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
```

---

## 11. Cleanup

```powershell
# PowerShell
Set-Location "../{original-repo}"
git worktree remove "../$newBranch"
git branch -D $newBranch  # Optional: delete branch
```

```bash
# Bash
cd "../{original-repo}"
git worktree remove "../${new_branch}"
git branch -D "${new_branch}"  # Optional: delete branch
```
