Skip to content

Commit 0df19eb

Browse files
jerry-skydiogitster
authored andcommitted
builtin: patch-id: fix patch-id with binary diffs
"git patch-id" currently doesn't produce correct output if the incoming diff has any binary files. Add logic to get_one_patchid to handle the different possible styles of binary diff. This attempts to keep resulting patch-ids identical to what would be produced by the counterpart logic in diff.c, that is it produces the id by hashing the a and b oids in succession. In general we handle binary diffs by first caching the object ids from the "index" line and using those if we then find an indication that the diff is binary. The input could contain patches generated with "git diff --binary". This currently breaks the parse logic and results in multiple patch-ids output for a single commit. Here we have to skip the contents of the patch itself since those do not go into the patch id. --binary implies --full-index so the object ids are always available. When the diff is generated with --full-index there is no patch content to skip over. When a diff is generated without --full-index or --binary, it will contain abbreviated object ids. This will still result in a sufficiently unique patch-id when hashed, but does not match internal patch id output. We'll call this ok for now as we already need specialized arguments to diff in order to match internal patch id (namely -U3). Signed-off-by: Jerry Zhang <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 51276c1 commit 0df19eb

File tree

2 files changed

+62
-3
lines changed

2 files changed

+62
-3
lines changed

builtin/patch-id.c

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ static int get_one_patchid(struct object_id *next_oid, struct object_id *result,
6161
{
6262
int patchlen = 0, found_next = 0;
6363
int before = -1, after = -1;
64+
int diff_is_binary = 0;
65+
char pre_oid_str[GIT_MAX_HEXSZ + 1], post_oid_str[GIT_MAX_HEXSZ + 1];
6466
git_hash_ctx ctx;
6567

6668
the_hash_algo->init_fn(&ctx);
@@ -88,14 +90,44 @@ static int get_one_patchid(struct object_id *next_oid, struct object_id *result,
8890

8991
/* Parsing diff header? */
9092
if (before == -1) {
91-
if (starts_with(line, "index "))
93+
if (starts_with(line, "GIT binary patch") ||
94+
starts_with(line, "Binary files")) {
95+
diff_is_binary = 1;
96+
before = 0;
97+
the_hash_algo->update_fn(&ctx, pre_oid_str,
98+
strlen(pre_oid_str));
99+
the_hash_algo->update_fn(&ctx, post_oid_str,
100+
strlen(post_oid_str));
101+
if (stable)
102+
flush_one_hunk(result, &ctx);
92103
continue;
93-
else if (starts_with(line, "--- "))
104+
} else if (skip_prefix(line, "index ", &p)) {
105+
char *oid1_end = strstr(line, "..");
106+
char *oid2_end = NULL;
107+
if (oid1_end)
108+
oid2_end = strstr(oid1_end, " ");
109+
if (!oid2_end)
110+
oid2_end = line + strlen(line) - 1;
111+
if (oid1_end != NULL && oid2_end != NULL) {
112+
*oid1_end = *oid2_end = '\0';
113+
strlcpy(pre_oid_str, p, GIT_MAX_HEXSZ + 1);
114+
strlcpy(post_oid_str, oid1_end + 2, GIT_MAX_HEXSZ + 1);
115+
}
116+
continue;
117+
} else if (starts_with(line, "--- "))
94118
before = after = 1;
95119
else if (!isalpha(line[0]))
96120
break;
97121
}
98122

123+
if (diff_is_binary) {
124+
if (starts_with(line, "diff ")) {
125+
diff_is_binary = 0;
126+
before = -1;
127+
}
128+
continue;
129+
}
130+
99131
/* Looking for a valid hunk header? */
100132
if (before == 0 && after == 0) {
101133
if (starts_with(line, "@@ -")) {

t/t4204-patch-id.sh

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ calc_patch_id () {
4242
}
4343

4444
get_top_diff () {
45-
git log -p -1 "$@" -O bar-then-foo --
45+
git log -p -1 "$@" -O bar-then-foo --full-index --
4646
}
4747

4848
get_patch_id () {
@@ -61,6 +61,33 @@ test_expect_success 'patch-id detects inequality' '
6161
get_patch_id notsame &&
6262
! test_cmp patch-id_main patch-id_notsame
6363
'
64+
test_expect_success 'patch-id detects equality binary' '
65+
cat >.gitattributes <<-\EOF &&
66+
foo binary
67+
bar binary
68+
EOF
69+
get_patch_id main &&
70+
get_patch_id same &&
71+
git log -p -1 --binary main >top-diff.output &&
72+
calc_patch_id <top-diff.output main_binpatch &&
73+
git log -p -1 --binary same >top-diff.output &&
74+
calc_patch_id <top-diff.output same_binpatch &&
75+
test_cmp patch-id_main patch-id_main_binpatch &&
76+
test_cmp patch-id_same patch-id_same_binpatch &&
77+
test_cmp patch-id_main patch-id_same &&
78+
test_when_finished "rm .gitattributes"
79+
'
80+
81+
test_expect_success 'patch-id detects inequality binary' '
82+
cat >.gitattributes <<-\EOF &&
83+
foo binary
84+
bar binary
85+
EOF
86+
get_patch_id main &&
87+
get_patch_id notsame &&
88+
! test_cmp patch-id_main patch-id_notsame &&
89+
test_when_finished "rm .gitattributes"
90+
'
6491

6592
test_expect_success 'patch-id supports git-format-patch output' '
6693
get_patch_id main &&

0 commit comments

Comments
 (0)