Skip to content

Instantly share code, notes, and snippets.

@Chronial
Last active December 15, 2015 14:38
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 Chronial/5275577 to your computer and use it in GitHub Desktop.
Save Chronial/5275577 to your computer and use it in GitHub Desktop.
#!/usr/bin/python -O
"""
Finds the branch all the commits have most likely been mode on
"""
import os
import sys
import re
from pprint import pprint
if len(sys.argv) < 2:
print ("USAGE: {0} <list-of-branches>".format([sys.argv[0]]))
exit(1)
rev_list = os.popen('git log --format="%H:%P:%s" ' + ' '.join(sys.argv[1:]))
heads = {}
for head in sys.argv[1:]:
if head[0] == "^":
continue
sha = os.popen('git rev-parse {0}'.format(head)).read().strip()
heads[head] = sha
commits = {}
# commit structure:
# [parents, children, msg, distances
for line in rev_list:
line = line.strip().split(":")
sha = line[0]
if sha not in commits:
commits[sha] = [[], [], "", {}]
commit = commits[sha]
# Build Tree
for parent in line[1].split(' '):
if parent.strip() == "":
continue
if parent not in commits:
commits[parent] = [[], [], "", {}]
parent = commits[parent]
parent[1].append(commit)
commit[0].append(parent)
# Commit message
if len(commit[0]) > 1:
commit[2] = line[2]
def getBranchNames(message):
m = re.match(r"Merge branch '([^']+)' into (.+)", message)
if m is None:
return None
else:
return [m.group(2), m.group(1)]
known = []
for (branch, sha) in heads.iteritems():
todo = []
c = commits[sha]
d = 0
while True:
c[3][branch] = d
d = d - 1
if len(c[0]) == 2:
names = getBranchNames(c[2])
todo.append([c[0][1], d + 100 + 10000 * (names[1] == branch)])
c = c[0][0]
d = d + 10000 * (names[0] == branch)
for (parent, name) in zip(c[0], names):
if name not in heads:
continue
for parent_child in parent[1]:
# Are we the first parent?
if parent_child[0][0] == parent:
known.append([name, parent_child])
elif len(c[0]) > 0:
c = c[0][0]
todo.extend([x, d + 100] for x in c[0][1:])
else:
try:
(c, d) = todo.pop()
except IndexError:
break
branchHeadIds = set(id(commits[sha]) for sha in heads.itervalues())
for (branch, c) in known:
while True:
if branch not in c[3]:
break
if id(c) in branchHeadIds:
break
c[3][branch] = c[3][branch] - 10000
if len(c[1]) == 1:
c = c[1][0]
else:
break
match = {}
for (sha, commit) in sorted(commits.iteritems()):
match[sha] = min(commit[3].items(), key=lambda x: x[1])[0]
#print sha + ": " + match[sha]
log = os.popen('git log --color --oneline --graph --decorate --abbrev=100 '
+ ' '.join(sys.argv[1:])).read().splitlines()
for line in log:
try:
sha = re.search('[a-f0-9]{40}', line).group(0)
except AttributeError:
print line
continue
print re.sub('([a-f0-9]{7})[a-f0-9]{33}',
r'\1 [{}]'.format(match[sha]), line)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment