## File: README.md

#  chezmoi

[](https://github.com/twpayne/chezmoi/releases)

Manage your dotfiles across multiple diverse machines, securely.

chezmoi's documentation is at [chezmoi.io](https://chezmoi.io/).

If you're contributing to chezmoi, then please read the [developer guide](https://www.chezmoi.io/developer-guide/).

## Contributors



## License

MIT

---

## File: assets/chezmoi.io/docs/developer-guide/architecture.md

# Architecture

This document gives a high-level overview of chezmoi's source code for anyone
interested in contributing to chezmoi.

You can generate Go documentation for chezmoi's source code with `go doc`, for
example:

```sh
go doc -all -http -u chezmoi.io/chezmoi/v2
```

and then visit `http://localhost:$PORT/chezmoi.io/chezmoi/v2` in your browser.

You can also [browse chezmoi's generated documentation online][go-docs].

## Directory structure

The important directories in chezmoi are:

| Directory                        | Contents                                                                                                                                            |
| -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `assets/chezmoi.io/docs/`        | The documentation single source of truth. Help text, examples, and the [chezmoi.io][website] website are generated from the files in this directory |
| `internal/chezmoi/`              | chezmoi's core functionality                                                                                                                        |
| `internal/cmd/`                  | Code for the `chezmoi` command                                                                                                                      |
| `internal/cmd/testdata/scripts/` | High-level tests of chezmoi's commands using [`testscript`][testscript]                                                                             |

## Key concepts

As described in the [reference manual][ref], chezmoi evaluates the source state
to compute a target state for the destination directory (typically your home
directory). It then compares the target state to the actual state of the
destination directory and performs any changes necessary to update the
destination directory to match the target state. These concepts are represented
directly in chezmoi's code.

chezmoi uses the generic term *entry* to describe something that it manages.
Entries can be files, directories, symlinks, scripts, amongst other things.

## `internal/chezmoi/` directory

All of chezmoi's interaction with the operating system is abstracted through the
`System` interface. A `System` includes functionality to read and write files
and directories and execute commands. chezmoi makes a distinction between
idempotent commands that can be run multiple times without modifying the
underlying system and arbitrary commands that may modify the underlying system.

The real underlying system is implemented via a `RealSystem` struct. Other
`System`s are composed on top of this to provide further functionality. For
example, the `--debug` flag is implemented by wrapping the `RealSystem` with a
`DebugSystem` that logs all calls to the underlying `RealSystem`. `--dry-run` is
implemented by wrapping the `RealSystem` with a `DryRunSystem` that allows reads
to pass through but silently discards all writes.

The `SourceState` struct represents a source state, including reading a source
state from the source directory, executing templates, applying the source state
(i.e. updating a `System` to match the desired source state), and adding more
entries to the source state.

Entries in the source state are abstracted by the `SourceStateEntry` interface
implemented by the `SourceStateFile` and `SourceStateDir` structs, as the source
state only consists of regular files and directories.

A `SourceStateFile` includes a `FileAttr` struct describing the attributes
parsed from its file name. Similarly, a `SourceStateDir` includes a `DirAttr`
struct describing the directory attributes parsed from a directory name.

`SourceStateEntry`s can compute their target state entries, i.e. what the
equivalent entry should be in the target state, abstracted by the
`TargetStateEntry` interface.

Actual target state entries include `TargetStateFile` structs, representing a
file with contents and permissions, `TargetStateDir` structs, representing a
directory, `TargetStateSymlink` for symlinks, `TargetStateRemove` for entries
that should be removed, and `TargetStateScript` for scripts that should be run.

The actual state of an entry in the target state is abstracted via the
`ActualStateEntry` interface, with `ActualStateAbsent`, `ActualStateDir`,
`ActualStateFile`, `ActualStateSymlink` structs implementing this interface.

Finally, an `EntryState` struct represents a serialization of an
`ActualEntryState` for storage in and retrieval from chezmoi's persistent state.
It stores a SHA256 of the entry's contents, rather than the full contents, to
avoid storing secrets in the persistent state.

With these concepts, chezmoi's apply command is effectively:

1. Read the source state from the source directory.

2. For each entry in the source state (`SourceStateEntry`), compute its
   `TargetStateEntry` and read its actual state in the destination state
   (`ActualStateEntry`).

3. If the `ActualStateEntry` is not equivalent to the `TargetStateEntry` then
   apply the minimal set of changes to the `ActualStateEntry` so that they are
   equivalent.

Furthermore, chezmoi stores the `EntryState` of each entry that it writes in its
persistent state. chezmoi can then detect if a third party has updated a target
since chezmoi last wrote it by comparing the actual state entry in the target
state with the entry state in the persistent state.

## `internal/cmd/` directory

`internal/cmd/*cmd.go` files contain the code for each individual command.
`internal/cmd/*templatefuncs.go` files contain the template functions.

Commands are defined as methods on the `Config` struct. The `Config` struct is
large, containing all configuration values read from the config file, command
line arguments, and computed and cached values.

The `Config.persistentPreRunRootE` and `Config.persistentPostRunRootE` methods
set up and tear down state for individual commands based on the command's
`Annotations` field, which defines how the command interacts with the file
system and persistent state.

## Path handling

chezmoi uses separate types for absolute paths (`AbsPath`) and relative paths
(`RelPath`) to avoid errors where paths are combined (e.g. joining two absolute
paths is an error). The type `SourceRelPath` is a relative path within the
source directory and handles file and directory attributes.

Internally, chezmoi normalizes all paths to use forward slashes with an optional
upper-cased Windows volume so they can be compared with string comparisons.
Paths read from the user may include tilde (`~`) to represent the user's home
directory, use forward or backward slashes, and are treated as external paths
(`ExtPath`). These are normalized to absolute paths. chezmoi is case-sensitive
internally and makes no attempt to handle case-insensitive or case-preserving
file systems.

## Persistent state

Persistent state is treated as a two-level key-value store with the
pseudo-structure `map[Bucket]map[Key]Value`, where `Bucket`, `Key`, and `Value`
are all `[]byte`s. The `PersistentState` interface defines interaction with
them. Sometimes temporary persistent states are used. For example, in dry run
mode (`--dry-run`) the actual persistent state is copied into a temporary
persistent state in memory which remembers writes but does not persist them to
disk.

## Encryption

Encryption tools are abstracted by the `Encryption` interface that contains
methods of encrypting and decrypting files and `[]byte`s. Implementations are
the `AGEEncryption` and `GPGEncryption` structs. A `DebugEncryption` struct
wraps an `Encryption` interface and logs the methods called.

## `run_once_` and `run_onchange_` scripts

The execution of a `run_once_` script is recorded by storing the SHA256 of its
contents in the `scriptState` bucket in the persistent state. On future
invocations the script is only run if no matching contents SHA256 is found in
the persistent state.

The execution of a `run_onchange_` script is recorded by storing its target name
in the `entryState` bucket along with its contents SHA256 sum. On future
invocations the script is only run if its contents SHA256 sum has changed, and
its contents SHA256 sum is then updated in the persistent state.

## Testing

chezmoi has a mix of unit, integration, and end-to-end tests. Unit and
integration tests use the [`github.com/alecthomas/assert/v2`][assert] framework.
End-to-end tests use [`github.com/rogpeppe/go-internal/testscript`][testscript]
with the test scripts themselves in
`internal/cmd/testdata/scripts/$TEST_NAME.txtar`.

You can run individual end-to-end tests with

```sh
go test ./internal/cmd -run=TestScript/$TEST_NAME
```

Tests should, if at all possible, run unmodified on all operating systems tested
in CI (Linux, macOS, Windows, and FreeBSD). Windows will sometimes need special
handling due to its path separator and lack of POSIX-style file permissions.

[go-docs]: https://pkg.go.dev/chezmoi.io/chezmoi/v2
[website]: https://chezmoi.io
[testscript]: https://pkg.go.dev/github.com/rogpeppe/go-internal/testscript
[ref]: /reference/concepts.md
[assert]: https://pkg.go.dev/github.com/alecthomas/assert

---

## File: assets/chezmoi.io/docs/developer-guide/building-on-top-of-chezmoi.md

# Building on top of chezmoi

chezmoi is designed with UNIX-style composability in mind, and the command line
tool is semantically versioned. Building on top of chezmoi should primarily be
done by executing the `chezmoi` binary with arguments and the standard input and
output configured appropriately. The `chezmoi dump` and `chezmoi state` commands
allows the inspection of chezmoi's internal state.

---

## File: assets/chezmoi.io/docs/developer-guide/contributing-changes.md

# Contributing changes

!!! warning

    chezmoi has a strict zero-tolerance policy on LLM contributions. If you use
    an LLM (Large Language Model, like ChatGPT, Claude, Gemini, GitHub Copilot,
    or Llama) to make any kind of contribution then you will immediately be
    banned without recourse. See [`CODE_OF_CONDUCT.md`][coc] for more
    information.

Bug reports, bug fixes, and documentation improvements are always welcome.
Please [open an issue][issue] or [create a pull request][pr] with your report,
fix, or improvement.

If you want to make a more significant change, please first
[open an issue][issue] to discuss the change that you want to make. Dave Cheney
gives a [good rationale][rationale] as to why this is important.

All changes are made via pull requests. In your pull request, please make sure
that:

* All existing tests pass. You can ensure this by running `make test`.

* There are appropriate additional tests that demonstrate that your PR works as
  intended.

* The documentation is updated, if necessary. For new features you should add an
  entry in `assets/chezmoi.io/docs/user-guide/` and a complete description in
  `assets/chezmoi.io/docs/reference/`. See the [website developer guide][website]
  for instructions on how to build and view a local version of the documentation.
  By default, chezmoi will panic if a flag is undocumented or a long help is
  missing for a command. You can disable this panic during development by
  setting the environment variable `CHEZMOIDEV` to `ignoreflags=1,ignorehelp=1`.
  Once you have documented the command and its flags, run `make generate` to
  generate the embedded documentation.

* All generated files are up to date. You can ensure this by running `make
  generate` and including any modified files in your commit.

* The code is correctly formatted. You can ensure this by running `make format`.

* The code passes [`golangci-lint`][golangci-lint]. You can ensure this by
  running `make lint`.

* The commit messages adhere to the [conventional commits specification][commits],
  with the following additional requirements:

      * The first character of the commit message is uppercase, e.g:

          ```text
          chore: Fix typo in test
          ```

        The purpose of this is to maintain consistency in chezmoi's release
        notes, which are generated directly from the commit messages.

      * The commits do not have scopes (e.g. `chore(scope): Message` is invalid).

    The following criteria can be used to determine the commit type:

      * `fix`: bug fixes in chezmoi code
      * `feat`: extending an existing feature or adding a new feature
      * `docs`: adding to or updating the documentation
      * `chore`: small changes, such as fixing a typo, correcting grammar
        (including in documentation), or anything not covered by the above

    Examples can be found in the [commit history][history].

* Commits are logically separate, with no merge or "fixup" commits.

* The branch applies cleanly to `master`.

[issue]: https://github.com/twpayne/chezmoi/issues/new/choose
[pr]: https://help.github.com/en/articles/creating-a-pull-request
[rationale]: https://dave.cheney.net/2019/02/18/talk-then-code
[golangci-lint]: https://github.com/golangci/golangci-lint
[commits]: https://www.conventionalcommits.org/en/v1.0.0/
[history]: https://github.com/twpayne/chezmoi/commits/master/
[website]: /developer-guide/website.md
[coc]: https://github.com/twpayne/chezmoi/blob/master/.github/CODE_OF_CONDUCT.md

---

## File: assets/chezmoi.io/docs/developer-guide/index.md

# Developer guide

!!! warning

    If you use an LLM (Large Language Model, like ChatGPT, Claude, Gemini,
    GitHub Copilot, or Llama) to make any kind of contribution then you will
    immediately be banned without recourse. See [`CODE_OF_CONDUCT.md`][coc]
    for more information.

chezmoi is written in [Go][go] and development happens on [GitHub][github].
chezmoi is a standard Go project, using standard Go tooling. chezmoi requires
Go 1.25 or later.

Checkout chezmoi:

```sh
git clone https://github.com/twpayne/chezmoi.git
cd chezmoi
```

Build chezmoi:

```sh
go build
```

Run all tests:

```sh
go test ./...
```

chezmoi's tests include integration tests with other software. If the other
software is not found in `$PATH` the tests will be skipped. Running the full set
of tests requires `age`, `base64`, `bash`, `bzip2`, `git`, `gpg`, `gzip`,
`perl`, `python3`, `rage`, `ruby`, `sed`, `sha256sum`, `tr`, `true`, `unzip`,
`xz`, `zip`, and `zstd`.

Run chezmoi:

```sh
go tool chezmoi
```

Run a set of smoke tests, including cross-compilation, tests, and linting:

```sh
make smoke-test
```

Test building chezmoi for all architectures:

```sh
make test-release
```

!!! hint

    If you use `fish` as your primary shell, you may get warnings from Fish
    during tests:

    ```text
    error: can not save history
    warning-path: Unable to locate data directory derived from $HOME: '/home/user/.local/share/fish'.
    warning-path: The error was 'Operation not supported'.
    warning-path: Please set $HOME to a directory where you have write access.
    ```

    These can be avoided with by running tests with `SHELL=bash` or `SHELL=zsh`:

    ```sh
    SHELL=bash make test
    SHELL=zsh make smoke-test
    SHELL=bash go test ./...
    ```

[coc]: https://github.com/twpayne/chezmoi/blob/master/.github/CODE_OF_CONDUCT.md
[go]: https://golang.org
[github]: https://github.com

---

## File: assets/chezmoi.io/docs/developer-guide/install-script.md

# Install script

chezmoi generates the [install script][install] from a single source of truth.
You must run

```sh
make generate
```

if your change includes any of the following:

* Modifications to the install script template.

* Additions or modifications to the list of supported operating systems and
  architectures.

chezmoi's continuous integration verifies that all generated files are up to
date. Changes to generated files should be included in the commit that modifies
the source of truth.

[install]: https://github.com/twpayne/chezmoi/blob/master/assets/scripts/install.sh

---

## File: assets/chezmoi.io/docs/developer-guide/packaging.md

# Packaging

If you're packaging chezmoi for an operating system or distribution:

chezmoi has no build dependencies other than the standard Go toolchain.

chezmoi has no runtime dependencies, but is usually used with `git`, so many
packagers choose to make `git` an install dependency or recommended package.

Please set the version number, git commit, and build time in the binary. This
greatly assists debugging when end users report problems or ask for help. You
can do this by passing the following flags to `go build`:

```text
-ldflags "-X main.version=$VERSION
          -X main.commit=$COMMIT
          -X main.date=$DATE
          -X main.builtBy=$BUILT_BY"
```

`$VERSION` should be the chezmoi version, e.g. `1.7.3`. Any `v` prefix is
optional and will be stripped, so you can pass the git tag in directly.

!!! hint

    The command `git describe --abbrev=0 --tags` will return a suitable value
    for `$VERSION`.

`$COMMIT` should be the full git commit hash at which chezmoi is built, e.g.
`4d678ce6850c9d81c7ab2fe0d8f20c1547688b91`.

!!! hint

    The `internal/cmds/generate-commit/main.go` script will return a suitable value
    for `$COMMIT`.

    You can run it with `go tool generate-commit`.

!!! hint

    The source archive contains a file called `COMMIT` containing the commit
    hash.

`$DATE` should be the date of the build as a UNIX timestamp or in RFC3339
format.

!!! hint

    The command `git show -s --format=%ct HEAD` returns the UNIX timestamp of
    the last commit, e.g. `1636668628`.

    The command `date -u +%Y-%m-%dT%H:%M:%SZ` returns the current time in
    RFC3339 format, e.g. `2019-11-23T18:29:25Z`.

`$BUILT_BY` should be a string indicating what system was used to build the
binary. Typically it should be the name of your packaging system, e.g.
`homebrew`.

Please enable cgo, if possible. chezmoi can be built and run without cgo, but
the `.chezmoi.username` and `.chezmoi.group` template variables may not be set
correctly on some systems.

chezmoi includes an `upgrade` command which attempts to self-upgrade. You can
remove this command completely by building chezmoi with the `noupgrade` build
tag.

chezmoi includes shell completions in the `completions` directory. Please
include these in the package and install them in the shell-appropriate
directory, if possible.

If the instructions for installing chezmoi in chezmoi's [install guide][guide]
are absent or incorrect, please open an issue or submit a PR to correct them.

[guide]: /install.md

---

## File: assets/chezmoi.io/docs/developer-guide/releases.md

# Releases

Releases are managed with [`goreleaser`][goreleaser].

## Testing

To build a test release, without publishing, (Ubuntu Linux only) first ensure
that the `musl-tools` and `snapcraft` packages are installed:

```sh
sudo apt-get install musl-tools snapcraft
```

Then run:

```sh
make test-release
```

## Publishing

Publish a new release by creating and pushing a tag, for example:

```sh
git tag v1.2.3
git push --tags
```

This triggers a [GitHub Action][gha] that builds and publishes archives,
packages, and snaps, creates a new [GitHub Release][release], and deploys the
[website][website].

### Snaps

Publishing [Snaps][snaps] requires a `SNAPCRAFT_STORE_CREDENTIALS` [repository
secret][secret].

Snapcraft store credentials periodically expire. This is visible in the release
GitHub Action reporting:

```
Run snapcraft whoami
Store operation failed:
- macaroon-authorization-required: The request is missing an Authorization header field containing a valid macaroon
```

Create new snapcraft store credentials by running:

```sh
snapcraft export-login --snaps=chezmoi --channels=stable,candidate,beta,edge --acls=package_upload -
```

This command requires a Ubuntu machine with snapcraft installed and a keyring,
which is typically not available over SSH connections. Login to a GNOME session
on a Ubuntu machine and run:

```sh
sudo snap install --classic snapcraft
snapcraft login
```

### Homebrew

[Homebrew][homebrew] automation will automatically detect new releases of chezmoi within
a few hours and open a pull request in
[github.com/Homebrew/homebrew-core][homebrew-core] to bump the version.

If needed, the pull request can be created with:

```sh
brew bump-formula-pr --tag=v1.2.3 chezmoi
```

### Scoop

chezmoi is in [Scoop][scoop]'s Main bucket. Scoop's automation will
automatically detect new releases within a few hours.

## Signing

chezmoi uses [GoReleaser's support for signing][signing] to sign the checksums
of its release assets with [cosign][cosign].

Details:

* The cosign private key was generated with cosign v1.12.1 on a private
  recently-installed Ubuntu 22.04.1 system with a single user and all available
  updates applied.

* The private key uses a long (more than 32 character) password generated
  locally by a password manager.

* The password-protected private key is stored in chezmoi's public GitHub repo.

* The private key's password is stored as a [GitHub Actions secret][gha-secret]
  and only available to the `release` step of `release` job of the `main`
  workflow.

* The cosign public key is included in the release assets and also uploaded to
  [`https://chezmoi.io/cosign.pub`][pubkey]. Since
  [`https://chezmoi.io`][website] is served by [GitHub pages][pages], it
  probably has equivalent security to [chezmoi's GitHub Releases page][release],
  which is also managed by GitHub.

[goreleaser]: https://goreleaser.com/
[gha]: https://github.com/twpayne/chezmoi/actions
[release]: https://github.com/twpayne/chezmoi/releases
[website]: https://chezmoi.io
[snaps]: https://snapcraft.io/
[secret]: https://github.com/twpayne/chezmoi/settings/secrets/actions
[homebrew]: https://brew.sh/
[homebrew-core]: https://github.com/Homebrew/homebrew-core
[scoop]: https://scoop.sh/
[signing]: https://goreleaser.com/customization/sign/
[cosign]: https://github.com/sigstore/cosign
[gha-secret]: https://docs.github.com/en/actions/security-guides/encrypted-secrets
[pubkey]: https://chezmoi.io/cosign.pub
[pages]: https://pages.github.com/

---

## File: assets/chezmoi.io/docs/developer-guide/security.md

# Security

## Supported versions

Only the most recent version of chezmoi is supported with security updates.

## Virus scanner false positives

Virus scanning software, especially on Windows machines, occasionally report
viruses or trojans in the chezmoi binary. This is almost certainly a false
positive.

For more information see [Why does my virus-scanning software think my Go
distribution or compiled binary is infected?][false] in
the Go FAQ.

## Reporting a vulnerability

Please report vulnerabilities by [opening a GitHub issue][issue] or sending an
email to [`twpayne+chezmoi-security@gmail.com`][email].

## Security thanks

Security problems are reported privately and do not show up in the list of
contributors. chezmoi thanks:

### Organizations

* [Secur0](https://secur0.com/) who performed an extensive security analysis of
  chezmoi.

### Individuals

* eltiburon7
* gueco
* julichaan
* Krypt3d (multiple vulnerabilities)
* pulpo
* reddev (multiple vulnerabilities)
* TheRedP4nther (multiple vulnerabilities)

[false]: https://go.dev/doc/faq#virus
[issue]: https://github.com/twpayne/chezmoi/issues/new/choose
[email]: mailto:twpayne%2Bchezmoi-security@gmail.com

---

## File: assets/chezmoi.io/docs/developer-guide/testing.md

# Testing

chezmoi uses multiple levels of testing:

1. Unit testing, using [`testing`][testing],  and
   [`github.com/alecthomas/assert/v2`][assert], tests that functions and small
   components behave as expected for a wide range of inputs, especially edge
   cases. These are generally found in `internal/chezmoi/*_test.go`.

2. File system integration tests, using `testing` and
   [`github.com/twpayne/go-vfs/v5`][vfs], test chezmoi's effects on the file
   system. This include some tests in `internal/chezmoi/*_test.go`, and higher
   level command tests in `internal/cmd/*cmd_test.go`.

3. High-level integration tests using
   [`github.com/rogpeppe/go-internal/testscript`][testscript] are in
   `internal/cmd/testdata/scripts/*.txtar` and are run by
   `internal/cmd/main_test.go`.

4. Linux distribution and OS tests run the full test suite using Docker for
   different Linux distributions (in `assets/docker`) and Vagrant for different
   OSes (in `assets/vagrant`). Windows tests are run in GitHub Actions.

[testing]: https://pkg.go.dev/testing
[assert]: https://pkg.go.dev/github.com/alecthomas/assert/v2
[vfs]: https://pkg.go.dev/github.com/twpayne/go-vfs/v5
[testscript]: https://pkg.go.dev/github.com/rogpeppe/go-internal/testscript