-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathgit-retext
More file actions
executable file
·125 lines (100 loc) · 3.29 KB
/
git-retext
File metadata and controls
executable file
·125 lines (100 loc) · 3.29 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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#!/usr/bin/env python3
"""
Like git-rebase interactive, but instead of editing a script, you edit the
exported patches directly, which are presented in an email format.
You can edit the diff directly. For allowing this, this relies on
`recountdiff` to fix diff hunk header numbers. See `recountdiff` regarding the
editing of diffs.
"""
import sys
import os
import tempfile
import re
import subprocess
from optparse import OptionParser
def system(cmd):
return os.system(cmd)
class Abort(Exception): pass
def e_system(cmd):
r = system(cmd)
if r != 0:
raise Abort(f"command {cmd} failed: {r}");
C = re.compile("From ([a-f0-9]+) Mon Sep 17 00:00:00 2001")
def to_commits(content):
commits = []
githash = None
lines = []
for line in content.splitlines():
match = C.match(line)
if match:
if lines:
commits.append((githash, lines))
lines = []
githash = match.groups(0)[0]
lines.append(line)
if lines:
commits.append((githash, lines))
return commits
def error_msg(msg):
print('\u001b[31m', end='', file=sys.stderr)
print(msg, file=sys.stderr)
print('\u001b[0m', end='', file=sys.stderr)
sys.stderr.flush()
def main():
parser = OptionParser()
base = sys.argv[1]
ret = os.system("git status --porcelain")
if ret != 0:
print("There are uncommited changes", file=sys.stderr)
return
original = os.popen(f"git rev-parse HEAD").read().strip()
if original == "":
print("Unable to retrive original revision", file=sys.stderr)
return
rc = subprocess.call(['which', 'recountdiff'])
if rc != 0:
print('recountdiff missing in path!', file=sys.stderr)
return
e_system(f"git rev-parse {base} > /dev/null")
editor = os.popen("git config core.editor").read().strip()
if not editor:
editor = os.getenv("EDITOR", "vi")
filename = tempfile.mktemp("git-retext.diff")
pipe = os.popen(f"git format-patch --no-signature --stdout {base}..", "r")
before_edit = pipe.read()
fobj = open(filename, "w")
fobj.write(before_edit)
fobj.close()
rcode = os.system(f"{editor} {filename}")
success = False
try:
if rcode == 0:
after_edit = open(filename, "r").read()
new_data = []
for (_, lines) in to_commits(after_edit):
fobj = open(filename, "w")
fobj.write("\n".join(lines))
fobj.close()
pipe = os.popen(f"recountdiff {filename}")
fixed = pipe.read() + "\n"
ret = pipe.close()
if ret:
error_msg("recountdiff returned error")
new_data.append(fixed)
fobj = open(filename, "w")
for data in new_data:
fobj.write(data)
fobj.close()
e_system(f"git reset --hard {base}")
e_system(f"git am < {filename}")
success = True
finally:
os.unlink(filename)
if not success:
error_msg("Not successful, reverting to original")
sys.stderr.flush()
system(f"git am --abort")
e_system(f"git reset --hard {original}")
sys.exit(1)
if __name__ == "__main__":
main()