From 085cc65406b256761506cde4a4225fef511771df Mon Sep 17 00:00:00 2001 From: Christian Zeitner - dotSource SE Date: Wed, 1 Jul 2026 10:21:58 +0200 Subject: [PATCH] Initial Commit --- cleanupGoneBranches.go | 204 ++++++++++++++++++++--------------------- 1 file changed, 102 insertions(+), 102 deletions(-) diff --git a/cleanupGoneBranches.go b/cleanupGoneBranches.go index e37f079..c8e4721 100644 --- a/cleanupGoneBranches.go +++ b/cleanupGoneBranches.go @@ -42,7 +42,7 @@ func currentBranch() (string, error) { } func fetchPrune() error { - fmt.Println("Git fetch mit prune...") + fmt.Println("Git fetch with prune...") cmd := exec.Command("git", "fetch", "--prune") cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr @@ -82,7 +82,7 @@ func readLine(prompt string) (string, error) { func parseSelection(input string, max int) (map[int]bool, error) { input = strings.TrimSpace(input) if input == "" { - return nil, errors.New("keine Auswahl") + return nil, errors.New("No Selection") } if strings.EqualFold(input, "all") { @@ -103,18 +103,18 @@ func parseSelection(input string, max int) (map[int]bool, error) { if strings.Contains(p, "-") { b := strings.SplitN(p, "-", 2) if len(b) != 2 { - return nil, fmt.Errorf("ungültiger Bereich: %s", p) + return nil, fmt.Errorf("Invalid Range: %s", p) } start, err := strconv.Atoi(strings.TrimSpace(b[0])) if err != nil { - return nil, fmt.Errorf("ungültige Zahl: %s", b[0]) + return nil, fmt.Errorf("Invalid Number: %s", b[0]) } end, err := strconv.Atoi(strings.TrimSpace(b[1])) if err != nil { - return nil, fmt.Errorf("ungültige Zahl: %s", b[1]) + return nil, fmt.Errorf("Invalid Number: %s", b[1]) } if start < 1 || end > max || start > end { - return nil, fmt.Errorf("Bereich außerhalb 1..%d: %s", max, p) + return nil, fmt.Errorf("Range outside of 1..%d: %s", max, p) } for i := start; i <= end; i++ { sel[i] = true @@ -122,10 +122,10 @@ func parseSelection(input string, max int) (map[int]bool, error) { } else { n, err := strconv.Atoi(p) if err != nil { - return nil, fmt.Errorf("ungültige Zahl: %s", p) + return nil, fmt.Errorf("Invalid Number: %s", p) } if n < 1 || n > max { - return nil, fmt.Errorf("Auswahl außerhalb 1..%d: %d", max, n) + return nil, fmt.Errorf("Range outside of 1..%d: %d", max, n) } sel[n] = true } @@ -166,77 +166,77 @@ func main() { case "--show": showOnly = true case "--help", "-h": - fmt.Println("Usage: cleanupGoneBranches [--show] [--all] [--force]") - fmt.Println(" --show zeigt nur gone Branches") - fmt.Println(" --info zeigt die manuellen Git-Befehle für denselben Ablauf") - fmt.Println(" --all löscht alle gone Branches ohne Auswahl, fragt aber noch nach") - fmt.Println(" --force nutzt git branch -D statt -d") + fmt.Println("Usage: cleanupGoneBranches [--show] [--all] [--force]") + fmt.Println(" --show only displays gone branches") + fmt.Println(" --info displays the manual Git commands for the same workflow") + fmt.Println(" --all deletes all gone branches without prompting for selection, but still asks for confirmation") + fmt.Println(" --force uses git branch -D instead of -d") os.Exit(0) default: - fmt.Fprintf(os.Stderr, "Unbekanntes Argument: %s\n", a) + fmt.Fprintf(os.Stderr, "Unkown Argument: %s\n", a) os.Exit(2) } } if info { - fmt.Println("Manuelle Git-Befehle für denselben Ablauf:") - fmt.Println() - fmt.Println("1) Remote-Branches aktualisieren und verwaiste Referenzen entfernen:") - fmt.Println(" git fetch --prune") - fmt.Println() - fmt.Println("2) Gone-Branches anzeigen:") - fmt.Println(" git branch -vv") - fmt.Println(" (Branches mit '[origin/xyz: gone]' sind lokal verwaist)") - fmt.Println() - fmt.Println("3) Einzelnen Branch löschen (sicher, nur wenn gemerged):") - fmt.Println(" git branch -d ") - fmt.Println() - fmt.Println("4) Erzwingen (auch wenn nicht gemerged):") - fmt.Println(" git branch -D ") - fmt.Println() - fmt.Println("5) Alle gone-Branches automatisch löschen:") - fmt.Println(` git branch -vv | awk '/: gone]/{print $1}' | xargs -r git branch -D`) + fmt.Println("Manual Git commands for the same workflow:") + fmt.Println() + fmt.Println("1) Update remote branches and remove stale references:") + fmt.Println(" git fetch --prune") + fmt.Println() + fmt.Println("2) Show gone branches:") + fmt.Println(" git branch -vv") + fmt.Println(" (Branches marked with '[origin/xyz: gone]' are orphaned local branches)") + fmt.Println() + fmt.Println("3) Delete a single branch (safe, only if it has been merged):") + fmt.Println(" git branch -d ") + fmt.Println() + fmt.Println("4) Force deletion (even if it has not been merged):") + fmt.Println(" git branch -D ") + fmt.Println() + fmt.Println("5) Automatically delete all gone branches:") + fmt.Println(` git branch -vv | awk '/: gone]/{print $1}' | xargs -r git branch -D`) fmt.Println() return } - if !inGitRepo() { - fmt.Fprintln(os.Stderr, "Fehler: Das ist kein Git Repository (oder du bist nicht innerhalb des Worktrees).") - os.Exit(1) - } + if !inGitRepo() { + fmt.Fprintln(os.Stderr, "Error: This is not a Git repository (or you are not inside the working tree).") + os.Exit(1) + } - if err := fetchPrune(); err != nil { - fmt.Fprintln(os.Stderr, "Fetch fehlgeschlagen:", err) - os.Exit(1) - } + if err := fetchPrune(); err != nil { + fmt.Fprintln(os.Stderr, "Fetch failed:", err) + os.Exit(1) + } - vv, err := runGit("branch", "-vv") - if err != nil { - fmt.Fprintln(os.Stderr, "Konnte git branch -vv nicht ausführen:", err) - os.Exit(1) - } + vv, err := runGit("branch", "-vv") + if err != nil { + fmt.Fprintln(os.Stderr, "Failed to run git branch -vv:", err) + os.Exit(1) + } - gone, err := parseGoneBranches(vv) - if err != nil { - fmt.Fprintln(os.Stderr, "Konnte gone Branches nicht parsen:", err) - os.Exit(1) - } + gone, err := parseGoneBranches(vv) + if err != nil { + fmt.Fprintln(os.Stderr, "Failed to parse gone branches:", err) + os.Exit(1) + } - if len(gone) == 0 { - fmt.Println("Keine gone Branches gefunden.") - return - } + if len(gone) == 0 { + fmt.Println("No gone branches found.") + return + } cur, _ := currentBranch() fmt.Println() - fmt.Println("Gefundene lokale Branches mit gelöschtem Remote (gone):") + fmt.Println("Local branches found with a deleted remote (gone):") fmt.Println() for i, b := range gone { marker := "" if b == cur { - marker = " (aktueller Branch, wird übersprungen)" + marker = " (current branch, skipped)" } fmt.Printf(" %2d) %s%s\n", i+1, b, marker) } @@ -258,21 +258,21 @@ func main() { } } else { fmt.Println() - fmt.Println("Auswahl eingeben, z.B. 1,3-5 oder all. Leer lassen zum Abbrechen.") - in, rerr := readLine("Auswahl: ") - if rerr != nil { - fmt.Fprintln(os.Stderr, "Eingabe fehlgeschlagen:", rerr) - os.Exit(1) - } - if strings.TrimSpace(in) == "" { - fmt.Println("Abgebrochen, nichts gelöscht.") - return - } - selected, err = parseSelection(in, len(indexToBranch)) - if err != nil { - fmt.Fprintln(os.Stderr, "Ungültige Auswahl:", err) - os.Exit(2) - } + fmt.Println("Enter your selection, e.g. 1,3-5 or all. Leave blank to cancel.") + in, rerr := readLine("Selection: ") + if rerr != nil { + fmt.Fprintln(os.Stderr, "Input failed:", rerr) + os.Exit(1) + } + if strings.TrimSpace(in) == "" { + fmt.Println("Cancelled, nothing was deleted.") + return + } + selected, err = parseSelection(in, len(indexToBranch)) + if err != nil { + fmt.Fprintln(os.Stderr, "Invalid selection:", err) + os.Exit(2) + } } var toDelete []string @@ -285,40 +285,40 @@ func main() { } sort.Strings(toDelete) - if len(toDelete) == 0 { - fmt.Println("Nichts zu löschen (aktueller Branch wird nicht gelöscht).") - return - } + if len(toDelete) == 0 { + fmt.Println("Nothing to delete (current branch will not be deleted).") + return + } - fmt.Println() - fmt.Println("Es werden diese Branches gelöscht:") - for _, b := range toDelete { - fmt.Println(" -", b) - } + fmt.Println() + fmt.Println("The following branches will be deleted:") + for _, b := range toDelete { + fmt.Println(" -", b) + } - fmt.Println() - confirm, _ := readLine("Wirklich löschen? (y/N): ") - if !strings.EqualFold(confirm, "y") { - fmt.Println("Abgebrochen, nichts gelöscht.") - return - } + fmt.Println() + confirm, _ := readLine("Really delete? (y/N): ") + if !strings.EqualFold(confirm, "y") { + fmt.Println("Cancelled, nothing was deleted.") + return + } - fmt.Println() - fmt.Println("Lösche Branches...") - var failed bytes.Buffer - for _, b := range toDelete { - if err := deleteBranch(b, force); err != nil { - failed.WriteString(b) - failed.WriteString("\n") - } - } + fmt.Println() + fmt.Println("Deleting branches...") + var failed bytes.Buffer + for _, b := range toDelete { + if err := deleteBranch(b, force); err != nil { + failed.WriteString(b) + failed.WriteString("\n") + } + } - if failed.Len() > 0 { - fmt.Println() - fmt.Println("Fertig, aber diese Branches konnten nicht gelöscht werden:") - fmt.Print(failed.String()) - fmt.Println("Tipp: ohne --force wird nur gelöscht, wenn Git es als sicher ansieht.") - } else { - fmt.Println("Fertig.") - } + if failed.Len() > 0 { + fmt.Println() + fmt.Println("Done, but these branches could not be deleted:") + fmt.Print(failed.String()) + fmt.Println("Tip: without --force, Git only deletes branches it considers safe.") + } else { + fmt.Println("Done.") + } }