diff: strip extra "/" when stripping prefix

There are two ways a user might want to use "diff --relative":

  1. For a file in a directory, like "subdir/file", the user
     can use "--relative=subdir/" to strip the directory.

  2. To strip part of a filename, like "foo-10", they can
     use "--relative=foo-".

We currently handle both of those situations. However, if the user passes
"--relative=subdir" (without the trailing slash), we produce inconsistent
results. For the unified diff format, we collapse the double-slash of
"a//file" correctly into "a/file". But for other formats (raw, stat,
name-status), we end up with "/file".

We can do what the user means here and strip the extra "/" (and only a
slash).  We are not hurting any existing users of (2) above with this
behavior change because the existing output for this case was nonsensical.

Patch by Jakub, tests and commit message by Jeff King.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Jakub Narebski 2010-08-09 10:50:53 -04:00 committed by Junio C Hamano
parent 497d9c3439
commit d8faea9d18
2 changed files with 69 additions and 2 deletions

10
diff.c
View File

@ -2704,10 +2704,16 @@ static void diff_fill_sha1_info(struct diff_filespec *one)
static void strip_prefix(int prefix_length, const char **namep, const char **otherp)
{
/* Strip the prefix but do not molest /dev/null and absolute paths */
if (*namep && **namep != '/')
if (*namep && **namep != '/') {
*namep += prefix_length;
if (*otherp && **otherp != '/')
if (**namep == '/')
++*namep;
}
if (*otherp && **otherp != '/') {
*otherp += prefix_length;
if (**otherp == '/')
++*otherp;
}
}
static void run_diff(struct diff_filepair *p, struct diff_options *o)

61
t/t4045-diff-relative.sh Executable file
View File

@ -0,0 +1,61 @@
#!/bin/sh
test_description='diff --relative tests'
. ./test-lib.sh
test_expect_success 'setup' '
git commit --allow-empty -m empty &&
echo content >file1 &&
mkdir subdir &&
echo other content >subdir/file2 &&
git add . &&
git commit -m one
'
check_diff() {
expect=$1; shift
cat >expected <<EOF
diff --git a/$expect b/$expect
new file mode 100644
index 0000000..25c05ef
--- /dev/null
+++ b/$expect
@@ -0,0 +1 @@
+other content
EOF
test_expect_success "-p $*" "
git diff -p $* HEAD^ >actual &&
test_cmp expected actual
"
}
check_stat() {
expect=$1; shift
cat >expected <<EOF
$expect | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
EOF
test_expect_success "--stat $*" "
git diff --stat $* HEAD^ >actual &&
test_cmp expected actual
"
}
check_raw() {
expect=$1; shift
cat >expected <<EOF
:000000 100644 0000000000000000000000000000000000000000 25c05ef3639d2d270e7fe765a67668f098092bc5 A $expect
EOF
test_expect_success "--raw $*" "
git diff --no-abbrev --raw $* HEAD^ >actual &&
test_cmp expected actual
"
}
for type in diff stat raw; do
check_$type file2 --relative=subdir/
check_$type file2 --relative=subdir
check_$type dir/file2 --relative=sub
done
test_done