combine-diff: handle binary files as binary

The combined diff code path is totally different from the
regular diff code path, and didn't handle binary files at
all. The results of a combined diff on a binary file could
range from annoying (since we spewed binary garbage,
possibly upsetting the user's terminal), to wrong (embedded
NULs caused us to show incorrect diffs, with lines truncated
at the NUL character), to potential security problems
(embedded NULs could interfere with "-z" output, possibly
defeating policy hooks which parse diff output).

Instead, we consider a combined diff to be binary if any of
the input blobs is binary. To show a binary combined diff,
we indicate "Binary blobs differ"; the "index" meta line
will show which parents had which blob.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Jeff King 2011-05-23 16:27:34 -04:00 коммит произвёл Junio C Hamano
Родитель c95b99bb5d
Коммит 4d5f347199
2 изменённых файлов: 148 добавлений и 2 удалений

Просмотреть файл

@ -7,6 +7,7 @@
#include "xdiff-interface.h"
#include "log-tree.h"
#include "refs.h"
#include "userdiff.h"
static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr, int n, int num_parent)
{
@ -685,7 +686,8 @@ static void show_combined_header(struct combine_diff_path *elem,
int num_parent,
int dense,
struct rev_info *rev,
int mode_differs)
int mode_differs,
int show_file_header)
{
struct diff_options *opt = &rev->diffopt;
int abbrev = DIFF_OPT_TST(opt, FULL_INDEX) ? 40 : DEFAULT_ABBREV;
@ -739,6 +741,9 @@ static void show_combined_header(struct combine_diff_path *elem,
printf("%s\n", c_reset);
}
if (!show_file_header)
return;
if (added)
dump_quoted_path("--- ", "", "/dev/null",
c_meta, c_reset);
@ -765,8 +770,13 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
int i, show_hunks;
int working_tree_file = is_null_sha1(elem->sha1);
mmfile_t result_file;
struct userdiff_driver *userdiff;
int is_binary;
context = opt->context;
userdiff = userdiff_find_by_path(elem->path);
if (!userdiff)
userdiff = userdiff_find_by_name("default");
/* Read the result of merge first */
if (!working_tree_file)
@ -852,6 +862,29 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
}
}
if (userdiff->binary != -1)
is_binary = userdiff->binary;
else {
is_binary = buffer_is_binary(result, result_size);
for (i = 0; !is_binary && i < num_parent; i++) {
char *buf;
unsigned long size;
buf = grab_blob(elem->parent[i].sha1,
elem->parent[i].mode,
&size);
if (buffer_is_binary(buf, size))
is_binary = 1;
free(buf);
}
}
if (is_binary) {
show_combined_header(elem, num_parent, dense, rev,
mode_differs, 0);
printf("Binary files differ\n");
free(result);
return;
}
for (cnt = 0, cp = result; cp < result + result_size; cp++) {
if (*cp == '\n')
cnt++;
@ -906,7 +939,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
if (show_hunks || mode_differs || working_tree_file) {
show_combined_header(elem, num_parent, dense, rev,
mode_differs);
mode_differs, 1);
dump_sline(sline, cnt, num_parent,
DIFF_OPT_TST(opt, COLOR_DIFF), result_deleted);
}

113
t/t4048-diff-combined-binary.sh Executable file
Просмотреть файл

@ -0,0 +1,113 @@
#!/bin/sh
test_description='combined and merge diff handle binary files and textconv'
. ./test-lib.sh
test_expect_success 'setup binary merge conflict' '
echo oneQ1 | q_to_nul >binary &&
git add binary &&
git commit -m one &&
echo twoQ2 | q_to_nul >binary &&
git commit -a -m two &&
git checkout -b branch-binary HEAD^ &&
echo threeQ3 | q_to_nul >binary &&
git commit -a -m three &&
test_must_fail git merge master &&
echo resolvedQhooray | q_to_nul >binary &&
git commit -a -m resolved
'
cat >expect <<'EOF'
resolved
diff --git a/binary b/binary
index 7ea6ded..9563691 100644
Binary files a/binary and b/binary differ
resolved
diff --git a/binary b/binary
index 6197570..9563691 100644
Binary files a/binary and b/binary differ
EOF
test_expect_success 'diff -m indicates binary-ness' '
git show --format=%s -m >actual &&
test_cmp expect actual
'
cat >expect <<'EOF'
resolved
diff --combined binary
index 7ea6ded,6197570..9563691
Binary files differ
EOF
test_expect_success 'diff -c indicates binary-ness' '
git show --format=%s -c >actual &&
test_cmp expect actual
'
cat >expect <<'EOF'
resolved
diff --cc binary
index 7ea6ded,6197570..9563691
Binary files differ
EOF
test_expect_success 'diff --cc indicates binary-ness' '
git show --format=%s --cc >actual &&
test_cmp expect actual
'
test_expect_success 'setup non-binary with binary attribute' '
git checkout master &&
test_commit one text &&
test_commit two text &&
git checkout -b branch-text HEAD^ &&
test_commit three text &&
test_must_fail git merge master &&
test_commit resolved text &&
echo text -diff >.gitattributes
'
cat >expect <<'EOF'
resolved
diff --git a/text b/text
index 2bdf67a..2ab19ae 100644
Binary files a/text and b/text differ
resolved
diff --git a/text b/text
index f719efd..2ab19ae 100644
Binary files a/text and b/text differ
EOF
test_expect_success 'diff -m respects binary attribute' '
git show --format=%s -m >actual &&
test_cmp expect actual
'
cat >expect <<'EOF'
resolved
diff --combined text
index 2bdf67a,f719efd..2ab19ae
Binary files differ
EOF
test_expect_success 'diff -c respects binary attribute' '
git show --format=%s -c >actual &&
test_cmp expect actual
'
cat >expect <<'EOF'
resolved
diff --cc text
index 2bdf67a,f719efd..2ab19ae
Binary files differ
EOF
test_expect_success 'diff --cc respects binary attribute' '
git show --format=%s --cc >actual &&
test_cmp expect actual
'
test_done