-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgit-wip
More file actions
executable file
·109 lines (96 loc) · 3.76 KB
/
git-wip
File metadata and controls
executable file
·109 lines (96 loc) · 3.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#!/usr/bin/env -S uv --quiet run --no-project --script --
# https://peps.python.org/pep-0723/
# https://github.com/astral-sh/uv
# /// script
# # Docopt issues SyntaxWarning in Python 3.12
# requires-python = ">=3.11,<3.12"
# dependencies = [
# "docopt >=0.6.2",
# ]
# ///
"""
Usage:
{prog} new NEW_WIP_BRANCH_NAME [UPSTREAM_BRANCH_NAME [STARTING_POINT]]
{prog} rebase WIP_BRANCH_NAME
"""
import sys, locale, os, subprocess as sp
import docopt
def main(*, args, prog):
locale.setlocale(locale.LC_ALL, "")
params = docopt.docopt(
__doc__.replace("\t", " " * 4).format(prog=os.path.basename(prog)),
argv=args,
help=True,
version=True,
options_first=False
)
verb = None
if params.pop("new", None):
verb = "new"
wip_branch = params.pop("NEW_WIP_BRANCH_NAME")
upstream_branch = params.pop("UPSTREAM_BRANCH_NAME") or git("config", "--get", "wip.defaultUpstream", stdout=sp.PIPE).stdout.strip()
starting_point = params.pop("STARTING_POINT") or upstream_branch
assert params.pop("WIP_BRANCH_NAME") is None
assert params.pop("rebase") == False
elif params.pop("rebase", None):
verb = "rebase"
wip_branch = params.pop("WIP_BRANCH_NAME")
assert params.pop("NEW_WIP_BRANCH_NAME") is None
assert params.pop("UPSTREAM_BRANCH_NAME") is None
assert params.pop("STARTING_POINT") is None
assert not params, params
wip_branch = wip_branch \
.removeprefix("wip/") \
.removeprefix("heads/wip/") \
.removeprefix("refs/heads/wip/")
if verb == "new":
try:
git("update-ref", "--create-reflog", "--stdin", "-z", input=(
"start\0"
f"create refs/heads/wip/{wip_branch}/head\0{starting_point}\0"
f"create refs/heads/wip/{wip_branch}/base\0{upstream_branch}\0"
f"create refs/heads/wip/{wip_branch}/dest\0{upstream_branch}\0"
"prepare\0"
"commit\0"
))
git("branch", f"wip/{wip_branch}/head", "--set-upstream-to", f"wip/{wip_branch}/base")
git("branch", f"wip/{wip_branch}/base", "--set-upstream-to", f"wip/{wip_branch}/dest")
git("branch", f"wip/{wip_branch}/dest", "--set-upstream-to", f"{upstream_branch}")
except sp.CalledProcessError as e:
print(repr(e.cmd), ": ", e.returncode, sep="", file=sys.stderr)
elif verb == "rebase":
assert not git("status", "--porcelain=v2", stdout=sp.PIPE).stdout
print(f"Detaching HEAD from {wip_branch!r}")
git("switch", "--detach", f"refs/heads/wip/{wip_branch}/head")
print(f"Rebasing: from base of {wip_branch!r} to HEAD onto dest of {wip_branch!r}.")
git("rebase", f"refs/heads/wip/{wip_branch}/base", "HEAD", "--onto", f"refs/heads/wip/{wip_branch}/dest") #TODO:vruyr This could fail because of conflicts.
patchid_old = git("patch-id", input=git("diff", f"refs/heads/wip/{wip_branch}/base", f"refs/heads/wip/{wip_branch}/head", "--", stdout=sp.PIPE).stdout, stdout=sp.PIPE).stdout.strip()
patchid_new = git("patch-id", input=git("diff", f"refs/heads/wip/{wip_branch}/dest", f"HEAD", "--", stdout=sp.PIPE).stdout, stdout=sp.PIPE).stdout.strip()
assert patchid_old == patchid_new, (patchid_old, patchid_new) #TODO:vruyr This could fail because of conflict resolution.
print(f"Updating head of {wip_branch!r}")
git("fetch", ".", f"+HEAD:refs/heads/wip/{wip_branch}/head")
print(f"Updating base of {wip_branch!r}")
git("fetch", ".", f"+refs/heads/wip/{wip_branch}/dest:refs/heads/wip/{wip_branch}/base")
print(f"Switching to branch {wip_branch!r}")
git("switch", f"wip/{wip_branch}/head")
def git(*args, **kwargs):
cmd = ["git", *args]
return sp.run(
cmd,
shell=False,
check=kwargs.pop("check", True),
encoding=kwargs.pop("encoding", "UTF-8"),
**kwargs,
)
def smain(argv=None):
if argv is None:
argv = sys.argv
try:
return main(
args=argv[1:],
prog=argv[0]
)
except KeyboardInterrupt:
print(file=sys.stderr)
if __name__ == "__main__":
sys.exit(smain())