Hacktoberfest 2026: los issues que los mantenedores marcaron para octubre, abiertos y aptos para principiantes. Explorar issues de Hacktoberfest

feat(prune): `--apply` — safe, worktree-aware branch/worktree removal

Abierto
#3 0 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
5/5
Tiempo estimado
Más de una semana
Aptitud para principiantes
35/100
Tipo de issue
Nueva funcionalidad
Claridad
Bien especificado
Estado de actividad
Tranquilo
Stack tecnológico
git, github, go

Línea de trabajo

Comienza con la tarea seleccionada y ordenada por dependencias, empezando por report/guard.go y report/guard_test.go para los tipos Guard puros y las pruebas tabulares. Lee los archivos de paquete referenciados y ejecuta primero el comando de pruebas de Go indicado en la tarea. Se considera terminado cuando se cumplen los criterios de aceptación de la tarea sin cambiar el valor predeterminado de solo lectura; la funcionalidad completa también requiere la integración con cmd/prune.go, pruebas de extremo a extremo y actualizaciones de README/help.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

Summary

skiffs prune today classifies local branches read-only. This adds an opt-in executor,
skiffs prune --apply, that removes integrated/merged branches and the worktrees holding
them — behind a durability guard that never destroys unique work. Read-only stays the default
(a plan / apply split).

Design

Durability guard — block removal if any of:

  1. Working tree not clean — untracked / modified / staged files.
  2. Un-PR'd commit — a commit in default..branch that is not an ancestor of the default
    branch, not patch-equivalent to one already in default (rebase-&-merge, detected via
    git cherry), and not covered by a MERGED PR (squash-&-merge). A CLOSED-unmerged
    PR does not make a branch safe.
  3. Precious ignored content — gitignored-but-present files that a plain git worktree remove would silently destroy. Opted in via --anti-gitignore <path> (file of verbatim
    .gitignore keys) or --no-ignore (blanket: every ignored+present file is precious).

Removal routing (per --git-common-dir):

  • default → native git worktree remove + git branch -D
  • worktrunk-managed repo (.config/wt.toml present or any worktrunk.* key in
    .git/config) → delegate to wt remove (preserves its pre-remove hooks)
  • worktrunk-managed but wt not on PATH → skip + report, never native-fallback
    (fail-closed)

Interaction:

  • read-only by default (bare skiffs prune = the report / "plan")
  • --apply → interactive [y/N/a/q] (Enter=skip, a=all, q=quit); -y/--yes = all
  • --apply refuses when the scan spans more than one --git-common-dir (single-repo
    safety boundary; the primary + all its worktrees still count as one repo)
  • the per-branch verdict is additive to the existing PruneResult JSON —
    safeToDelete/needsReview unchanged

Tasks

Dependency-ordered. T1 unblocks the parallel block T2–T5. Each task ≤ ~5 files, test-first.

  • T1 — Guard verdict types + pure Guard()

    • Acceptance: report/guard.go defines Verdict{Branch, Blocks []BlockReason, Route},
      BlockReason (DirtyWorktree|UnPushedCommits|PreciousIgnored), Route
      (NativeGit|WorktrunkDelegate|SkipWtUnavailable), BranchState, GuardConfig.
      Guard(BranchState, GuardConfig) Verdict; Removable == len(Blocks)==0. Additive —
      PruneResult slices untouched.
    • Verify: go test ./report/ — table tests: each block reason alone, combined, clean case.
    • Files: report/guard.go, report/guard_test.go.
  • T2 — gh: MERGED-only signal

    • Acceptance: internal/gh adds MergedPRBranches(ctx, dir, limit) (map[string]bool, error)
      filtering state == MERGED only. Existing MergedClosedPRBranches unchanged.
    • Verify: go test ./internal/gh/ — fixture asserts CLOSED excluded, MERGED included.
    • Files: internal/gh/gh.go, internal/gh/gh_test.go.
  • T3 — git: durability collectors

    • Acceptance: WorktreeDirty(dir) (bool, FileStatus) (reuse GetState);
      UnDurableCommits(ctx, dir, defaultRef, branch string, mergedPR bool) ([]string, error)
      combining merge-base --is-ancestor, git cherry defaultRef branch (+ = candidate,
      - = upstream), and the MERGED-PR cover; ignores empty commits and in-range merges.
    • Verify: go test ./internal/git/ — t.TempDir() repos for merge-commit, rebase-&-merge,
      squash (+MERGED), and CLOSED-unmerged; assert removable vs held per the matrix.
    • Files: internal/git/prune.go, internal/git/prune_test.go.
  • T4 — internal/ignore: .anti-gitignore

    • Acceptance: new package. Parse(path) ([]string, error) (non-empty, non-# verbatim
      keys); PreciousPresent(ctx, dir string, keys []string, blanket bool) ([]string, error) =
      ignored+present files (git ls-files --others --ignored --exclude-standard) matched by a
      listed key (verbatim, via doublestar), or all when blanket. Reports per-key match count.
    • Verify: go test ./internal/ignore/ — temp repo with a gitignored dir + noise; scoped key
      matches only its dir, blanket matches all, a typo'd key → 0 (surfaced, not silent).
    • Files: internal/ignore/ignore.go, internal/ignore/ignore_test.go.
  • T5 — internal/worktrunk: detect + route

    • Acceptance: new package. IsManaged(ctx, dir) bool (.config/wt.toml present or
      git config --get-regexp '^worktrunk\.' non-empty). Available() bool
      (exec.LookPath("wt")). Route(managed, available bool) report.Route:
      managed+avail→WorktrunkDelegate; managed+!avail→SkipWtUnavailable; else→NativeGit.
    • Verify: go test ./internal/worktrunk/ — temp repos with/without each signal; assert
      fail-closed route when wt unavailable.
    • Files: internal/worktrunk/worktrunk.go, internal/worktrunk/worktrunk_test.go.
  • T6 — Executor interface (real + fake)

    • Acceptance: Executor interface { RemoveWorktree(dir) error; DeleteBranch(name) error; WtRemove(branch) error }. Real impl shells git worktree remove / git branch -D /
      wt remove --foreground. fakeExecutor records calls without running them.
    • Verify: go test ./internal/git/ — integration (temp repo) for real RemoveWorktree +
      DeleteBranch; fake used by later routing tests.
    • Files: internal/git/executor.go, internal/git/executor_test.go.
  • T7 — cmd/prune: per-branch Verdict in the read-only report

    • Acceptance: runPrune collects state (T2–T5), builds a BranchState per candidate, runs
      Guard, renders held reasons in the table + adds verdict to JSON additively. No
      --apply yet → still fully read-only.
    • Verify: go test ./cmd/ — safety-regression: bare prune performs zero mutations
      (refs+worktrees unchanged); JSON still contains safeToDelete/needsReview plus verdict.
    • Files: cmd/prune.go, cmd/prune_test.go.
  • T8 — cmd/prune: --apply (single-repo gate + [y/N/a/q] + dispatch)

    • Acceptance: flags --apply (bool), --no-ignore (bool), --anti-gitignore <path>,
      -y/--yes. Single-repo gate: if --apply and discovered branches span >1
      --git-common-dir, error before any prompt. Interactive loop matches [y/N/a/q]
      (Enter=skip, y, a=all, q=quit); -y = all. Only Removable verdicts offered; held
      listed with reason. Each confirmed removal dispatched via Route→Executor.
    • Verify: go test ./cmd/ — (a) multi-common-dir --apply refused; (b) interaction parity
      with scripted stdin; (c) SkipWtUnavailable never calls native executor (fake asserts);
      (d) temp-repo end-to-end: one loose branch + one worktree removed.
    • Files: cmd/prune.go, cmd/prune_test.go.
  • T9 — Docs + help text

    • Acceptance: README documents the plan/apply model, the durability guard, and all flags;
      cobra long-help for prune updated. gofmt -l . clean, go vet ./... clean.
    • Verify: go run . prune --help shows the new flags; go test ./... green.
    • Files: README.md, cmd/prune.go.

Parallelization

T1 ─┬─ T2 ─┐
    ├─ T3 ─┼─ T6 ─┐
    ├─ T4 ─┤      ├─ T8 ─ T9
    └─ T5 ─┘  T7 ─┘
                (T7 needs T1–T5; T8 needs T6+T7)

Out of scope

  • Touching NeedsReview, CLOSED-unmerged branches, or the primary/current worktree.
  • Glob re-interpretation in .anti-gitignore — keys match verbatim against .gitignore.
  • Making the bare skiffs prune command destructive (read-only stays the default).
  • Non-GitHub remotes: branches whose squash-safety can't be proven via a MERGED PR are held,
    never auto-removed.
Lenguaje dominante
Go
Estrellas
5
Forks
0
Métricas de merge de PR
Sin PR fusionados en 30 d

Preparar el entorno

Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Issues similares

Más issues de Go

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.