Skip to content

Commit ffd04e9

Browse files
j6tgitster
authored andcommitted
diff: don't attempt to strip prefix from absolute Windows paths
git diff can be invoked with absolute paths. Typically, this triggers the --no-index case. Then the absolute paths remain in the file names that are printed in the output. There is one peculiarity, though: When the command is invoked from a a sub-directory in a repository, then it is attempted to strip the sub-directory from the beginning of relative paths. Yet, to detect a relative path the code just checks for an initial forward slash. This mistakes a Windows style path like "D:/base" as a relative path and the output looks like this, for example: D:\dir\test\one>git -P diff --numstat D:\dir\base D:\dir\diff 1 1 ir/{base => diff}/1.txt where the correct output should be D:\dir\test\one>git -P diff --numstat D:\dir\base D:\dir\diff 1 1 D:/dir/{base => diff}/1.txt If the sub-directory where 'git diff' is invoked is sufficiently deep that the prefix becomes longer than the path to be printed, then the subsequent code accesses the path out of bounds. Use is_absolute_path() to detect Windows style absolute paths. One might wonder whether the check for a directory separator that is visible in the patch context should be changed from == '/' to is_dir_sep() or not. It turns out not to be necessary. That code only ever investigates paths that have undergone pathspec normalization, after which there are only forward slashes even on Windows. Signed-off-by: Johannes Sixt <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 27d05d1 commit ffd04e9

File tree

2 files changed

+12
-2
lines changed

2 files changed

+12
-2
lines changed

diff.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3958,12 +3958,12 @@ static void diff_fill_oid_info(struct diff_filespec *one)
39583958
static void strip_prefix(int prefix_length, const char **namep, const char **otherp)
39593959
{
39603960
/* Strip the prefix but do not molest /dev/null and absolute paths */
3961-
if (*namep && **namep != '/') {
3961+
if (*namep && !is_absolute_path(*namep)) {
39623962
*namep += prefix_length;
39633963
if (**namep == '/')
39643964
++*namep;
39653965
}
3966-
if (*otherp && **otherp != '/') {
3966+
if (*otherp && !is_absolute_path(*otherp)) {
39673967
*otherp += prefix_length;
39683968
if (**otherp == '/')
39693969
++*otherp;

t/t4053-diff-no-index.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,4 +127,14 @@ test_expect_success 'diff --no-index from repo subdir respects config (implicit)
127127
test_cmp expect actual.head
128128
'
129129

130+
test_expect_success 'diff --no-index from repo subdir with absolute paths' '
131+
cat <<-EOF >expect &&
132+
1 1 $(pwd)/non/git/{a => b}
133+
EOF
134+
test_expect_code 1 \
135+
git -C repo/sub diff --numstat \
136+
"$(pwd)/non/git/a" "$(pwd)/non/git/b" >actual &&
137+
test_cmp expect actual
138+
'
139+
130140
test_done

0 commit comments

Comments
 (0)