#!/usr/bin/env python3 # vim: set noet sw=4 ts=4: import pathlib import subprocess import sys def main(): delete = len(sys.argv) == 2 and sys.argv[1] == '-d' remotes = all_remotes() to_delete = [] print('will delete:') for local, remote in iter_locals(): if remote not in remotes: to_delete.append(local) sys.stdout.buffer.write(b'\t' + local) print() if delete and len(to_delete) > 0: if has_branchless(): run([b'git', b'hide'] + [b'draft()::' + branch for branch in to_delete]) else: run([b'git', b'branch', b'-D'] + to_delete) def all_remotes(): refs = run(['git', 'for-each-ref', '--format=%(refname:short)', 'refs/remotes'], capture_output=True) return frozenset(refs.stdout.rstrip(b'\n').split(b'\n')) def iter_locals(): refs = run(['git', 'for-each-ref', '--format=%(refname:short) %(upstream)', 'refs/heads'], capture_output=True) for line in refs.stdout.split(b'\n'): if not line: continue local, remote = line.split(b' ', 1) if not remote: continue assert remote.startswith(b'refs/remotes/') remote = remote.removeprefix(b'refs/remotes/') yield local, remote def has_branchless() -> bool: repo_root = run(['git', 'rev-parse', '--show-toplevel'], capture_output=True, text=True).stdout.rstrip('\n') return pathlib.Path(repo_root, '.git/branchless/config').is_file() def run(cmd, capture_output=False, text=None): return subprocess.run(cmd, capture_output=capture_output, check=True, text=text) if __name__ == '__main__': main()