Subject: Re: git difftool: No such file or directory

From: Đoàn Trần Công Danh <[email-masked]>
Date: Thu, 1 Jul 2021 07:35:54 +0700

On 2021-06-30 11:38:21+0200, Alan Blotz <[email-masked]> wrote:

> Thank you for filling out a Git bug report!
> Please answer the following questions to help us understand your issue.
> 
> What did you do before the bug happened? (Steps to reproduce your issue)
> 
> mkdir broken-diff
> cd broken-diff
> git init
> mkdir dir1
> mkdir dir2
> touch dir1/orig
> cd dir2/
> ln -s ../dir1/orig sym
> cd ..
> git add dir*
> git ci -m "init"
> git checkout -b b
> git rm dir2/sym 
> git ci -m "remove"
> git difftool -d master HEAD
> 
> What did you expect to happen? (Expected behavior)
> 
> git difftool shall compare both branches.
> 
> What happened instead? (Actual behavior)
> 
> git difftool prints an error:
> 
> fatal: could not open '/tmp/git-difftool.l4UM7e/left/dir2/sym' for writing: No such file or directory

It looks like this behaviour was there from the time difftool was
re-written in C in 03831ef7b5, (difftool: implement the functionality
in the builtin, 2017-01-19). The perl version didn't have this
problem.

The perl version create a file in place of that symlink and write the
symlink's target into that file. The C version tries to write (and
follow?) the symlink.

This hack can fix the problem but I'm not sure it's correct:
----8<---

diff --git a/builtin/difftool.c b/builtin/difftool.c
index 2115e548a5..737ebb5b1a 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -492,12 +492,14 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 		if (*entry->left) {
 			add_path(&ldir, ldir_len, entry->path);
 			ensure_leading_directories(ldir.buf);
-			write_file(ldir.buf, "%s", entry->left);
+			unlink(ldir.buf);
+			write_file_buf(ldir.buf, entry->left, strlen(entry->left));
 		}
 		if (*entry->right) {
 			add_path(&rdir, rdir_len, entry->path);
 			ensure_leading_directories(rdir.buf);
-			write_file(rdir.buf, "%s", entry->right);
+			unlink(rdir.buf);
+			write_file_buf(rdir.buf, entry->right, strlen(entry->right));
 		}
 	}
---->8----- 

+Cc: Dscho, who wrote the C version.

-- 
Danh