Skip to content

Merge

What is the merge command

When running chezmoi apply --interactive, chezmoi computes the desired state (the target) from your source. If applying would change a file on disk - i.e. the destination differs from the target, usually because you edited the live file directly - a prompt appears to either overwrite, diff, skip.

Choosing merge is chezmoi's analog of resolving a git conflict by hand - except it reconciles three states, not two:

  1. .Destination - the file on your system
  2. .Source - the file in your chezmoi repo (the source of truth)
  3. .Target - the desired state, computed by rendering the source (templates applied, etc.)

Use a custom merge command

By default, chezmoi uses vimdiff. You can use a custom command by setting the merge.command and merge.args configuration variables. The elements of merge.args are interpreted as templates with the variables .Destination, .Source, and .Target containing filenames of the file in the destination state, source state, and target state respectively. For example, to use neovim's diff mode, specify:

~/.config/chezmoi/chezmoi.toml
[merge]
    command = "nvim"
    args = [
        "-d",
        "{{ .Destination }}",
        "{{ .Source }}",
        "{{ .Target }}"
    ]
~/.config/chezmoi/chezmoi.yaml
merge:
  command: nvim
  args:
  - -d
  - "{{ .Destination }}"
  - "{{ .Source }}"
  - "{{ .Target }}"
~/.config/chezmoi/chezmoi.json
{
    "merge": {
        "command": "nvim",
        "args": [
            "-d",
            "{{ .Destination }}",
            "{{ .Source }}",
            "{{ .Target }}"
        ]
    }
}

Hint

If you generate your config file from a config file template, then you'll need to escape the {{ and }}. That way your generated config file contains the {{ and }} you expect.

~/.local/share/chezmoi/chezmoi.toml.tmpl
[merge]
    command = "nvim"
    args = [
        "-d",
        {{ printf "%q" "{{ .Destination }}" }},
        {{ printf "%q" "{{ .Source }}" }},
        {{ printf "%q" "{{ .Target }}" }},
    ]
~/.local/share/chezmoi/chezmoi.yaml.tmpl
merge:
  command: nvim
  args:
  - -d
  - {{ printf "%q" "{{ .Destination }}" }}
  - {{ printf "%q" "{{ .Source }}" }}
  - {{ printf "%q" "{{ .Target }}" }}
~/.local/share/chezmoi/chezmoi.json.tmpl
{
    "merge": {
        "command": "nvim",
        "args": [
            "-d",
            {{ printf "%q" "{{ .Destination }}" }},
            {{ printf "%q" "{{ .Source }}" }},
            {{ printf "%q" "{{ .Target }}" }}
        ]
    }
}

Use Beyond Compare as the merge tool

To use Beyond Compare as the merge tool, add the following to your config:

~/.config/chezmoi/chezmoi.toml
[merge]
    command = "bcomp"
    args = [
        "{{ .Destination }}",
        "{{ .Source }}",
        "{{ .Target }}",
        "{{ .Source }}"
    ]
~/.config/chezmoi/chezmoi.yaml
merge:
  command: "bcomp"
  args:
  - "{{ .Destination }}"
  - "{{ .Source }}"
  - "{{ .Target }}"
  - "{{ .Source }}"
~/.config/chezmoi/chezmoi.json
{
    "merge": {
        "command": "bcomp",
        "args": [
            "{{ .Destination }}",
            "{{ .Source }}",
            "{{ .Target }}",
            "{{ .Source }}"
        ]
    }
}

Use VSCode as the merge tool

To use VSCode as the merge tool, add the following to your config:

~/.config/chezmoi/chezmoi.toml
[merge]
command = "bash"
args = [
    "-c",
    "cp {{ .Target | quote }} {{ printf \"%s.base\" .Target | quote }} && code --new-window --wait --merge {{ .Destination | quote }} {{ .Target | quote }} {{ printf \"%s.base\" .Target | quote }} {{ .Source | quote }}",
]
~/.config/chezmoi/chezmoi.yaml
merge:
  command: "bash"
  args:
  - "-c"
  - "cp {{ .Target | quote }} {{ printf \"%s.base\" .Target | quote }} && code --new-window --wait --merge {{ .Destination | quote }} {{ .Target | quote }} {{ printf \"%s.base\" .Target | quote }} {{ .Source | quote }}"
~/.config/chezmoi.chezmoi.json
{
    "merge": {
        "command": "bash",
        "args": [
            "-c",
            "cp {{ .Target | quote }} {{ printf \"%s.base\" .Target | quote }} && code --new-window --wait --merge {{ .Destination | quote }} {{ .Target | quote }} {{ printf \"%s.base\" .Target | quote }} {{ .Source | quote }}",
        ]
    }
}