Skip to content

Instantly share code, notes, and snippets.

@ShawnMilo
Created December 12, 2014 02:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ShawnMilo/62770d9762ed51690e7a to your computer and use it in GitHub Desktop.
Save ShawnMilo/62770d9762ed51690e7a to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
"""
Identify (and potentially delete) remote branches which have already
been merged into the current branch.
It works by using the "git merge-base" command to see if the other branch's
newest commit is already contained in the current branch.
Run normally it does nothing destructive. It will just list branches that
could be deleted. This information can be used selectively, or reviewed
and this script can be run with the word DELETE passed as its sole argument
to actually perform the git commands to delete these branches from the
'origin' repository.
"""
import sys
from subprocess import check_output, CalledProcessError
from collections import Counter
DO_DELETE = sys.argv[-1] == 'DELETE'
# Branches that should be ignored, and a blank space to clean
# up the output of 'git branch' above.
EXEMPT = set(('master',))
def get_current_branch():
"""
Get current branch using subprocess call to git.
"""
return check_output(['git', 'rev-parse', '--abbrev-ref', 'HEAD']).strip()
def main():
"""
Check for (and optionally delete) the branches.
"""
current_branch = get_current_branch()
# Get remote branches.
branches = [
x.strip() for x in check_output(['git', 'branch', '-r']).split('\n')
]
EXEMPT.add(current_branch)
counter = Counter()
for branch in branches:
if branch.split('/')[-1] in EXEMPT:
counter['skipped exempt branches'] += 1
continue
try:
merge_base = check_output([
'git', 'merge-base', current_branch, branch
]).strip()
except CalledProcessError:
sys.stderr.write("Unable to check branch {0}\n".format(branch))
continue
branch_head = check_output([
'git', 'log', '-n', '1', '--oneline', branch
]).split()[0]
assert len(branch_head.strip()) >= 7
if merge_base.startswith(branch_head):
if DO_DELETE:
print "Removing old branch from server: '{0}'".format(branch)
remote, branch_name = branch.split('/')[-2:]
print check_output(['git', 'push', remote, ':' + branch_name])
else:
info = check_output([
'git', 'log', '-n 1', '--format="%an %ar"', branch
])
info = info.replace('"', '').strip()
print "Would be deleted: '{0}', last updated by {1}".format(
branch, info
)
counter['to remove'] += 1
else:
counter['leave alone'] += 1
for key in counter:
print unicode(key).rjust(20, ' '), unicode(counter[key]).rjust(10, ' ')
if counter['to remove'] == 0:
print "\nCongratulations! Nothing to do."
elif not DO_DELETE:
print (
"\nNothing done. Pass 'DELETE' as the "
"first argument to actually clear out the branches."
)
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment