git diff -D: omit the preimage of deletes

When reviewing a patch while concentrating primarily on the text after
then change, wading through pages of deleted text involves a cognitive
burden.

Introduce the -D option that omits the preimage text from the patch output
for deleted files.  When used with -B (represent total rewrite as a single
wholesale deletion followed by a single wholesale addition), the preimage
text is also omitted.

To prevent such a patch from being applied by mistake, the output is
designed not to be usable by "git apply" (or GNU "patch"); it is strictly
for human consumption.

It of course is possible to "apply" such a patch by hand, as a human can
read the intention out of such a patch.  It however is impossible to apply
such a patch even manually in reverse, as the whole point of this option
is to omit the information necessary to do so from the output.

Initial request by Mart Sõmermaa, documentation and tests helped by
Michael J Gruber.

Signed-off-by: Michael J Gruber <git@drmicha.warpmail.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Junio C Hamano 2011-02-28 16:11:55 -08:00
parent afb0b7933f
commit 467ddc14fe
4 changed files with 70 additions and 6 deletions

View File

@ -259,6 +259,19 @@ endif::git-log[]
projects, so use it with caution. Giving more than one
`-C` option has the same effect.
-D::
--irreversible-delete::
Omit the preimage for deletes, i.e. print only the header but not
the diff between the preimage and `/dev/null`. The resulting patch
is not meant to be applied with `patch` nor `git apply`; this is
solely for people who want to just concentrate on reviewing the
text after the change. In addition, the output obviously lack
enough information to apply such a patch in reverse, even manually,
hence the name of the option.
+
When used together with `-B`, omit also the preimage in the deletion part
of a delete/create pair.
-l<num>::
The `-M` and `-C` options require O(n^2) processing time where n
is the number of potential rename/copy targets. This

19
diff.c
View File

@ -572,11 +572,14 @@ static void emit_rewrite_diff(const char *name_a,
line_prefix, metainfo, a_name.buf, name_a_tab, reset,
line_prefix, metainfo, b_name.buf, name_b_tab, reset,
line_prefix, fraginfo);
print_line_count(o->file, lc_a);
if (!o->irreversible_delete)
print_line_count(o->file, lc_a);
else
fprintf(o->file, "?,?");
fprintf(o->file, " +");
print_line_count(o->file, lc_b);
fprintf(o->file, " @@%s\n", reset);
if (lc_a)
if (lc_a && !o->irreversible_delete)
emit_rewrite_lines(&ecbdata, '-', data_one, size_one);
if (lc_b)
emit_rewrite_lines(&ecbdata, '+', data_two, size_two);
@ -1943,7 +1946,11 @@ static void builtin_diff(const char *name_a,
}
}
if (!DIFF_OPT_TST(o, TEXT) &&
if (o->irreversible_delete && lbl[1][0] == '/') {
fprintf(o->file, "%s", header.buf);
strbuf_reset(&header);
goto free_ab_and_return;
} else if (!DIFF_OPT_TST(o, TEXT) &&
( (!textconv_one && diff_filespec_is_binary(one)) ||
(!textconv_two && diff_filespec_is_binary(two)) )) {
if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
@ -1963,8 +1970,7 @@ static void builtin_diff(const char *name_a,
fprintf(o->file, "%sBinary files %s and %s differ\n",
line_prefix, lbl[0], lbl[1]);
o->found_changes = 1;
}
else {
} else {
/* Crazy xdl interfaces.. */
const char *diffopts = getenv("GIT_DIFF_OPTS");
xpparam_t xpp;
@ -3160,6 +3166,9 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
return error("invalid argument to -M: %s", arg+2);
options->detect_rename = DIFF_DETECT_RENAME;
}
else if (!strcmp(arg, "-D") || !strcmp(arg, "--irreversible-delete")) {
options->irreversible_delete = 1;
}
else if (!prefixcmp(arg, "-C") || !prefixcmp(arg, "--find-copies=") ||
!strcmp(arg, "--find-copies")) {
if (options->detect_rename == DIFF_DETECT_COPY)

1
diff.h
View File

@ -104,6 +104,7 @@ struct diff_options {
int interhunkcontext;
int break_opt;
int detect_rename;
int irreversible_delete;
int skip_stat_unmatch;
int line_termination;
int output_format;

View File

@ -11,7 +11,9 @@ test_expect_success setup '
tr \
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" \
"nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM" \
<"$TEST_DIRECTORY"/../COPYING >test
<"$TEST_DIRECTORY"/../COPYING >test &&
echo "to be deleted" >test2 &&
git add test2
'
@ -25,5 +27,44 @@ test_expect_success 'detect rewrite' '
'
cat >expect <<EOF
diff --git a/test2 b/test2
deleted file mode 100644
index 4202011..0000000
--- a/test2
+++ /dev/null
@@ -1 +0,0 @@
-to be deleted
EOF
test_expect_success 'show deletion diff without -D' '
rm test2 &&
git diff -- test2 >actual &&
test_cmp expect actual
'
cat >expect <<EOF
diff --git a/test2 b/test2
deleted file mode 100644
index 4202011..0000000
EOF
test_expect_success 'suppress deletion diff with -D' '
git diff -D -- test2 >actual &&
test_cmp expect actual
'
test_expect_success 'show deletion diff with -B' '
git diff -B -- test >actual &&
grep "Linus Torvalds" actual
'
test_expect_success 'suppress deletion diff with -B -D' '
git diff -B -D -- test >actual &&
grep -v "Linus Torvalds" actual
'
test_done