Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
git-rmbranch/git-rmbranch /
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
executable file
105 lines (75 sloc)
3.26 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env python3 | |
| import argparse | |
| import re | |
| import subprocess | |
| import sys | |
| def get_default_branch(): | |
| """Get the repo's "default" branch from the config. If not set, then use either master or main""" | |
| result = subprocess.run(['git', 'config', '--get', 'rmbranch.defaultBranch'], capture_output=True, text=True) | |
| if result.returncode == 0: | |
| return result.stdout.rstrip() | |
| for branch_name in ('master', 'main'): | |
| if subprocess.run(['git', 'show-ref', '--verify', '--quiet', f'refs/heads/{branch_name}']).returncode == 0: | |
| return branch_name | |
| raise RuntimeError('Unable to determine the default branch for the repo') | |
| def get_upstream(branch_name): | |
| """Get upstream information for a local branch from config""" | |
| result = subprocess.run( | |
| ['git', 'config', '--get-regexp', fr'^branch\.{re.escape(branch_name)}\.'], | |
| capture_output=True, text=True) | |
| if result.returncode != 0: | |
| return None | |
| upstream = {} | |
| offset = len(f'branch.{branch_name}.') | |
| for line in result.stdout.splitlines(): | |
| key, value = line.split() | |
| key = key[offset:] | |
| assert key not in upstream, f"Multiple values for 'branch.{branch_name}.{key}'" | |
| upstream[key] = value | |
| return upstream | |
| def get_current_branch(): | |
| """Get the current branch name""" | |
| return subprocess.run( | |
| ['git', 'branch', '--show-current'], | |
| capture_output=True, check=True, text=True | |
| ).stdout.rstrip() | |
| def main(): | |
| args = parse_args() | |
| current_branch = get_current_branch() | |
| branch_name = current_branch if args.branch_name is None else args.branch_name | |
| default_branch = get_default_branch() | |
| if branch_name == default_branch: | |
| print(f"Refusing to remove the default branch '{branch_name}'") | |
| return 1 | |
| if branch_name == current_branch: | |
| new_branch = input(f'Enter a branch name to checkout ({default_branch}): ').strip() | |
| if not new_branch: | |
| new_branch = default_branch | |
| result = subprocess.run(['git', 'checkout', new_branch]) | |
| if result.returncode != 0: | |
| return result.returncode | |
| upstream = get_upstream(branch_name) | |
| result = subprocess.run(['git', 'branch', '-D', branch_name], | |
| capture_output=True, text=True) | |
| if result.returncode != 0: | |
| print(result.stderr, end='') | |
| return result.returncode | |
| sha = re.search(r'\(was (\w+)\)', result.stdout)[1] | |
| print(result.stdout.rstrip(), | |
| f"To restore, run 'git branch {branch_name} {sha}'.") | |
| if upstream is None: | |
| print(f"No upstream configured for the branch '{branch_name}'.") | |
| return 0 | |
| print(f"Deleting '{upstream['merge']}' from '{upstream['remote']}'..") | |
| # this command also removes the local remote-tracking branch | |
| return subprocess.run( | |
| ['git', 'push', upstream['remote'], '--delete', upstream['merge']], | |
| timeout=30 | |
| ).returncode | |
| def parse_args(): | |
| parser = argparse.ArgumentParser(description='Delete a Git branch locally and remotely.') | |
| parser.add_argument('branch_name', nargs='?', | |
| help='The branch name. In case no argument is provided, the current branch will be used') | |
| return parser.parse_args() | |
| if __name__ == '__main__': | |
| sys.exit(main()) |