Skip to content

Commit 580fb25

Browse files
bonzinigitster
authored andcommitted
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 9ae144f commit 580fb25

File tree

2 files changed

+90
-6
lines changed

2 files changed

+90
-6
lines changed

builtin/patch-id.c

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,40 @@ static int remove_space(char *line)
2828
return dst - line;
2929
}
3030

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+
3160
int get_one_patchid(unsigned char *next_sha1, git_SHA_CTX *ctx)
3261
{
3362
static char line[1000];
3463
int patchlen = 0, found_next = 0;
64+
int before = -1, after = -1;
3565

3666
while (fgets(line, sizeof(line), stdin) != NULL) {
3767
char *p = line;
@@ -41,6 +71,8 @@ int get_one_patchid(unsigned char *next_sha1, git_SHA_CTX *ctx)
4171
p += 10;
4272
else if (!memcmp(line, "commit ", 7))
4373
p += 7;
74+
else if (!memcmp(line, "From ", 5))
75+
p += 5;
4476

4577
if (!get_sha1_hex(p, next_sha1)) {
4678
found_next = 1;
@@ -51,13 +83,37 @@ int get_one_patchid(unsigned char *next_sha1, git_SHA_CTX *ctx)
5183
if (!patchlen && memcmp(line, "diff ", 5))
5284
continue;
5385

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+
}
5795

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--;
61117

62118
/* Compute the sha without whitespace */
63119
len = remove_space(line);

t/t4204-patch-id.sh

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ test_expect_success 'patch-id output is well-formed' '
1818
grep "^[a-f0-9]\{40\} $(git rev-parse HEAD)$" output
1919
'
2020

21+
calc_patch_id () {
22+
git patch-id |
23+
sed "s# .*##" > patch-id_"$1"
24+
}
25+
2126
get_patch_id () {
2227
git log -p -1 "$1" | git patch-id |
2328
sed "s# .*##" > patch-id_"$1"
@@ -35,4 +40,27 @@ test_expect_success 'patch-id detects inequality' '
3540
! test_cmp patch-id_master patch-id_notsame
3641
'
3742

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+
3866
test_done

0 commit comments

Comments
 (0)