14

当我执行 agit difftool时,Kaleidoscope会在左侧边栏中显示所有已更改的文件:


(来源:kaleidoscopeapp.com

Windows 中是否有任何差异工具可以显示这样的文件列表?

(我不希望该工具在单独的窗口中同时打开所有文件。我正在寻找一个窗口来显示已更改文件的列表,并且我应该能够单击特定文件查看它的差异,如万花筒屏幕截图所示)

4

1 回答 1

12

You can use git difftool in a way which lists all the files (git1.8+ recommended):

git difftool --dir-diff

Copy the modified files to a temporary location and perform a directory diff on them.
This mode never prompts before launching the diff tool.

You can then integrate it with a BeyondCompare for instance.

Or with WinMerge:

[diff]
    tool = winmerge
[difftool "winmerge"]
    path = C:/Program Files (x86)/WinMerge/winmergeu.exe
    cmd = \"C:/Program Files (x86)/WinMerge/winmergeu.exe\" -r -u \"$LOCAL\" \"$REMOTE\"

All that with:

    $ git difftool [<commit> [<commit>]]

The only problem is the git diff-tool, on Windows, is described in this blog post, by nitoyon.

On Unix and MacOS, git difftool --dir-diff create a symbolic link to the working directory if a right-hand file has the same SHA1 as the file in the working directory. It's very useful when we modify right-hand files with a difftool.

On Windows, instead of creating symbolic links, git difftool --dir-diff copy back right-hand files to working directory after difftool program exits. I want to use symlinks on Git for Windows like Unix and MacOS.

Note: On Windows, administrator privileges is required to create symbolic links.

Run GitBash as an administrator, and enter following command.

$ git difftool -d --symlinks [<commit> [<commit>]]

If you want, create an alias on .gitconfig.

[alias]
    d = difftool -d --symlinks

But that requires:

  • to create a git mklink command:
C:\Program Files (x86)\Git\libexec\git-core\git-mklink:

#!/bin/sh

cmd.exe /c "mklink \"$2\" \"$1\"" > /dev/null
  • to patch msysgit 1.8.3:
cd /c/Program\ Files\ \(x86\)/Git/libexec/git-core/
$ patch < ~/git-difftool.patch

With git-difftool.patch:

    --- git-difftool    Sun Jun  2 11:28:06 2013
    +++ git-difftool    Tue Jul  9 00:42:02 2013
    @@ -283,7 +283,7 @@
                exit_cleanup($tmpdir, 1);
            }
            if ($symlinks) {
    -           symlink("$workdir/$file", "$rdir/$file") or
    +           !system("git", "mklink", "$workdir/$file", "$rdir/$file") or
                exit_cleanup($tmpdir, 1);
            } else {
                copy("$workdir/$file", "$rdir/$file") or
    @@ -448,7 +448,7 @@
        my $indices_loaded = 0;
    
        for my $file (@worktree) {
    -       next if $symlinks && -l "$b/$file";
    +       next if $symlinks;
            next if ! -f "$b/$file";
    
            if (!$indices_loaded) {

Before Git 2.34 (Q4 2021), "git difftool --dir-diff"(man) mishandled symbolic links.

See commit 5bafb35 (22 Sep 2021) by David Aguilar (davvid).
(Merged by Junio C Hamano -- gitster -- in commit 6a4f5da, 03 Oct 2021)

difftool: fix symlink-file writing in dir-diff mode

Reported-by: Alan Blotz
Helped-by: Đoàn Trần Công Danh
Signed-off-by: David Aguilar

The difftool dir-diff mode handles symlinks by replacing them with their readlink(2) values.
This allows diff tools to see changes to symlinks as if they were regular text diffs with the old and new path values.
This is analogous to what "git diff"(man) displays when symlinks change.

The temporary diff directories that are created initially contain symlinks because they get checked-out using a temporary index that retains the original symlinks as checked-in to the repository.

A bug was introduced when difftool was rewritten in C that made difftool write the readlink(2) contents into the pointed-to file rather than the symlink itself.
The write was going through the symlink and writing to its target rather than writing to the symlink path itself.

Replace symlinks with raw text files by unlinking the symlink path before writing the readlink(2) content into them.

When 18ec800 ("difftool: handle modified symlinks in dir-diff mode", 2017-03-15, Git v2.13.0-rc0 -- merge listed in batch #6) added handling for modified symlinks this bug got recorded in the test suite.
The tests included the pointed-to symlink target paths.
These paths were being reported because difftool was erroneously writing to them, but they should have never been reported nor written.

Correct the modified-symlinks test cases by removing the target files from the expected output.

And, still Git 2.34:

See commit 28c10ec, commit 8e2af8f, commit 2255c80, commit 4ac9f15 (30 Sep 2021) by David Aguilar (davvid).
See commit 77bd616 (23 Sep 2021), and commit 93a8ed2 (20 Sep 2021) by Junio C Hamano (gitster).
(Merged by Junio C Hamano -- gitster -- in commit 0cc4ec1, 11 Oct 2021)

difftool: refactor dir-diff to write files using helper functions

Signed-off-by: David Aguilar

Add a helpers function to handle the unlinking and writing of the dir-diff submodule and symlink stand-in files.

Use the helpers to implement the guts of the hashmap loops.
This eliminate duplicate code and safeguards the submodules hashmap loop against the symlink-chasing behavior that 5bafb35 ("difftool: fix symlink-file writing in dir-diff mode", 2021-09-22, Git v2.34.0 -- merge listed in batch #10) addressed.

The submodules loop should not strictly require the unlink() call that this is introducing to them, but it does not necessarily hurt them either beyond the cost of the extra unlink().

/* Write the file contents for the left and right sides of the difftool
 * dir-diff representation for submodules and symlinks. Symlinks and submodules
 * are written as regular text files so that external diff tools can diff them
 * as text files, resulting in behavior that is analogous to to what "git diff"
 * displays for symlink and submodule diffs.
 */
static void write_standin_files() {...}
于 2013-07-19T06:53:42.573 回答