Created
September 14, 2016 17:24
-
-
Save mccutchen/cc96d52c42998134456adab90c9dd166 to your computer and use it in GitHub Desktop.
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 python | |
import subprocess | |
import sys | |
def get_current_branch(): | |
cmd = 'git name-rev --name-only HEAD'.split() | |
return subprocess.check_output(cmd).strip() | |
def delete_local_branch(name): | |
cmd = 'git branch -d {}'.format(name).split() | |
return subprocess.check_output(cmd).strip() | |
def delete_remote_branch(name): | |
remote, name = name.split('/') | |
cmd = 'git push {} :{}'.format(remote, name).split() | |
return subprocess.check_output(cmd).strip() | |
def list_branches(opts=''): | |
""" | |
Return a list of branch names that should be safe to delete. The given opts | |
will be passed into `git branch` and should determine whether to list local | |
or remote branches. | |
Local branch output: | |
$ git branch --merged | |
INFRA-658-user-cleanup | |
* master | |
master-new | |
new-master | |
Remote branch output: | |
$ git branch -r --merged | |
origin/DISTR-609-scaffold-components-and-fetch-artifacts | |
origin/HEAD -> origin/master | |
origin/INFRA-658-user-cleanup | |
origin/VIDPUB-136-API-GET-project-by-ID-precommit | |
origin/feeder-worker | |
origin/master | |
""" | |
assert isinstance(opts, basestring) | |
cmd = 'git branch {} --merged'.format(opts).split() | |
lines = subprocess.check_output(cmd).splitlines() | |
names = map(parse_branch_name, lines) | |
return filter(safe_to_delete, names) | |
def list_local_branches(): | |
return list_branches() | |
def list_remote_branches(): | |
return list_branches('-r') | |
def parse_branch_name(line): | |
return line.lstrip(' *').split()[0] | |
def safe_to_delete(name): | |
return name.split('/')[-1] not in ('master', 'develop', 'HEAD') | |
def pluralize(xs, suffix='s'): | |
return suffix if len(xs) > 0 else '' | |
def get_answer(base_prompt): | |
answer_map = { 'y': True, 'yes': True, 'n': False, 'no': False} | |
prompt = '{} [Y/n]: '.format(base_prompt) | |
while True: | |
answer = raw_input(prompt).strip().lower() or 'y' | |
if answer in answer_map: | |
return answer_map[answer] | |
def main(): | |
if get_current_branch() != 'master': | |
print 'Error: git-cleanup must be run from the `master` branch' | |
return 1 | |
local_branches = list_local_branches() | |
remote_branches = list_remote_branches() | |
if local_branches: | |
count = len(local_branches) | |
branch_word = 'branch{}'.format(pluralize(local_branches, 'es')) | |
print 'Found {} fully merged local {}:'.format(count, branch_word) | |
for branch in local_branches: | |
print ' - {}'.format(branch) | |
do_delete = get_answer('Delete {} local {}?'.format(count, branch_word)) | |
if do_delete: | |
for branch in local_branches: | |
delete_local_branch(branch) | |
if remote_branches: | |
count = len(remote_branches) | |
branch_word = 'branch{}'.format(pluralize(remote_branches, 'es')) | |
print 'Found {} fully merged remote {}:'.format(count, branch_word) | |
for branch in remote_branches: | |
print ' - {}'.format(branch) | |
do_delete = get_answer('Delete {} remote {}?'.format(count, branch_word)) | |
if do_delete: | |
for branch in remote_branches: | |
delete_remote_branch(branch) | |
if __name__ == '__main__': | |
sys.exit(main()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment