Describe the bug
When diff.command is configured, pressing d at an apply --interactive prompt for an added file passes the missing destination path to the external diff command.
This differs from chezmoi diff, which passes /dev/null for the missing side. External diff tools such as difftastic fail with No such file when given the missing destination path.
To reproduce
With difftastic installed as difft, run this in a temporary directory:
$ tmp=$(mktemp -d)
$ mkdir -p "$tmp/home/.config/chezmoi" "$tmp/source"
$ printf '[diff]\ncommand = "difft"\n' > "$tmp/home/.config/chezmoi/chezmoi.toml"
$ printf 'hello\n' > "$tmp/source/dot_file"
$ HOME="$tmp/home" chezmoi -S "$tmp/source" -D "$tmp/home" \
apply --interactive --no-tty "$tmp/home/.file" <<<'d'
Observed output:
Apply .file (diff/yes/no/all/quit)? No such file: /tmp/tmp.QpIuQgK7pW/home/.file
chezmoi: .file: exit status 2
For comparison, chezmoi diff on the same target succeeds:
$ HOME="$tmp/home" chezmoi -S "$tmp/source" -D "$tmp/home" diff "$tmp/home/.file"
/tmp/chezmoi-diff2066257932/.file --- Text
1 hello
2
Expected behavior
chezmoi prints diff normally and not exit.
Output of command with the --verbose flag
$ HOME="$tmp/home" chezmoi -S "$tmp/source" -D "$tmp/home" \
--verbose apply --interactive --no-tty "$tmp/home/.file" <<<'d'
Apply .file (diff/yes/no/all/quit)? No such file: /tmp/tmp.QpIuQgK7pW/home/.file
chezmoi: .file: exit status 2
Output of chezmoi doctor
Details
$ chezmoi doctor
RESULT CHECK MESSAGE
warning version v2.70.4, built at 2026-05-20T07:44:27Z
ok latest-version v2.70.4
ok os-arch linux/amd64 (Arch Linux)
ok go-version go1.26.3-X:nodwarf5 (gc)
ok executable /usr/bin/chezmoi
ok config-file found ~/.config/chezmoi/chezmoi.toml
ok git-command found git
ok shell-command found bash
Additional context
This kinda break my difft mentality.. So I'm using a wrapper as workaround for now:
> cat private_dot_local/bin/executable_chezmoi-difft
#!/usr/bin/env bash
set -euo pipefail
args=("$@")
if ((${#args[@]} >= 2)); then
old_path_index=$((${#args[@]} - 2))
new_path_index=$((${#args[@]} - 1))
for path_index in "$old_path_index" "$new_path_index"; do
path=${args[$path_index]}
if [[ $path != /dev/null && ! -e $path ]]; then
args[$path_index]=/dev/null
fi
done
fi
exec difft "${args[@]}"
Describe the bug
When
diff.commandis configured, pressingdat anapply --interactiveprompt for an added file passes the missing destination path to the external diff command.This differs from
chezmoi diff, which passes/dev/nullfor the missing side. External diff tools such asdifftasticfail withNo such filewhen given the missing destination path.To reproduce
With
difftasticinstalled asdifft, run this in a temporary directory:Observed output:
For comparison,
chezmoi diffon the same target succeeds:Expected behavior
chezmoi prints diff normally and not exit.
Output of command with the
--verboseflagOutput of
chezmoi doctorDetails
Additional context
This kinda break my difft mentality.. So I'm using a wrapper as workaround for now: