patch-id: Add support for mbox format
I have an alias that takes two arguments and compares their patch IDs. I would like to use to make sure I've tested exactly what I submit (patch by patch), like git patch-cmp origin/master.. file-being-sent However, I cannot do that because git patch-id is fooled by the "-- " trailer that git format-patch puts, or likely by the MIME boundary. This patch adds hunk parsing logic to git patch-id in order to detect an out of place "-" line and split the patch when it comes. In addition, commit ids in the "From " lines are considered and printed in the output. Signed-off-by: Paolo Bonzini <bonzini@gnu.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Paolo Bonzini committed
Apr 19, 2010 at 10:46 UTC
580fb25b7a941267aad747afdc74b9b4a42e154a
2 files changed
+90
-6
builtin/patch-id.c
+62
-6
@@ -28,10 +28,40 @@ static int remove_space(char *line)
28
return dst - line;
29
}
30
31
+static int scan_hunk_header(const char *p, int *p_before, int *p_after)
32
+{
33
+ static const char digits[] = "0123456789";
34
+ const char *q, *r;
35
+ int n;
36
+
37
+ q = p + 4;
38
+ n = strspn(q, digits);
39
+ if (q[n] == ',') {
40
+ q += n + 1;
41
+ n = strspn(q, digits);
42
+ }
43
+ if (n == 0 || q[n] != ' ' || q[n+1] != '+')
44
+ return 0;
45
+
46
+ r = q + n + 2;
47
+ n = strspn(r, digits);
48
+ if (r[n] == ',') {
49
+ r += n + 1;
50
+ n = strspn(r, digits);
51
+ }
52
+ if (n == 0)
53
+ return 0;
54
+
55
+ *p_before = atoi(q);
56
+ *p_after = atoi(r);
57
+ return 1;
58
+}
59
+
60
int get_one_patchid(unsigned char *next_sha1, git_SHA_CTX *ctx)
61
{
62
static char line[1000];
63
int patchlen = 0, found_next = 0;
64
+ int before = -1, after = -1;
65
66
while (fgets(line, sizeof(line), stdin) != NULL) {
67
char *p = line;
@@ -41,6 +71,8 @@ int get_one_patchid(unsigned char *next_sha1, git_SHA_CTX *ctx)
71
p += 10;
72
else if (!memcmp(line, "commit ", 7))
73
p += 7;
74
+ else if (!memcmp(line, "From ", 5))
75
+ p += 5;
76
77
if (!get_sha1_hex(p, next_sha1)) {
78
found_next = 1;
@@ -51,13 +83,37 @@ int get_one_patchid(unsigned char *next_sha1, git_SHA_CTX *ctx)
83
if (!patchlen && memcmp(line, "diff ", 5))
84
continue;
85
54
- /* Ignore git-diff index header */
55
- if (!memcmp(line, "index ", 6))
56
- continue;
86
+ /* Parsing diff header? */
87
+ if (before == -1) {
88
+ if (!memcmp(line, "index ", 6))
89
+ continue;
90
+ else if (!memcmp(line, "--- ", 4))
91
+ before = after = 1;
92
+ else if (!isalpha(line[0]))
93
+ break;
94
+ }
95
58
- /* Ignore line numbers when computing the SHA1 of the patch */
59
- if (!memcmp(line, "@@ -", 4))
60
- continue;
96
+ /* Looking for a valid hunk header? */
97
+ if (before == 0 && after == 0) {
98
+ if (!memcmp(line, "@@ -", 4)) {
99
+ /* Parse next hunk, but ignore line numbers. */
100
+ scan_hunk_header(line, &before, &after);
101
+ continue;
102
+ }
103
+
104
+ /* Split at the end of the patch. */
105
+ if (memcmp(line, "diff ", 5))
106
+ break;
107
+
108
+ /* Else we're parsing another header. */
109
+ before = after = -1;
110
+ }
111
+
112
+ /* If we get here, we're inside a hunk. */
113
+ if (line[0] == '-' || line[0] == ' ')
114
+ before--;
115
+ if (line[0] == '+' || line[0] == ' ')
116
+ after--;
117
118
/* Compute the sha without whitespace */
119
len = remove_space(line);
t/t4204-patch-id.sh
+28
@@ -18,6 +18,11 @@ test_expect_success 'patch-id output is well-formed' '
18
grep "^[a-f0-9]\{40\} $(git rev-parse HEAD)$" output
19
'
20
21
+calc_patch_id () {
22
+ git patch-id |
23
+ sed "s# .*##" > patch-id_"$1"
24
+}
25
+
26
get_patch_id () {
27
git log -p -1 "$1" | git patch-id |
28
sed "s# .*##" > patch-id_"$1"
@@ -35,4 +40,27 @@ test_expect_success 'patch-id detects inequality' '
40
! test_cmp patch-id_master patch-id_notsame
41
'
42
43
+test_expect_success 'patch-id supports git-format-patch output' '
44
+ get_patch_id master &&
45
+ git checkout same &&
46
+ git format-patch -1 --stdout | calc_patch_id same &&
47
+ test_cmp patch-id_master patch-id_same &&
48
+ set `git format-patch -1 --stdout | git patch-id` &&
49
+ test "$2" = `git rev-parse HEAD`
50
+'
51
+
52
+test_expect_success 'whitespace is irrelevant in footer' '
53
+ get_patch_id master &&
54
+ git checkout same &&
55
+ git format-patch -1 --stdout | sed "s/ \$//" | calc_patch_id same &&
56
+ test_cmp patch-id_master patch-id_same
57
+'
58
+
59
+test_expect_success 'patch-id supports git-format-patch MIME output' '
60
+ get_patch_id master &&
61
+ git checkout same &&
62
+ git format-patch -1 --attach --stdout | calc_patch_id same &&
63
+ test_cmp patch-id_master patch-id_same
64
+'
65
+
66
test_done