]> git.wh0rd.org - home.git/commitdiff
git-rb-all: handle buggy worktreepath settings
authorMike Frysinger <vapier@gentoo.org>
Tue, 12 Oct 2021 06:30:27 +0000 (02:30 -0400)
committerMike Frysinger <vapier@gentoo.org>
Tue, 12 Oct 2021 06:30:27 +0000 (02:30 -0400)
.bin/git-rb-all

index b44b449def815e1cb6bdb0249c1595d46ba432a6..c9071e10f5ab74b73cabd8abcb95692a2d48dfa2 100755 (executable)
@@ -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'))