From 8c438e9f56895f69bf09ee78db44bc2f9688679e Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 12 Oct 2021 02:30:27 -0400 Subject: [PATCH] git-rb-all: handle buggy worktreepath settings --- .bin/git-rb-all | 52 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/.bin/git-rb-all b/.bin/git-rb-all index b44b449..c9071e1 100755 --- a/.bin/git-rb-all +++ b/.bin/git-rb-all @@ -7,6 +7,7 @@ import functools import os from pathlib import Path import re +import shlex import subprocess import sys @@ -59,10 +60,10 @@ class Color: return cls.BAD + msg + cls.NORMAL -def dbg(msg): +def dbg(*args, **kwargs): """Print a debug |msg|.""" if DEBUG: - print(msg, file=sys.stderr) + print(*args, file=sys.stderr, **kwargs) def fatal(msg): @@ -78,8 +79,16 @@ def git(args, **kwargs): kwargs.setdefault('stderr', subprocess.STDOUT) kwargs.setdefault('encoding', 'utf-8') if DEBUG: - print('+', 'git', *args) - return subprocess.run(['git'] + args, **kwargs) + dbg('+', 'git', shlex.join(args)) + ret = subprocess.run(['git'] + args, **kwargs) + if DEBUG: + if ret.stdout: + dbg(ret.stdout.rstrip()) + if ret.stderr: + dbg('stderr =', ret.stderr) + if ret.returncode: + dbg('++ exit', ret.returncode) + return ret @functools.lru_cache(maxsize=None) @@ -110,6 +119,32 @@ def cherry_pick_inprogress(): return Path(output).exists() +@functools.lru_cache(maxsize=None) +def top_dir() -> Path: + """Find the top dir of the git checkout.""" + output = git(['rev-parse', '--show-toplevel'], stderr=subprocess.PIPE).stdout.strip() + return Path(output).resolve() + + +@functools.lru_cache(maxsize=None) +def git_dir() -> Path: + """Find the internal git dir for this project.""" + output = git(['rev-parse', '--git-dir']).stdout.strip() + return Path(output).resolve() + + +@functools.lru_cache(maxsize=None) +def worktree_is_local(worktree: str) -> bool: + """See whether |worktree| is the cwd git repo.""" + if not worktree: + return True + + # NB: worktree path is supposed to be absolute from for-each-ref, but it's + # not always, so we have to resolve it. https://crbug.com/git/88 + worktree = (git_dir() / worktree).resolve() + return worktree == top_dir() + + class AppendOption(argparse.Action): """Append the command line option (with no arguments) to dest. @@ -154,7 +189,7 @@ def main(argv): # Switch to the top dir in case the working dir doesn't exist in every branch. try: - topdir = git(['rev-parse', '--show-toplevel'], stderr=subprocess.PIPE).stdout.strip() + topdir = top_dir() except subprocess.CalledProcessError as e: sys.exit(f'{os.path.basename(sys.argv[0])}: {Path.cwd()}:\n{e}\n{e.stderr.strip()}') os.chdir(topdir) @@ -177,7 +212,7 @@ def main(argv): if head == '*': curr_state = branch local_count += 1 - elif not (worktreepath and worktreepath != topdir): + elif worktree_is_local(worktreepath): local_count += 1 else: dbg(f'{worktreepath}:{branch}: Skipping branch checked out in diff worktree') @@ -196,7 +231,8 @@ def main(argv): _, worktreepath, branch, tracking, ahead_behind = line.split('|') # If it's a branch in another worktree, ignore it. - if worktreepath and worktreepath != topdir: + if not worktree_is_local(worktreepath): + dbg(f'{worktreepath}:{branch}: Skipping branch checked out in diff worktree') continue print(f'{Color.BRACKET}### {Color.GOOD}{branch:{branch_width}}{Color.NORMAL} ', @@ -249,7 +285,7 @@ def main(argv): else: result = git(['rebase'] + opts.git_options, check=False) if result.returncode: - git(['rebase', '--abort']) + git(['rebase', '--abort'], check=False) print(Color.bad('failed') + '\n' + result.stdout.strip()) else: print(Color.good('OK')) -- 2.39.5