Skip to content

Commit 71b989e

Browse files
torvaldsspearce
authored andcommitted
fix bogus "diff --git" header from "diff --no-index"
When "git diff --no-index" is given an absolute pathname, it would generate a diff header with the absolute path prepended by the prefix, like: diff --git a/dev/null b/foo Not only is this nonsensical, and not only does it violate the description of diffs given in git-diff(1), but it would produce broken binary diffs. Unlike text diffs, the binary diffs don't contain the filenames anywhere else, and so "git apply" relies on this header to figure out the filename. This patch just refuses to use an invalid name for anything visible in the diff. Now, this fixes the "git diff --no-index --binary a /dev/null" kind of case (and we'll end up using "a" as the basename), but some other insane cases are impossible to handle. If you do git diff --no-index --binary a /bin/echo you'll still get a patch like diff --git a/a b/bin/echo old mode 100644 new mode 100755 index ... and "git apply" will refuse to apply it for a couple of reasons, and the diff is simply bogus. And that, btw, is no longer a bug, I think. It's impossible to know whethe the user meant for the patch to be a rename or not. And as such, refusing to apply it because you don't know what name you should use is probably _exactly_ the right thing to do! Original problem reported by Imre Deak. Test script and problem description by Jeff King. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
1 parent fe8aa14 commit 71b989e

File tree

2 files changed

+25
-0
lines changed

2 files changed

+25
-0
lines changed

diff.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1465,6 +1465,10 @@ static void builtin_diff(const char *name_a,
14651465
const char *set = diff_get_color_opt(o, DIFF_METAINFO);
14661466
const char *reset = diff_get_color_opt(o, DIFF_RESET);
14671467

1468+
/* Never use a non-valid filename anywhere if at all possible */
1469+
name_a = DIFF_FILE_VALID(one) ? name_a : name_b;
1470+
name_b = DIFF_FILE_VALID(two) ? name_b : name_a;
1471+
14681472
a_one = quote_two(o->a_prefix, name_a + (*name_a == '/'));
14691473
b_two = quote_two(o->b_prefix, name_b + (*name_b == '/'));
14701474
lbl[0] = DIFF_FILE_VALID(one) ? a_one : "/dev/null";

t/t4012-diff-binary.sh

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,25 @@ test_expect_success 'apply binary patch' \
7777
tree1=`git write-tree` &&
7878
test "$tree1" = "$tree0"'
7979

80+
q_to_nul() {
81+
perl -pe 'y/Q/\000/'
82+
}
83+
84+
nul_to_q() {
85+
perl -pe 'y/\000/Q/'
86+
}
87+
88+
test_expect_success 'diff --no-index with binary creation' '
89+
echo Q | q_to_nul >binary &&
90+
(:# hide error code from diff, which just indicates differences
91+
git diff --binary --no-index /dev/null binary >current ||
92+
true
93+
) &&
94+
rm binary &&
95+
git apply --binary <current &&
96+
echo Q >expected &&
97+
nul_to_q <binary >actual &&
98+
test_cmp expected actual
99+
'
100+
80101
test_done

0 commit comments

Comments
 (0)