Last active
August 15, 2019 10:23
-
-
Save rhizoome/b1007add1400935a89b0d1eb239b9f3d to your computer and use it in GitHub Desktop.
Bisect get merge/rebase (seems safe, but use at your own risk)
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 bisect | |
import functools | |
import shlex | |
import subprocess as s | |
import sys | |
devel = False | |
tokens = """ | |
git | |
merge-base | |
rev-parse | |
HEAD | |
rev-list | |
--ancestry-path | |
-b | |
--abort | |
symbolic-ref | |
--short | |
--no-commit | |
stash | |
pop | |
--get | |
config | |
rebase.autostash | |
""" | |
help = """ | |
Seems safe, but use at your own risk. | |
Brase will try merge/rebase a branch as far as possible using bisect. | |
Please specify which branch you want to merge/rebase. | |
git brase <merge|rebase> '<branch>' [-n] | |
--exec execute the merge/rebase found | |
""".strip() | |
class Tokens: | |
def __init__(self): | |
token_list = shlex.split(tokens) | |
token_dict = {} | |
for token in token_list: | |
name = token.lstrip("-") | |
name = name.replace("-", "_") | |
name = name.replace(".", "_") | |
token_dict[name] = token | |
assert len(token_dict.keys()) == len(token_list) | |
for name in token_dict.keys(): | |
setattr(self, name, token_dict[name]) | |
t = Tokens() | |
def git(*args): | |
try: | |
return s.check_output((t.git,) + args, stderr=s.STDOUT).strip().decode("UTF-8") | |
except s.CalledProcessError as e: | |
if devel: | |
print(get_output(e)) | |
raise | |
def igit(*args): | |
try: | |
return git(*args) | |
except s.CalledProcessError as e: | |
if devel: | |
print(get_output(e)) | |
import traceback | |
traceback.print_exc() | |
def get_output(e): | |
return e.output.decode("UTF-8") | |
def execute(target, index): | |
ret = False | |
try: | |
git(t.command, t.no_commit, target[index]) | |
ret = True | |
except s.CalledProcessError: | |
pass | |
finally: | |
igit(t.command, t.abort) | |
short = target[index][:8] | |
if ret: | |
text = "sucessful" | |
else: | |
text = "failed" | |
print(f"{t.command} index({index}) rev({short}) {text}") | |
return ret | |
def brase(target, base): | |
max_index = len(target) - 1 | |
driver = functools.partial(execute, target) | |
class BisectTarget(object): | |
def __getitem__(self, index): | |
ret = driver(index) | |
return ret | |
def __len__(self): | |
return max_index | |
if driver(0): | |
return 0 | |
else: | |
bt = BisectTarget() | |
return bisect.bisect(bt, False) | |
def main(): | |
head = git(t.rev_parse, t.HEAD) | |
head_name = git(t.symbolic_ref, t.short, t.HEAD) | |
dry = True | |
len_argv = len(sys.argv) | |
if len_argv == 4: | |
if sys.argv[3] != "--exec": | |
print(help) | |
sys.exit(1) | |
else: | |
dry = False | |
elif len_argv < 3: | |
print(help) | |
sys.exit(1) | |
elif sys.argv[1] not in ("merge", "rebase"): | |
print(help) | |
sys.exit(1) | |
t.command = sys.argv[1] | |
target_name = sys.argv[2] | |
target = git(t.rev_parse, target_name) | |
assert target != head | |
base = git(t.merge_base, head, target) | |
path = git(t.rev_list, t.ancestry_path, f"{base}..{target}").split("\n") | |
print(f"found {len(path)} commits to {t.command}") | |
# _path_parent = git(t.rev_parse, f"{path[-1]}^") | |
assert path[0] == target | |
# assert _path_parent == base | |
autostash = git(t.config, t.get, t.rebase_autostash).lower() == "true" | |
stashed = False | |
if autostash and t.command == "rebase": | |
try: | |
if not git(t.stash): | |
stashed = True | |
except s.CalledProcessError: | |
pass | |
try: | |
index = brase(path, base) | |
if dry: | |
sys.stdout.write("-> ") | |
execute(path, index) | |
finally: | |
igit(t.command, t.abort) | |
if stashed: | |
git(t.stash, t.pop) | |
if not dry: | |
try: | |
git(t.command, path[index]) | |
except s.CalledProcessError as e: | |
print(get_output(e)) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment