twpayne / chezmoi

Manage your dotfiles across multiple diverse machines, securely.
https://www.chezmoi.io/
MIT License
13.36k stars 493 forks source link

Apply the external diff command to the entire directory (opt-in) #2828

Closed FranklinYu closed 1 year ago

FranklinYu commented 1 year ago

Is your feature request related to a problem? Please describe.

My external diff tool Difftastic cannot handle directories when being invoked from Chezmoi. Chezmoi seems to use foobar-directory/null to indicate that the directory doesn’t exist, which doesn’t work with Difftastic (or as basic as the GNU Diff).

Describe the solution you'd like

Have another configuration bit under the diff section, possibly named recursive. If it is true, then Chezmoi only invoke the diff.command once, and the two template-variables in diff.args becomes the two top-level directories. This works with Difftastic, Meld, and plain diff --recursive.

Describe alternatives you've considered

An alternative could be to make use of the compatibility of Difftastic against the GIT_EXTERNAL_DIFF API. However, I’m not aware of any other diff tool compatible with that specific interface out-of-box; for example, I use Meld with Git under git difftool instead of git diff, and the difftool subcommand provides --dir-diff which is similar to what I proposed (comparing the project-root directory).

Another alternative could be to provide {{ .DestinationDir }} and {{ .TargetDir }}, but Chezmoi still need to decide how many times to invoke the command.

Additional context

N/A

twpayne commented 1 year ago

I haven't tried this, but you might be able to set

[diff]
    exclude = ["dirs"]

in your config file, which should stop chezmoi from invoking your diff tool for directories.

halostatue commented 1 year ago

There might be a separate discussion that could be made for different tools on different types. Something like:

[diff.dirs]
  command = "" # some tool that shows a directory diff
twpayne commented 1 year ago

I haven't tried this, but you might be able to set

[diff]
    exclude = ["dirs"]

in your config file, which should stop chezmoi from invoking your diff tool for directories.

This indeed fixes the problem, as verified in #2830.

FranklinYu commented 1 year ago

I’m not sure whether to consider that a “fix”. If I understand it correctly, that configuration would completely suppress any output for directories, so when I run chezmoi diff I don’t even know that it is going to create a directory upon chezmoi apply. This is not what I really meant.

twpayne commented 1 year ago

Describe the solution you'd like

Have another configuration bit under the diff section, possibly named recursive. If it is true, then Chezmoi only invoke the diff.command once, and the two template-variables in diff.args becomes the two top-level directories. This works with Difftastic, Meld, and plain diff --recursive.

chezmoi invokes the diff tool once for each entry that has changed, so it only needs to create entries that have changed. The solution you propose would require recreating the entire target state, including entries that have not changed. If entries that have not changed are not included then the external diff tool would show them as deleted, which is not correct.

Alternatively, if you want to see diffs to directories, then use a diff tool that can handle directories, like chezmoi's builtin diff.