]>
git.wh0rd.org - home.git/blob - .bin/git-rb-all
1d9ded3d9d0786b9cd6060223b1a0de4d94fd3ce
3 """Helper to rebase all local branches."""
7 from pathlib
import Path
13 PROG
= os
.path
.basename(__file__
)
17 """Terminal escape sequences."""
23 _BLACK
, _RED
, _GREEN
, _YELLOW
, _BLUE
, _MAGENTA
, _CYAN
, _WHITE
= range(0, 8)
26 FG_BLACK
= str(_FG
+ _BLACK
)
27 FG_RED
= str(_FG
+ _RED
)
28 FG_GREEN
= str(_FG
+ _GREEN
)
29 FG_YELLOW
= str(_FG
+ _YELLOW
)
30 FG_BLUE
= str(_FG
+ _BLUE
)
31 FG_MAGENTA
= str(_FG
+ _MAGENTA
)
32 FG_CYAN
= str(_FG
+ _CYAN
)
33 FG_WHITE
= str(_FG
+ _WHITE
)
39 _combine
= lambda *args
: Terminal
.CSI_PREFIX
+ ';'.join(args
) + Terminal
.SGR_SUFFIX
40 NORMAL
= _combine(Terminal
.NORMAL
)
41 GOOD
= _combine(Terminal
.FG_GREEN
)
42 WARN
= _combine(Terminal
.FG_YELLOW
)
43 BAD
= _combine(Terminal
.FG_RED
)
44 HILITE
= _combine(Terminal
.BOLD
, Terminal
.FG_CYAN
)
45 BRACKET
= _combine(Terminal
.BOLD
, Terminal
.FG_BLUE
)
48 def git(args
, **kwargs
):
50 kwargs
.setdefault('check', True)
51 kwargs
.setdefault('capture_output', True)
52 kwargs
.setdefault('encoding', 'utf-8')
53 #print('+', 'git', *args)
54 return subprocess
.run(['git'] + args
, **kwargs
)
57 def rebase_inprogress():
58 """Determine whether a rebase is already in progress."""
59 output
= git(['rev-parse', '--git-path', 'rebase-merge']).stdout
.strip()
60 if Path(output
).exists():
63 output
= git(['rev-parse', '--git-path', 'rebase-apply']).stdout
.strip()
64 if Path(output
).exists():
70 class AppendOption(argparse
.Action
):
71 """Append the command line option (with no arguments) to dest.
73 parser.add_argument('-b', '--barg', dest='out', action='append_option')
74 options = parser.parse_args(['-b', '--barg'])
75 options.out == ['-b', '--barg']
78 def __init__(self
, option_strings
, dest
, **kwargs
):
80 raise ValueError('nargs is not supported for append_option action')
81 super().__init
__(option_strings
, dest
, nargs
=0, **kwargs
)
83 def __call__(self
, parser
, namespace
, values
, option_string
=None):
84 if getattr(namespace
, self
.dest
, None) is None:
85 setattr(namespace
, self
.dest
, [])
86 getattr(namespace
, self
.dest
).append(option_string
)
91 parser
= argparse
.ArgumentParser(description
=__doc__
)
93 '--catchup', action
='store_true',
94 help='run git-rb-catchup when rebasing')
96 '-q', '--quiet', dest
='git_options', action
=AppendOption
, default
=['-q'],
97 help='passthru to git rebase')
102 """The main entry point for scripts."""
103 parser
= get_parser()
104 opts
= parser
.parse_args(argv
)
106 # Skip if rebase is in progress.
107 if rebase_inprogress():
108 print(f
'{Color.BAD}{PROG}: skipping due to active rebase{Color.NORMAL}')
111 # Switch to the top dir in case the working dir doesn't exist in every branch.
112 topdir
= git(['rev-parse', '--show-toplevel']).stdout
.strip()
116 # ||m|refs/remotes/origin/master|ahead 2, behind 203
117 # *||master|refs/remotes/origin/master|ahead 1
118 # |/usr/local/src/gnu/gdb/build/release|release||behind 10
121 ['for-each-ref', '--format=%(HEAD)|%(worktreepath)|%(refname:short)|%(upstream)|%(upstream:track,nobracket)',
122 'refs/heads/*']).stdout
.splitlines()
127 head
, worktreepath
, branch
, tracking
, ahead_behind
= line
.split('|')
128 branch_width
= max(branch_width
, len(branch
))
132 print('Unable to resolve current branch', file=sys
.stderr
)
137 head
, worktreepath
, branch
, tracking
, ahead_behind
= line
.split('|')
139 # If it's a branch in another worktree, ignore it.
140 if worktreepath
and worktreepath
!= topdir
:
143 print(f
'{Color.BRACKET}### {Color.GOOD}{branch:{branch_width}}{Color.NORMAL} ',
146 print(f
'{Color.WARN}skipping{Color.NORMAL} due to missing merge branch')
149 m
= re
.match(r
'ahead ([0-9]+)', ahead_behind
)
150 ahead
= int(m
.group(1)) if m
else 0
151 m
= re
.search(r
'behind ([0-9]+)', ahead_behind
)
152 behind
= int(m
.group(1)) if m
else 0
157 git(['update-ref', f
'refs/heads/{branch}', tracking
])
158 print('fast forwarded')
161 print(f
'rebasing [{ahead_behind}] ', end
='', flush
=True)
162 git(['checkout', '-q', branch
])
165 result
= git(['rb-catchup'], capture_output
=False, check
=False)
167 result
= git(['rebase'] + opts
.git_options
, check
=False)
168 if result
.returncode
:
169 git(['rebase', '--abort'])
170 print(f
'{Color.BAD}failed{Color.NORMAL}\n' + result
.stdout
.strip())
174 git(['checkout', '-q', curr_state
])
178 if __name__
== '__main__':
179 sys
.exit(main(sys
.argv
[1:]))