From 72cf48414071636546eddfbfc828eda81649cb48 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sun, 26 Oct 2008 00:41:28 -0400 Subject: [PATCH 1/4] diff: add missing static declaration This function isn't used outside of diff.c; the 'static' was simply overlooked in the original writing. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- diff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/diff.c b/diff.c index e368fef14f..d1fd594ba3 100644 --- a/diff.c +++ b/diff.c @@ -1282,7 +1282,7 @@ static void emit_binary_diff(FILE *file, mmfile_t *one, mmfile_t *two) emit_binary_diff_body(file, two, one); } -void diff_filespec_load_driver(struct diff_filespec *one) +static void diff_filespec_load_driver(struct diff_filespec *one) { if (!one->driver) one->driver = userdiff_find_by_path(one->path); From 678852d918e874c99590ba6e857efeef974a3fb9 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sun, 26 Oct 2008 00:41:52 -0400 Subject: [PATCH 2/4] document the diff driver textconv feature This patch also changes the term "custom diff driver" to "external diff driver"; now that there are more facets of a "custom driver" than just external diffing, it makes sense to refer to the configuration of "diff.foo.*" as the "foo diff driver", with "diff.foo.command" as the "external driver for foo". Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- Documentation/gitattributes.txt | 66 ++++++++++++++++++++++++++------- 1 file changed, 53 insertions(+), 13 deletions(-) diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt index 26945593cb..314e2d32e5 100644 --- a/Documentation/gitattributes.txt +++ b/Documentation/gitattributes.txt @@ -213,10 +213,12 @@ with `crlf`, and then `ident` and fed to `filter`. Generating diff text ~~~~~~~~~~~~~~~~~~~~ -The attribute `diff` affects if 'git-diff' generates textual -patch for the path or just says `Binary files differ`. It also -can affect what line is shown on the hunk header `@@ -k,l +n,m @@` -line. +The attribute `diff` affects how 'git' generates diffs for particular +files. It can tell git whether to generate a textual patch for the path +or to treat the path as a binary file. It can also affect what line is +shown on the hunk header `@@ -k,l +n,m @@` line, tell git to use an +external command to generate the diff, or ask git to convert binary +files to a text format before generating the diff. Set:: @@ -227,7 +229,8 @@ Set:: Unset:: A path to which the `diff` attribute is unset will - generate `Binary files differ`. + generate `Binary files differ` (or a binary patch, if + binary patches are enabled). Unspecified:: @@ -238,21 +241,21 @@ Unspecified:: String:: - Diff is shown using the specified custom diff driver. - The driver program is given its input using the same - calling convention as used for GIT_EXTERNAL_DIFF - program. This name is also used for custom hunk header - selection. + Diff is shown using the specified diff driver. Each driver may + specify one or more options, as described in the following + section. The options for the diff driver "foo" are defined + by the configuration variables in the "diff.foo" section of the + git config file. -Defining a custom diff driver -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Defining an external diff driver +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The definition of a diff driver is done in `gitconfig`, not `gitattributes` file, so strictly speaking this manual page is a wrong place to talk about it. However... -To define a custom diff driver `jcdiff`, add a section to your +To define an external diff driver `jcdiff`, add a section to your `$GIT_DIR/config` file (or `$HOME/.gitconfig` file) like this: ---------------------------------------------------------------- @@ -328,6 +331,43 @@ patterns are available: - `tex` suitable for source code for LaTeX documents. +Performing text diffs of binary files +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Sometimes it is desirable to see the diff of a text-converted +version of some binary files. For example, a word processor +document can be converted to an ASCII text representation, and +the diff of the text shown. Even though this conversion loses +some information, the resulting diff is useful for human +viewing (but cannot be applied directly). + +The `textconv` config option is used to define a program for +performing such a conversion. The program should take a single +argument, the name of a file to convert, and produce the +resulting text on stdout. + +For example, to show the diff of the exif information of a +file instead of the binary information (assuming you have the +exif tool installed): + +------------------------ +[diff "jpg"] + textconv = exif +------------------------ + +NOTE: The text conversion is generally a one-way conversion; +in this example, we lose the actual image contents and focus +just on the text data. This means that diffs generated by +textconv are _not_ suitable for applying. For this reason, +only `git diff` and the `git log` family of commands (i.e., +log, whatchanged, show) will perform text conversion. `git +format-patch` will never generate this output. If you want to +send somebody a text-converted diff of a binary file (e.g., +because it quickly conveys the changes you have made), you +should generate it separately and send it as a comment _in +addition to_ the usual binary diff that you might send. + + Performing a three-way merge ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From df5e91fc2c95e051744ec9b9de66869d2b323037 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sun, 26 Oct 2008 00:42:25 -0400 Subject: [PATCH 3/4] add userdiff textconv tests These tests provide a basic sanity check that textconv'd files work. The tests try to describe how this configuration _should_ work; thus some of the tests are marked to expect failure. In particular, we fail to actually textconv anything because the 'diff.foo.binary' config option is not set, which will be fixed in the next patch. This also means that some "expect_failure" tests actually seem to be fixed; in reality, this is just because textconv is broken and its failure mode happens to make these tests work. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- t/t4030-diff-textconv.sh | 118 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100755 t/t4030-diff-textconv.sh diff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh new file mode 100755 index 0000000000..1b0964843e --- /dev/null +++ b/t/t4030-diff-textconv.sh @@ -0,0 +1,118 @@ +#!/bin/sh + +test_description='diff.*.textconv tests' +. ./test-lib.sh + +find_diff() { + sed '1,/^index /d' | sed '/^-- $/,$d' +} + +cat >expect.binary <<'EOF' +Binary files a/file and b/file differ +EOF + +cat >expect.text <<'EOF' +--- a/file ++++ b/file +@@ -1 +1,2 @@ + 0 ++1 +EOF + +cat >hexdump <<'EOF' +#!/bin/sh +perl -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' "$1" +EOF +chmod +x hexdump + +test_expect_success 'setup binary file with history' ' + printf "\\0\\n" >file && + git add file && + git commit -m one && + printf "\\1\\n" >>file && + git add file && + git commit -m two +' + +test_expect_success 'file is considered binary by porcelain' ' + git diff HEAD^ HEAD >diff && + find_diff actual && + test_cmp expect.binary actual +' + +test_expect_success 'file is considered binary by plumbing' ' + git diff-tree -p HEAD^ HEAD >diff && + find_diff actual && + test_cmp expect.binary actual +' + +test_expect_success 'setup textconv filters' ' + echo file diff=foo >.gitattributes && + git config diff.foo.textconv "$PWD"/hexdump && + git config diff.fail.textconv false +' + +test_expect_failure 'diff produces text' ' + git diff HEAD^ HEAD >diff && + find_diff actual && + test_cmp expect.text actual +' + +test_expect_success 'diff-tree produces binary' ' + git diff-tree -p HEAD^ HEAD >diff && + find_diff actual && + test_cmp expect.binary actual +' + +test_expect_failure 'log produces text' ' + git log -1 -p >log && + find_diff actual && + test_cmp expect.text actual +' + +test_expect_failure 'format-patch produces binary' ' + git format-patch --no-binary --stdout HEAD^ >patch && + find_diff actual && + test_cmp expect.binary actual +' + +cat >expect.stat <<'EOF' + file | Bin 2 -> 4 bytes + 1 files changed, 0 insertions(+), 0 deletions(-) +EOF +test_expect_failure 'diffstat does not run textconv' ' + echo file diff=fail >.gitattributes && + git diff --stat HEAD^ HEAD >actual && + test_cmp expect.stat actual +' +# restore working setup +echo file diff=foo >.gitattributes + +cat >expect.typechange <<'EOF' +--- a/file ++++ /dev/null +@@ -1,2 +0,0 @@ +-0 +-1 +diff --git a/file b/file +new file mode 120000 +index ad8b3d2..67be421 +--- /dev/null ++++ b/file +@@ -0,0 +1 @@ ++frotz +\ No newline at end of file +EOF +# make a symlink the hard way that works on symlink-challenged file systems +test_expect_failure 'textconv does not act on symlinks' ' + echo -n frotz > file && + git add file && + git ls-files -s | sed -e s/100644/120000/ | + git update-index --index-info && + git commit -m typechange && + git show >diff && + find_diff actual && + test_cmp expect.typechange actual +' + +test_done From 6ecfd91df5ec462aeded967c9ad21912c249f96e Mon Sep 17 00:00:00 2001 From: Brian Gernhardt Date: Fri, 31 Oct 2008 01:09:13 -0400 Subject: [PATCH 4/4] Avoid using non-portable `echo -n` in tests. Expecting echo to recognise -n is a BSDism. Using printf is far more portable. Discovered on OS X 10.5.5 in t4030-diff-textconv.sh and changed in all the test scripts. Signed-off-by: Brian Gernhardt Signed-off-by: Junio C Hamano --- t/t2005-checkout-index-symlinks.sh | 2 +- t/t2102-update-index-symlinks.sh | 4 ++-- t/t4030-diff-textconv.sh | 2 +- t/t6025-merge-symlinks.sh | 4 ++-- t/t9400-git-cvsserver-server.sh | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/t/t2005-checkout-index-symlinks.sh b/t/t2005-checkout-index-symlinks.sh index ed12c4d782..9fa5610474 100755 --- a/t/t2005-checkout-index-symlinks.sh +++ b/t/t2005-checkout-index-symlinks.sh @@ -13,7 +13,7 @@ file if core.symlinks is false.' test_expect_success \ 'preparation' ' git config core.symlinks false && -l=$(echo -n file | git hash-object -t blob -w --stdin) && +l=$(printf file | git hash-object -t blob -w --stdin) && echo "120000 $l symlink" | git update-index --index-info' test_expect_success \ diff --git a/t/t2102-update-index-symlinks.sh b/t/t2102-update-index-symlinks.sh index f195aefe3a..1ed44ee503 100755 --- a/t/t2102-update-index-symlinks.sh +++ b/t/t2102-update-index-symlinks.sh @@ -13,12 +13,12 @@ even if a plain file is in the working tree if core.symlinks is false.' test_expect_success \ 'preparation' ' git config core.symlinks false && -l=$(echo -n file | git hash-object -t blob -w --stdin) && +l=$(printf file | git hash-object -t blob -w --stdin) && echo "120000 $l symlink" | git update-index --index-info' test_expect_success \ 'modify the symbolic link' ' -echo -n new-file > symlink && +printf new-file > symlink && git update-index symlink' test_expect_success \ diff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh index 1b0964843e..3aed1bbdfe 100755 --- a/t/t4030-diff-textconv.sh +++ b/t/t4030-diff-textconv.sh @@ -105,7 +105,7 @@ index ad8b3d2..67be421 EOF # make a symlink the hard way that works on symlink-challenged file systems test_expect_failure 'textconv does not act on symlinks' ' - echo -n frotz > file && + printf frotz > file && git add file && git ls-files -s | sed -e s/100644/120000/ | git update-index --index-info && diff --git a/t/t6025-merge-symlinks.sh b/t/t6025-merge-symlinks.sh index 53892a555c..433c4de08f 100755 --- a/t/t6025-merge-symlinks.sh +++ b/t/t6025-merge-symlinks.sh @@ -18,11 +18,11 @@ git add file && git commit -m initial && git branch b-symlink && git branch b-file && -l=$(echo -n file | git hash-object -t blob -w --stdin) && +l=$(printf file | git hash-object -t blob -w --stdin) && echo "120000 $l symlink" | git update-index --index-info && git commit -m master && git checkout b-symlink && -l=$(echo -n file-different | git hash-object -t blob -w --stdin) && +l=$(printf file-different | git hash-object -t blob -w --stdin) && echo "120000 $l symlink" | git update-index --index-info && git commit -m b-symlink && git checkout b-file && diff --git a/t/t9400-git-cvsserver-server.sh b/t/t9400-git-cvsserver-server.sh index c1850d2923..6a37f71d11 100755 --- a/t/t9400-git-cvsserver-server.sh +++ b/t/t9400-git-cvsserver-server.sh @@ -424,7 +424,7 @@ cd "$WORKDIR" test_expect_success 'cvs update (-p)' ' touch really-empty && echo Line 1 > no-lf && - echo -n Line 2 >> no-lf && + printf "Line 2" >> no-lf && git add really-empty no-lf && git commit -q -m "Update -p test" && git push gitcvs.git >/dev/null &&