Manage different types of file
Have chezmoi create a directory, but ignore its contents
If you want chezmoi to create a directory, but ignore its contents, say
~/src
, first run:
$ mkdir -p $(chezmoi source-path)/src
This creates the directory in the source state, which means that chezmoi will
create it (if it does not already exist) when you run chezmoi apply
.
However, as this is an empty directory it will be ignored by git. So, create a file in the directory in the source state that will be seen by git (so git does not ignore the directory) but ignored by chezmoi (so chezmoi does not include it in the target state):
$ touch $(chezmoi source-path)/src/.keep
chezmoi automatically creates .keep
files when you add an empty directory
with chezmoi add
.
Ensure that a target is removed
Create a file called .chezmoiremove
in the source directory containing a list
of patterns of files to remove. chezmoi will remove anything in the target
directory that matches the pattern. As this command is potentially dangerous,
you should run chezmoi in verbose, dry-run mode beforehand to see what would be
removed:
$ chezmoi apply --dry-run --verbose
.chezmoiremove
is interpreted as a template, so you can remove different
files on different machines. Negative matches (patterns prefixed with a !
) or
targets listed in .chezmoiignore
will never be removed.
Manage part, but not all, of a file
chezmoi, by default, manages whole files, but there are two ways to manage just parts of a file.
Firstly, a modify_
script receives the current contents of the file on the
standard input and chezmoi reads the target contents of the file from the
script's standard output. This can be used to change parts of a file, for
example using sed
.
Hint
If you need random access to the file to modify it, then you can write standard input to a temporary file, modify the temporary file, and then write the temporary file to the standard output, for example:
#!/bin/sh
tempfile="$(mktemp)"
trap 'rm -rf "${tempfile}"' EXIT
cat > "${tempfile}"
# modify ${tempfile}
cat "${tempfile}"
Note
If the file does not exist then the standard input to the modify_
script
will be empty and it is the script's responsibility to write a complete
file to the standard output.
modify_
scripts that contain the string chezmoi:modify-template
are
executed as templates with the current contents of the file passed as
.chezmoi.stdin
and the result of the template execution used as the new
contents of the file.
Example
To replace the string old
with new
in a file while leaving the rest of
the file unchanged, use the modify script:
{{- /* chezmoi:modify-template */ -}}
{{- .chezmoi.stdin | replaceAllRegex "old" "new" }}
To set individual values in JSON, JSONC, TOML, and YAML files you can use
the setValueAtPath
template function, for example:
{{- /* chezmoi:modify-template */ -}}
{{ fromJson .chezmoi.stdin | setValueAtPath "key.nestedKey" "value" | toPrettyJson }}
Warning
Modify templates must not have a .tmpl
extension.
Secondly, if only a small part of the file changes then consider using a template to re-generate the full contents of the file from the current state. For example, Kubernetes configurations include a current context that can be substituted with:
current-context: {{ output "kubectl" "config" "current-context" | trim }}
Hint
For managing ini files with a mix of settings and state (such as recently
used files or window positions), there is a third party tool called
chezmoi_modify_manager
that builds upon modify_
scripts. See
related software
for more information.
Manage a file's permissions, but not its contents
chezmoi's create_
attributes allows you to tell chezmoi to create a file if
it does not already exist. chezmoi, however, will apply any permission changes
from the executable_
, private_
, and readonly_
attributes. This can be
used to control a file's permissions without altering its contents.
For example, if you want to ensure that ~/.kube/config
always has permissions
600 then if you create an empty file called dot_kube/private_config
in
your source state, chezmoi will ensure ~/.kube/config
's permissions are 0600
when you run chezmoi apply
without changing its contents.
This approach does have the downside that chezmoi will create the file if it
does not already exist. If you only want chezmoi apply
to set a file's
permissions if it already exists and not create the file otherwise, you can use
a run_
script. For example, create a file in your source state called
run_set_kube_config_permissions.sh
containing:
#!/bin/sh
FILE="$HOME/.kube/config"
if [ -f "$FILE" ]; then
if [ "$(stat -c %a "$FILE")" != "600" ] ; then
chmod 600 "$FILE"
fi
fi
Handle configuration files which are externally modified
Some programs modify their configuration files. When you next run chezmoi
apply
, any modifications made by the program will be lost.
You can track changes to these files by replacing with a symlink back to a file
in your source directory, which is under version control. Here is a worked
example for VSCode's settings.json
on Linux:
Copy the configuration file to your source directory:
$ cp ~/.config/Code/User/settings.json $(chezmoi source-path)
Tell chezmoi to ignore this file:
$ echo settings.json >> $(chezmoi source-path)/.chezmoiignore
Tell chezmoi that ~/.config/Code/User/settings.json
should be a symlink to
the file in your source directory:
$ mkdir -p $(chezmoi source-path)/private_dot_config/private_Code/User
$ echo -n "{{ .chezmoi.sourceDir }}/settings.json" > $(chezmoi source-path)/private_dot_config/private_Code/User/symlink_settings.json.tmpl
The prefix private_
is used because the ~/.config
and ~/.config/Code
directories are private by default.
Apply the changes:
$ chezmoi apply -v
Now, when the program modifies its configuration file it will modify the file in the source state instead.
Populate ~/.ssh/authorized_keys
with your public SSH keys from GitHub
chezmoi can retrieve your public SSH keys from GitHub, which can be useful for
populating your ~/.ssh/authorized_keys
. Put the following in your
~/.local/share/chezmoi/dot_ssh/authorized_keys.tmpl
:
{{ range gitHubKeys "$GITHUB_USERNAME" -}}
{{ .Key }}
{{ end -}}