是否可以在 git diff 中配置临时文件夹?

Is it possible to configure the temp file folder in git diff?

在存储库中调用 git difftool 时,git 将本地存储库中的修改文件与远程存储库中的匹配项进行比较。为此,它会为遥控器创建一个临时文件,设置变量 LOCALREMOTE 并调用在 git 的配置中为差异指定的任何工具。

默认情况下,临时文件在 /tmp/<hash>_filename 中创建。 是否可以更改此默认位置?

你为什么要这么做?

长话短说,我通过 windows 子系统为 linux 使用 git,我想使用 windows 工具进行差异和合并。问题是,无法从 Windows 端访问 /tmp,因此我需要将 git 创建临时文件的默认位置移动到 Windows 可访问的位置。

我尝试了什么:

到目前为止,我能找到的只是对 sudo mount -B /tmp /mnt/c/tmp 的建议,但这似乎不起作用(/tmp 仍然指向与以前相同的目录...)

您可以尝试设置 TMPDIR 环境变量。

来自 POSIX 手册:

TMPDIR This variable shall represent a pathname of a directory made available for programs that need a place to create temporary files.


快速查看git代码后(git/builtin/difftool.c),我认为目前不支持配置临时目录:

/* Setup temp directories */
tmp = getenv("TMPDIR");
xsnprintf(tmpdir, sizeof(tmpdir), "%s/git-difftool.XXXXXX", tmp ? tmp : "/tmp");

似乎 git 正在采用 TMPDIR 值,或者 "/tmp",如果 TMPDIR 未定义。

同样的问题,解决方案不是通过更改 git 的临时目录,而是使用您可以定义的 diff 脚本:

  1. .gitconfig

    中定义差异脚本
    [diff]
    external = /home/user/scripts/my_diff.sh
    
  2. 创建脚本 /home/user/scripts/my_diff.sh 以使用 Windows 工具:

    #!/bin/bash
    FILE2="C:\dev\wsl\Debian\rootfs\${2//\//\}"
    FILE1=$(wslpath -w )
    /c/Program\ Files\ \(x86\)/WinMerge/WinMergeU.exe $FILE1 $FILE2
    

在我的示例中,我使用的是 WinMerge。
我知道这个解决方案违反了 Windows 工具不允许触摸 Linux 文件的规则,但我对此很好,因为我们正在谈论一个临时文件,我不明白这一点无论如何在 WinMerge 中更改它。 手动路径替换是必要的,因为 wslpath 不适用于 Linux 内部路径。

您的 WSL 可能不同,通常在某处

C:\Users\%username%\AppData\Local\Packages\TheDebianProject.DebianGNULinux_76v4gfsz19hv4\LocalState\rootfs

这感觉有点hacky,但我一直在使用它并且到目前为止很开心。

我在这里对这两种方法做了一个变体,供我自己使用。我创建了一个脚本,我调用它而不是 运行 git diff(更改 "twm" 路径,如果复制 - 那是我自己的用户目录):

#!/bin/bash                                                                     

export TMPDIR=$( realpath --relative-to=. /mnt/c/Users/twm/tmp )
git difftool -y -t winmerge "$@"

我专门针对 Git 运行 在 Linux 的 Windows 子系统中调用的 WinMerge。我在使用 TMPDIR 时遇到的问题是,当 Git 写入它时,WinMerge 无法识别临时路径,最初是因为它以“/mnt/c”开头 - 我确实得到了 WSL 之间匹配的路径和 Windows,除了领先的 "c:" 和 WinMerge 仍然无法识别它。但是,我注意到另一条路径被正确识别,并且 ps 显示它作为相对路径传递给 WinMerge,因此我也使用 realpath 使 TMPDIR 成为相对路径。

使用脚本在本地设置 TMPDIR 也解决了评论中提到的问题。也就是说,为这个用例更改所有其他程序的临时目录似乎有点矫枉过正,可能会产生一些意想不到的副作用。

就像此处列出的第二种方法一样,我也对 Git 别名进行了修改,试图让它发挥作用。但是,我想利用 Git 现有的 WinMerge 集成,以防内置集成现在或将来提供比硬编码脚本更多的功能。

将其放入 windows/HOME 目录中的 .gitconfig。 您需要为 cygpath(和 git)命令安装 cygwin 并在下面调整WinMerge的位置

[difftool "winmerge"]
         # Usage: git difftool --tool winmerge
        path = C:/bin/WinMergeU.exe
        cmd =  C:/bin/WinMergeU.exe \"$(cygpath -wam $LOCAL)\" \"$(cygpath -wam $REMOTE)\"

By default, the temporary file is created in /tmp/<hash>_filename.
Is it possible to change this default location?

不完全是,但是此默认位置已使用 Git 2.37(2022 年第 3 季度)进行了修改:提供给外部 diff 命令的临时文件现在在 new 中生成 相同基名下的临时目录。

参见 commit 8af7593, commit 2c2db19 (20 Apr 2022) by René Scharfe (rscharfe)
(由 Junio C Hamano -- gitster -- in commit 2e96975 合并,2022 年 5 月 20 日)

diff: use mks_tempfile_dt()

Signed-off-by: René Scharfe

Git uses temporary files to pass the contents of blobs to external diff programs and textconv filters.
It calls mks_tempfile_ts() to create them, which puts them all in the same directory.
This requires adding a random name prefix.

Use mks_tempfile_dt() instead, which allows the files to have arbitrary names, each in their own separate temporary directory.
This way they can have the same basename as the original blob, which looks nicer in graphical diff programs.

并且:

tempfile: add mks_tempfile_dt()

Signed-off-by: René Scharfe

Add a function to create a temporary file with a certain name in a temporary directory created using mkdtemp(3).
Its result is more sightly than the paths created by mks_tempfile_ts(), which include a random prefix.
That's useful for files passed to a program that displays their name, e.g. an external diff tool.