gitdiffgit-diffdifftoolgit-difftool

Detect renames with `git difftool --dir-diff`


With git difftool --dir-diff, I can 'diff a whole tree by preparing a temporary copy'. However, I then lose information about renames. Here's a comprehensive example demonstrating the same.

git init
echo xyz >foo.txt
git add .
git commit -m 'Initial commit'
git mv foo.txt bar.txt
git commit -m 'Renamed'
git difftool --dir-diff --tool meld HEAD^

Meld is used just as an example.

Actual Output

Diff generated using Meld

Meld thinks a file was removed and a different file was added. A custom external diff tool which doesn't do similarity analysis would do the same.

Desired Output

Something resembling the output of git diff HEAD^. In theory, I could run a recursive similarity analysis on the left and right directories. However Git knows that foo.txt was renamed to bar.txt, and I'd ideally like this information to be sent to the custom external diff tool.

diff --git a/foo.txt b/bar.txt
similarity index 100%
rename from foo.txt
rename to bar.txt

Git - git-config Documentation | difftool.<tool>.cmd only mentions two arguments, LEFT and RIGHT, the two directories where the files will be made available.

Git - git-difftool Documentation doesn't provide any details on how to accomplish this, either.

How can I achieve correct rename detection without redoing the processing Git already does? Assuming I build my own custom external diff tool (using git config diff.tool custom and git config difftool.custom.cmd custom_command), how can I go about this?


Solution

  • As you have already understood: git difftool -d creates 2 temporary directories with the content to compare, and then calls the external diff tool on these two directories. By doing so, it completely delegates the task of computing/displaying/rendering the diff to that external tool.

    So in some way, your question is more a meld question (or whatever diff tool) than a pure git question, although a certain number of git options can give you an opportunity to tweak the process.


    By looking at the man page for meld or kdiff3, I don't see direct options to detect renaming when comparing two directories.

    You could write your own wrapper script and try to find renames before invoking the actual diff tool, and then define that script as a diff viewer:

    git config --global difftool.meld_rename.cmd '/path/to/my/script $LOCAL $REMOTE'
    
    # usage:
    git difftool -d --tool=meld_rename HEAD~