Files
repo_Claude/.claude/commands/git/recovery.md
T

10 KiB
Raw Blame History

Command: git-recovery

Recupera el repositorio de estados inconsistentes causados por worktrees huérfanos, branches bloqueados o conflictos de git. Ejecuta automáticamente cuando se detectan errores git durante operaciones de issues.

Para el usuario

Cuándo usar este comando

  • Cuando hay errores "exit status 128" al crear worktrees
  • Cuando git reporta "worktree already exists"
  • Cuando hay branches que no se pueden eliminar
  • Cuando git worktree list muestra worktrees huérfanos
  • Cuando el orquestador paralelo falla por problemas git
  • Automáticamente: El sistema lo invoca cuando detecta errores git

Sintaxis

/git:recovery [--aggressive]

Parámetros

  • --aggressive (opcional): Fuerza limpieza agresiva incluyendo branches remotas y reset de estado

Ejemplos

Ejemplo 1: Recuperación estándar (recomendado)

/git:recovery

Limpia worktrees huérfanos, verifica estado, sincroniza con remoto.

Ejemplo 2: Recuperación agresiva

/git:recovery --aggressive

Incluye force-prune, eliminación de branches huérfanas, reset de índice.

Para Claude

Precondiciones

Verificar antes de ejecutar:

  • Estamos en un repositorio git válido
  • Hay permisos para modificar .git/
  • No hay operaciones git críticas en progreso (rebase, merge)

Inputs

  • --aggressive (opcional): Modo agresivo de limpieza

Flujo obligatorio

1. Diagnóstico inicial

echo "🔍 Diagnosticando estado del repositorio..."
echo ""

# Verificar que estamos en repo git
if [ ! -d ".git" ]; then
  echo "❌ Error: No estamos en un repositorio git"
  exit 1
fi

# Guardar estado actual
git branch --show-current > /tmp/git-recovery-current-branch.txt
git status --porcelain > /tmp/git-recovery-status.txt

echo "Rama actual: $(cat /tmp/git-recovery-current-branch.txt)"
echo "Cambios pendientes: $(wc -l < /tmp/git-recovery-status.txt) archivos"
echo ""

2. Análisis de problemas

echo "📋 Analizando problemas..."
echo ""

# Listar worktrees (puede fallar si hay huérfanos)
echo "Worktrees actuales:"
git worktree list 2>&1 || echo "  (error listando worktrees - probablemente hay huérfanos)"
echo ""

# Verificar branches locales
echo "Branches locales:"
git branch --list
echo ""

# Verificar branches remotas
echo "Estado remoto:"
git remote -v
git fetch --dry-run 2>&1 || echo "  (problemas con fetch)"
echo ""

3. Limpieza de worktrees huérfanos

echo "🧹 Limpiando worktrees huérfanos..."
echo ""

# Ejecutar prune (elimina referencias a worktrees que ya no existen)
git worktree prune -v 2>&1

# Verificar si aún hay worktrees huérfanos en disco
if [ -d "worktrees" ]; then
  echo ""
  echo "Verificando directorio worktrees/..."

  # Listar directorios en worktrees/
  for worktree_dir in worktrees/issue-*; do
    if [ -d "$worktree_dir" ]; then
      worktree_name=$(basename "$worktree_dir")

      # Verificar si git lo conoce
      if ! git worktree list | grep -q "$worktree_dir"; then
        echo "  ⚠️  Worktree huérfano detectado: $worktree_name"

        # Eliminar directorio huérfano
        rm -rf "$worktree_dir"
        echo "     ✓ Eliminado: $worktree_dir"
      fi
    fi
  done
fi

echo ""
echo "✓ Limpieza de worktrees completada"
echo ""

4. Verificación de branches bloqueados

echo "🔓 Verificando branches bloqueados..."
echo ""

# Listar branches que podrían estar bloqueados
git branch --list 'issue/*' 'quick/*' | while read -r branch; do
  branch=$(echo "$branch" | sed 's/^\* //' | xargs)

  # Verificar si la branch está asociada a un worktree
  if git worktree list | grep -q "$branch"; then
    echo "  ️  Branch activa en worktree: $branch"
  else
    # Branch no está en worktree, podría estar mergeada
    if git branch --merged master | grep -q "$branch"; then
      echo "  ✓ Branch mergeada, puede eliminarse: $branch"
      git branch -d "$branch" 2>&1 || echo "     (no se pudo eliminar automáticamente)"
    else
      echo "  ⚠️  Branch NO mergeada: $branch"
    fi
  fi
done

echo ""

5. Sincronización con remoto

echo "🔄 Sincronizando con remoto..."
echo ""

# Volver a master si no estamos ahí
current_branch=$(git branch --show-current)
if [ "$current_branch" != "master" ]; then
  echo "Cambiando a master desde $current_branch..."
  git checkout master 2>&1 || {
    echo "❌ No se pudo cambiar a master"
    echo "   Quedando en rama: $current_branch"
  }
fi

# Fetch y pull
echo "Actualizando desde origin/master..."
git fetch origin 2>&1
git pull --rebase origin master 2>&1 || {
  echo "⚠️  Problemas al hacer pull, continuando..."
}

echo ""
echo "✓ Sincronización completada"
echo ""

6. Modo agresivo (solo si --aggressive)

if [ "$AGGRESSIVE" = "true" ]; then
  echo "⚡ MODO AGRESIVO ACTIVADO"
  echo ""

  echo "Limpiando branches remotas obsoletas..."
  git remote prune origin -v 2>&1
  echo ""

  echo "Verificando integridad del repositorio..."
  git fsck --full 2>&1 | head -20
  echo ""

  echo "Limpiando objetos no referenciados..."
  git gc --prune=now 2>&1
  echo ""

  echo "Verificando índice..."
  if [ -f ".git/index.lock" ]; then
    echo "  ⚠️  Encontrado index.lock (proceso git interrumpido)"
    rm -f .git/index.lock
    echo "     ✓ Eliminado .git/index.lock"
  fi

  echo ""
  echo "✓ Limpieza agresiva completada"
  echo ""
fi

7. Verificación final

echo "✅ Verificación final..."
echo ""

# Estado limpio
echo "Estado del repositorio:"
git status
echo ""

# Worktrees finales
echo "Worktrees activos:"
git worktree list
echo ""

# Branches locales
echo "Branches locales:"
git branch --list
echo ""

8. Resumen

echo "════════════════════════════════════════════════════════"
echo "RECUPERACIÓN COMPLETADA"
echo "════════════════════════════════════════════════════════"
echo ""

# Comparar estado antes/después
CHANGES_BEFORE=$(wc -l < /tmp/git-recovery-status.txt)
CHANGES_AFTER=$(git status --porcelain | wc -l)

echo "Resumen:"
echo "  Rama actual: $(git branch --show-current)"
echo "  Cambios pendientes: $CHANGES_AFTER (antes: $CHANGES_BEFORE)"
echo "  Worktrees activos: $(git worktree list | grep -v bare | wc -l)"
echo "  Sincronizado con origin: $(git rev-parse HEAD) = $(git rev-parse origin/master 2>/dev/null || echo 'N/A')"
echo ""

if [ "$AGGRESSIVE" = "true" ]; then
  echo "Modo agresivo aplicado: ✓"
  echo ""
fi

echo "Próximos pasos:"
echo "  - Verifica que master esté actualizado: git log --oneline -5"
echo "  - Reintenta la operación que falló"
echo "  - Si persisten errores, reporta el problema"
echo ""

# Limpiar archivos temporales
rm -f /tmp/git-recovery-*.txt

Detección automática de errores git

El orquestador Go debe detectar estos patrones de error:

Patrones de error que activan recovery:

  • exit status 128 (error genérico de git)
  • worktree .* already exists
  • reference is not a tree
  • cannot lock ref
  • index.lock
  • fatal: not a git repository

Flujo de auto-recovery:

  1. Orquestador detecta error git
  2. Pausa ejecución del grupo actual
  3. Ejecuta claude -p /git:recovery automáticamente
  4. Si recovery tiene éxito (exit code 0), reintenta la operación
  5. Si recovery falla, aborta con error descriptivo

Verificación final

# Verificar que el repo quedó en estado válido
git status --porcelain
git worktree list

# Exit code 0 si todo OK, 1 si hay problemas
if [ $? -eq 0 ]; then
  exit 0
else
  echo "❌ El repositorio sigue con problemas"
  exit 1
fi

Convenciones

  • No destructivo por defecto: Solo limpia worktrees huérfanos y branches mergeadas
  • Modo agresivo bajo demanda: Solo con flag explícito
  • Siempre sincroniza con remoto: Garantiza consistencia
  • Preserva cambios locales: No hace reset hard sin --aggressive
  • Logs detallados: Reporta cada acción para debugging

Troubleshooting

Error: "cannot remove worktree"

Causa: Proceso usando archivos del worktree

Solución:

# Verificar procesos
lsof +D worktrees/ 2>/dev/null

# Forzar eliminación con --aggressive
/git:recovery --aggressive

Error: "index.lock exists"

Causa: Operación git previa interrumpida

Solución: Automáticamente manejado en modo estándar. Si persiste:

rm -f .git/index.lock
/git:recovery

Warning: "branch no mergeada"

Causa: Branch contiene commits no integrados a master

Solución: Verificar manualmente si es seguro eliminarla:

git log master..branch-name
git branch -D branch-name  # Solo si estás seguro

Reglas críticas

  • NUNCA hacer git reset --hard sin --aggressive - puede perder cambios
  • SIEMPRE hacer backup del estado antes de recovery agresivo
  • NUNCA eliminar branches no mergeadas automáticamente
  • SIEMPRE sincronizar con remoto después de limpieza
  • SIEMPRE verificar que quedó en estado válido
  • LOGS completos - reportar cada acción para auditoría

Integración con orquestador

El orquestador Go debe:

  1. Capturar stderr de comandos git
  2. Detectar patrones de error conocidos
  3. Invocar recovery automáticamente:
    if isGitError(err) {
        log.Warn("Error git detectado, ejecutando recovery...")
        if err := executeRecovery(); err != nil {
            return fmt.Errorf("recovery falló: %w", err)
        }
        // Reintentar operación original
        return retryOperation()
    }
    
  4. Limitar reintentos a 1 vez por operación
  5. Abortar si recovery falla

Ejemplos de uso automático

Escenario 1: Error al crear worktree

[ERROR] crear worktree: exit status 128
[INFO]  Detectado error git, ejecutando recovery...
[INFO]  ✓ Recovery completado
[INFO]  Reintentando crear worktree...
[SUCCESS] ✓ Worktree creado exitosamente

Escenario 2: Recovery falla

[ERROR] crear worktree: exit status 128
[INFO]  Detectado error git, ejecutando recovery...
[ERROR] Recovery falló: problemas persistentes
[ABORT] Abortando ejecución del grupo