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)
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.
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)
# ||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
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 = {}
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
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()
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])