#4912·chezmoi

`re-add` called on files inside exact_ directories turns templates into regular files

Author: r-ricciCreated Feb 4, 2026Updated Jun 9, 2026
Labelsbug

I'm opening this issue because I think #4824 is not really fixed. To reproduce:

bash
#!/bin/sh

set -ex

# create an empty directory to use as the $HOME during the test and cd into it
rm -rf chezmoi-test
mkdir chezmoi-test
cd chezmoi-test
export HOME="$PWD"

# create an empty config file
mkdir -p .config/chezmoi
touch .config/chezmoi/chezmoi.toml

# initialize chezmoi
chezmoi init

# create a non-template file, add it to chezmoi and make its directory exact_
mkdir dir
echo regular > dir/regular
chezmoi add dir/regular
chezmoi chattr exact dir

# create a template in the source and call `chezmoi apply` to add it to the target
echo template > .local/share/chezmoi/exact_dir/template.tmpl
chezmoi apply

# the file has a .tmpl extension in the source
ls .local/share/chezmoi/exact_dir/template*

# modify the non-template file and call `chezmoi re-add` on it (not its directory)
echo regular2 > dir/regular
chezmoi re-add dir/regular

# the template turned into a regular file (it no longer has the .tmpl extension in the source)
ls .local/share/chezmoi/exact_dir/template*

The problem occurs when re-adding a non-template file (not the whole directory) inside an exact_ directory which also contains files generated from templates, without passing the files generated from templates on the command line.

(https://github.com/twpayne/chezmoi/issues/4824#issuecomment-3765840494)

#4862 does not fix this problem because, when chezmoi re-add is called with the same arguments as in the script above, this line https://github.com/twpayne/chezmoi/blob/bc055dfbae3ffcc1b1fee27563cad7f4deb590c5/internal/cmd/readdcmd.go#L283 is not executed because sourceStateEntries only contains files passed on the command line (so not the file generated from the template), therefore in this line https://github.com/twpayne/chezmoi/blob/bc055dfbae3ffcc1b1fee27563cad7f4deb590c5/internal/cmd/readdcmd.go#L307 ignoredFiles.Contains(entryRelPath) is false because ignoredFiles is empty.

@twpayne