Skip to content

feat: add git-delete-gone-branches command#1239

Open
codersofthedark wants to merge 3 commits intotj:mainfrom
codersofthedark:feat/delete-gone-branches
Open

feat: add git-delete-gone-branches command#1239
codersofthedark wants to merge 3 commits intotj:mainfrom
codersofthedark:feat/delete-gone-branches

Conversation

@codersofthedark
Copy link
Copy Markdown

Closes #1220

What

Adds a new git delete-gone-branches command that deletes all local branches whose remote-tracking branch has been deleted (shown as [gone] in git branch -vv).

Why

After PRs are merged and remote branches are cleaned up on GitHub/GitLab, local branches are left behind with no remote. There's no existing git-extras command to clean these up — git delete-merged-branches handles a different case (merged but remote still exists).

Usage

# Delete all gone branches
$ git delete-gone-branches
Deleted branch feature-123 (was abc1234).
Deleted branch feature-456 (was def5678).

# Preview without deleting
$ git delete-gone-branches --dry-run
Would delete the following branches:
  feature-123
  feature-456

Changes

  • bin/git-delete-gone-branches — the command
  • man/git-delete-gone-branches.md — man page
  • Commands.md — added to index and description section
  • etc/git-extras-completion.zsh — zsh completion with --dry-run flag

Checklist

  • Script starts with #!/usr/bin/env bash
  • Man page written
  • Added to Commands.md
  • Updated etc/git-extras-completion.zsh
  • check_integrity.sh — requires local install of ronn to generate .1/.html man files; happy to add if needed

Adds a new command to delete local branches whose remote-tracking
branch has been deleted (shown as [gone] in git branch -vv).

This is a common need after PRs are merged and remote branches are
cleaned up, leaving stale local branches behind.

Features:
- Deletes all local branches with a gone remote in one command
- --dry-run / -n flag to preview branches before deletion

Closes tj#1220
Comment thread bin/git-delete-gone-branches Outdated
esac
done

gone_branches=$(git branch -vv | awk '/: gone\]/{print $1}')
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

git branch -vv output includes the latest commit subject. If a commit message contains the literal text : gone], this branch would be incorrectly matched.

What about

gone_branches=$(git for-each-ref --format
  '%(if:equals=[gone])%(upstream:track,nobracket)%(then)%(refname:short)%(end)' refs/heads/ | sed '/^$/d')

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — switched to git for-each-ref with %(upstream:track,nobracket) to match only the tracking status, so commit message content can't cause false positives.

exit 0
fi

echo "$gone_branches" | xargs git branch -D
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we prompt for the branch deletion by default?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added an interactive [y/N] confirmation prompt by default. Use -f/--force to skip it (consistent with how git-clear and git-sync handle this in the repo).

exit 1
;;
esac
done
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to run git fetch --prune before?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a -p/--prune flag that runs git fetch --prune before checking. Kept it opt-in rather than automatic to avoid unexpected network calls.

- Use git for-each-ref instead of git branch -vv to avoid false
  positives from commit messages containing ': gone]'
- Add interactive confirmation prompt by default; skip with -f/--force
- Add -p/--prune flag to run git fetch --prune before checking
- Add generated man page .1 and .html files
@hyperupcall
Copy link
Copy Markdown
Collaborator

hyperupcall commented Mar 19, 2026

@spacewander Do you think we should have a policy about AI contributions? In my opinion, it's highly disrespectful if I spent my time reviewing code, and the reply from the contributor is fully AI generated. I'm not against the usefulness of AI, I use it quite frequently, but I think we should draw the line somewhere as maintainers. I hear many other open-source projects are figuring stuff out as well.

With the goal of allowing contributors to use AI, but still require talking to an actual human, I'm thinking about some ground-rules like:

  • Allow code generated by AI
  • If the issue content is AI-generated, that must be disclosed and the user must vouch for its correctness as if they had written it themselves
  • Replies to PRs must be human-generated. Of course, it's okay for code changes to be written by AI.

What do you think?

@spacewander
Copy link
Copy Markdown
Collaborator

@hyperupcall
Thanks. The AI contribution guideline LGTM. Would you add a doc for it?

fi

gone_branches=$(git for-each-ref --format \
'%(if:equals=[gone])%(upstream:track,nobracket)%(then)%(refname:short)%(end)' refs/heads/ | sed '/^$/d')
Copy link
Copy Markdown

@mevanlc mevanlc Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with ,nobracket, I think you'll want the if-condition to be:
%(if:equals=gone)
(remove the square brackets)
@codersofthedark

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature Request: Add git-delete-gone-branches command

4 participants