git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: git difftool: No such file or directory

From
David Aguilar <davvid@gmail.com>
Date
Aug 30, 2021, 00:32 UTC
Message-ID
<CAJDDKr6Z9E6MbQReTXtF3k9V8YJ-mv9swgsazdD0eeAA35UY0A@mail.gmail.com>
In-Reply-To
<YN0N6tUeSJM1EBHD@danh.dev>

On Wed, Jun 30, 2021 at 5:38 PM Đoàn Trần Công Danh <congdanhqx@gmail.com> wrote:

Show 69 quoted lines
>
> On 2021-06-30 11:38:21+0200, Alan Blotz <work@blotz.org> 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.
Thank you for tracking this down!

I re-read the original perl version and this indeed looks like it should do the trick since it's doing the same thing we did in perl.

I'm a little ashamed that we didn't have a test case to cover this use case but the reproduction recipe you included looks like a great start. We already have a few tests that use the SYMLINKS test prereq so this would slot in well there.

-- 
David
Previous: Đoàn Trần Công Danh
Message 3 of 3 in “git difftool: No such file or directory”
  1. Alan BlotzJun 30, 2021
  2. Đoàn Trần Công DanhJul 1, 2021
  3. David AguilarAug 30, 2021

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.