From fb5d2cb632ad05e57c8b257f5a3c85bb75c8ac31 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sat, 20 Feb 2021 11:34:56 -0500 Subject: [PATCH] git-rb-all: handle more edge cases --- .bin/git-rb-all | 50 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/.bin/git-rb-all b/.bin/git-rb-all index 92834ac..a2f7922 100755 --- a/.bin/git-rb-all +++ b/.bin/git-rb-all @@ -49,10 +49,18 @@ class Color: HILITE = _combine(Terminal.BOLD, Terminal.FG_CYAN) BRACKET = _combine(Terminal.BOLD, Terminal.FG_BLUE) + @classmethod + def good(cls, msg): + return cls.GOOD + msg + cls.NORMAL + + @classmethod + def bad(cls, msg): + return cls.BAD + msg + cls.NORMAL + def fatal(msg): """Show an error |msg| then exit.""" - print(f'{Color.BAD}{PROG}: error: {msg}{Color.NORMAL}', file=sys.stderr) + print(Color.bad(f'{PROG}: error: {msg}'), file=sys.stderr) sys.exit(1) @@ -87,6 +95,13 @@ def rebase_inprogress(): return False +@functools.lru_cache(maxsize=None) +def cherry_pick_inprogress(): + """Determine whether a cherry-pick is in progress.""" + output = git(['rev-parse', '--git-path', 'CHERRY_PICK_HEAD']).stdout.strip() + return Path(output).exists() + + class AppendOption(argparse.Action): """Append the command line option (with no arguments) to dest. @@ -123,10 +138,6 @@ def main(argv): parser = get_parser() opts = parser.parse_args(argv) - # Skip if rebase is in progress. - if rebase_inprogress(): - fatal('skipping due to active rebase') - # Switch to the top dir in case the working dir doesn't exist in every branch. topdir = git(['rev-parse', '--show-toplevel']).stdout.strip() os.chdir(topdir) @@ -138,7 +149,7 @@ def main(argv): # ||s-stash|| state = git( ['for-each-ref', '--format=%(HEAD)|%(worktreepath)|%(refname:short)|%(upstream)|%(upstream:track,nobracket)', - 'refs/heads/*']).stdout.splitlines() + 'HEAD', 'refs/heads/*']).stdout.splitlines() curr_state = None branch_width = 0 @@ -154,7 +165,10 @@ def main(argv): if not local_count: return 0 if not curr_state: - fatal('unable to resolve current branch') + # Are we in a detached head state? + if not git(['symbolic-ref', '-q', 'HEAD'], check=False).returncode: + fatal('unable to resolve current branch') + curr_state = git(['rev-parse', 'HEAD']).stdout.strip() switched_head = False branches = {} @@ -176,7 +190,7 @@ def main(argv): m = re.search(r'behind ([0-9]+)', ahead_behind) behind = int(m.group(1)) if m else 0 if not behind: - print('Up-to-date!') + print(Color.good('up-to-date')) continue elif not ahead: # If we haven't switched the checkout, update-ref on current HEAD @@ -187,17 +201,27 @@ def main(argv): else: result = git(['merge', '-q', '--ff-only'], check=False) if result.returncode: - print(f'{Color.BAD}unable to merge{Color.NORMAL}\n' + result.stdout.strip()) + print(Color.bad('unable to merge') + '\n' + result.stdout.strip()) else: print('fast forwarded [merged]') continue + # Skip this ref if tree is in a bad state. + if rebase_inprogress(): + print(Color.bad('skipping due to active rebase')) + continue + if cherry_pick_inprogress(): + print(Color.bad('skipping due to active cherry-pick')) + continue if checkout_is_dirty(): - print(f'{Color.BAD}unable to rebase: tree is dirty{Color.NORMAL}') + print(Color.bad('unable to rebase: tree is dirty')) continue print(f'rebasing [{ahead_behind}] ', end='', flush=True) - git(['checkout', '-q', branch]) + result = git(['checkout', '-q', branch], check=False) + if result.returncode: + print(Color.bad('unable to checkout') + '\n' + result.stdout.strip()) + continue switched_head = True if opts.catchup: print() @@ -206,9 +230,9 @@ def main(argv): result = git(['rebase'] + opts.git_options, check=False) if result.returncode: git(['rebase', '--abort']) - print(f'{Color.BAD}failed{Color.NORMAL}\n' + result.stdout.strip()) + print(Color.bad('failed') + '\n' + result.stdout.strip()) else: - print('OK!') + print(Color.good('OK')) if switched_head: git(['checkout', '-q', curr_state]) -- 2.39.2