Skip to content

Instantly share code, notes, and snippets.

@jaredly
Created December 1, 2016 20:53
Show Gist options
  • Select an option

  • Save jaredly/eea23db764ef081474c4e534d0438320 to your computer and use it in GitHub Desktop.

Select an option

Save jaredly/eea23db764ef081474c4e534d0438320 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
# Toss this in your ~/bin/ as ~/bin/reboost and `chmod +x ~/bin/reboost`
"""\
Usage:
reboost [cmd]
Commands:
first - follow upstream until just before master
last - follow downstreams all the way
up - go to parent
down - go to child
all - rebase & follow downstream, rebasing all the way
"""
from collections import defaultdict
import subprocess
import os
import sys
import re
example = '''\
examples-7 c377c75 [gen-files-6: ahead 2] wrong call
flow-ast-2 751352e [initial-diff-setup-1: ahead 1, behind 1] Add flowtype ast parsing for rn-codegen
gen-files-6 7c56ae7 [marshall-code-5: ahead 1] Implement swift class generation
* initial-diff-setup-1 29c611a [master: ahead 2] use error
marshall-code-5 9fe3d2e [vc-props-4: ahead 1] Implement serialization and deserialization [ReactNative codegen]
master 2ca33d5 [origin/master] empty readme
saved e87821b [phab-prep: gone] docs
signatures-3 2642f3f [flow-ast-2: ahead 1] Implement type signature generation [ReactNative codegen]
vc-props-4 9f0b957 [signatures-3: ahead 1] Implement code gen for the ViewController's properties'''
rx = '\s*(\*)?\s*(\S+)\s+(\S+)\s+(.+)'
def parse_branches(txt):
lines = txt.strip().split('\n')
current = None
children = defaultdict(list)
parents = {}
for line in lines:
line = line.strip()
match = re.match(rx, line)
if not match:
print ">> unexpected output line from git branch: %s" % line
continue
is_current, name, sha, extra = match.groups()
if is_current is not None:
current = name
if extra[0] != '[':
# no parent
# TODO maybe keep track of commit message?
continue
parentage = extra[1:].split('] ', 1)[0]
if ':' not in parentage:
parent = parentage
status = ''
else:
parent, status = parentage.split(': ', 1)
children[parent].append(name)
parents[name] = (parent, status)
if not current:
raise Exception('Current branch not found')
return current, parents, children
def get_branches():
return parse_branches(subprocess.check_output(['git', 'branch', '-vv']))
def get_children():
current, parents, children = get_branches()
return children[current]
def get_next_branch():
children = get_children()
if not children:
return # no children, reached the end
if len(children) != 1:
raise Exception("Current branch must have only one child")
child = children[0]
return child
def rebase_children():
for i in range(20):
child = get_next_branch()
if not child:
print "No more children"
break
print "Moving to", child
subprocess.check_call(['git', 'checkout', child], stdout=sys.stdout, stderr=sys.stderr)
subprocess.check_call(['git', 'rebase'], stdout=sys.stdout, stderr=sys.stderr)
def go_to_first():
current, parents, _ = get_branches()
while current in parents and parents[current][0] != 'master':
current = parents[current][0]
print "Checkout", current
subprocess.check_call(['git', 'checkout', current])
def go_to_last():
current, _, children = get_branches()
while len(children[current]) == 1:
current = children[current][0]
print "Checkout", current
subprocess.check_call(['git', 'checkout', current])
def go_to_parent():
current, parents, _ = get_branches()
if parents[current][0] != 'master':
current = parents[current][0]
print "Checkout", current
subprocess.check_call(['git', 'checkout', current])
def go_to_child():
current, _, children = get_branches()
if len(children[current]) == 1:
current = children[current][0]
print "Checkout", current
subprocess.check_call(['git', 'checkout', current])
def show_pedigree():
current, parents, children = get_branches()
branch = current
while len(children[branch]) == 1:
branch = children[branch][0]
while branch in parents:
print ('* ' if branch == current else ' ') + branch + ': ' + parents[branch][1]
branch = parents[branch][0]
print ('* ' if branch == current else ' ') + branch, '(root)'
def print_help():
try:
current, parents, children = get_branches()
print "Status:"
print " - current: ", current
print " - parent: ", parents[current]
print " - children: ", children[current]
print
except:
pass
print __doc__
if len(sys.argv) > 1:
cmd = sys.argv[1]
if cmd == 'first':
go_to_first()
elif cmd == 'last':
go_to_last()
elif cmd == 'up':
go_to_parent()
elif cmd == 'down':
go_to_child()
elif cmd == 'all':
rebase_children()
elif cmd in ('l', 'list', 'll'):
show_pedigree()
else:
print_help()
else:
print_help()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment