docs: explain file collision handling

Document how Home Manager handles activation-time file collisions in the usage manual, including standalone backup flags, NixOS and nix-darwin module options, per-file force handling, recursive directory behavior, and out-of-store symlink sources.

Also clarify the home.file-style ignorelinks option description so recursive symlink behavior is easier to understand from the generated option docs.
This commit is contained in:
Austin Horstman 2026-05-04 11:15:11 -05:00
parent 938311a3bd
commit 0ecfc72c7c
2 changed files with 137 additions and 2 deletions

View file

@ -34,3 +34,136 @@ Activating checkLinkTargets
Existing file '/home/jdoe/.config/git/config' is in the way
Please move the above files and try again
```
This error is about a file that Home Manager wants to manage as a
symbolic link in your home directory. It is separate from package
profile collisions, which usually mention `installPackages` or a
`collision between .../bin/...` path. For package collisions, see
[Why is there a collision error when switching generation?](#_why_is_there_a_collision_error_when_switching_generation).
## Resolving file collisions {#sec-usage-dotfiles-collisions}
The safest resolution is to inspect the existing path, move any
settings you want Home Manager to manage into your configuration, and
remove or move the unmanaged file before switching again.
For a standalone Home Manager installation, you can ask Home Manager to
move unmanaged non-symlink paths out of the way during activation:
``` shell
home-manager switch -b backup
```
With the command above, a colliding `~/.config/git/config` is moved to
`~/.config/git/config.backup` before Home Manager links the managed
file. If the backup path already exists then activation still aborts, so
choose an extension whose backup path does not already exist.
Standalone activation can also run a custom command for each collision:
``` shell
home-manager switch -B trash-put
```
The command receives the colliding path as an argument and must move or
remove that path. If both `-B` and `-b` are set, the custom command takes
precedence; the command may still use the
`HOME_MANAGER_BACKUP_EXT` environment variable set by `-b`.
When Home Manager is used as a NixOS or nix-darwin module, configure the
corresponding module options instead of passing standalone command line
flags:
``` nix
{
home-manager.backupFileExtension = "backup";
}
```
or
``` nix
{
home-manager.backupCommand = "${pkgs.trash-cli}/bin/trash-put";
}
```
If both {option}`home-manager.backupCommand` and
{option}`home-manager.backupFileExtension` are set, the command takes
precedence. The extension is still exported to the command as
`HOME_MANAGER_BACKUP_EXT`, so the command can use it when implementing
its own backup naming. With
{option}`home-manager.backupFileExtension`, Home Manager refuses to
replace an existing backup path unless
{option}`home-manager.overwriteBackup` is enabled:
``` nix
{
home-manager.backupFileExtension = "backup";
home-manager.overwriteBackup = true;
}
```
::: {.warning}
{option}`home-manager.overwriteBackup` allows activation to clobber
existing backup files. Only enable it when those backup paths are
disposable.
:::
For individual files, many file options also support `force = true`:
``` nix
{
home.file.".config/example" = {
source = ./example;
force = true;
};
}
```
This skips the collision check for the affected target and lets Home
Manager replace the existing file or link. Use it sparingly; it can
silently delete local changes.
Backup commands and backup extensions are intended for unmanaged
non-symlink paths. If the colliding target is an unmanaged symbolic
link, move it manually or use `force = true` after checking that the
link target is safe to replace.
## Advanced file behavior {#sec-usage-dotfiles-advanced}
The notes below apply to {option}`home.file` and to options based on the
same file type, such as {option}`xdg.configFile`.
When a file source is a directory, {option}`home.file.<name>.recursive`
changes how the directory is linked. With the default `recursive =
false`, the target is one symbolic link to the source directory. With
`recursive = true`, Home Manager creates a matching directory tree and
links each leaf file into it.
Recursive directory linking has special overlap behavior. A direct
duplicate target, such as two managed files both targeting `foo`, is an
error. If a recursively linked directory provides `foo/bar` and another
managed file also targets `foo/bar`, Home Manager keeps the recursive
file by default and ignores the overlapping regular file.
The {option}`home.file.<name>.onChange` hook runs after the new files
are linked. For recursive file entries, the hook is always run, so it
should be written to be safe even when no leaf file actually changed.
Normally a path assigned to {option}`home.file.<name>.source` is copied
or linked through the Nix store. To make Home Manager create a link to a
live path outside the store, use
`config.lib.file.mkOutOfStoreSymlink`:
``` nix
{ config, ... }:
{
home.file.".config/example".source =
config.lib.file.mkOutOfStoreSymlink ./example;
}
```
This is useful when the target should follow changes to a mutable file
or directory outside the store.