Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
4b48c68
refactor(git): add plumbing helpers for detached snapshots
jdx Sep 5, 2026
fe08886
feat(bootstrap): record generations
jdx Sep 5, 2026
8e37a0b
fix(bootstrap): address review feedback on generation recording
jdx Sep 5, 2026
cb1041a
fix(bootstrap): record a --from generation only when the checkout cha…
jdx Sep 5, 2026
4b09508
fix(bootstrap): identify --from generations by their checkout in the …
jdx Sep 5, 2026
bd6bd70
feat(bootstrap): diff generations
jdx Sep 5, 2026
db934e3
fix(bootstrap): address review feedback on generations diff
jdx Sep 5, 2026
708c2cf
fix(bootstrap): diff a root present in one snapshot only
jdx Sep 5, 2026
4979bc3
feat(bootstrap): journal dotfiles and edits
jdx Sep 5, 2026
8609390
fix(bootstrap): address review feedback on the dotfiles journal
jdx Sep 5, 2026
18bd62d
feat(dotfiles): track files in place with history
jdx Sep 5, 2026
da3681f
fix(dotfiles): address review feedback on tracking
jdx Sep 5, 2026
cdcf5b4
test(history): silence shellcheck on tracked-file assertions
jdx Sep 5, 2026
6fae916
fix(dotfiles): reject add --mode track and keep every variant os
jdx Sep 5, 2026
37dcec1
refactor(dotfiles): move history under bootstrap dotfiles, records ho…
jdx Sep 5, 2026
c696df3
fix(dotfiles): address review feedback on tracking and history
jdx Sep 6, 2026
8071389
fix(dotfiles): exclusions, saved deletions, subtree promotion, and pr…
jdx Sep 6, 2026
e120f23
fix(dotfiles): find git.exe on Windows, address the tracked symlink a…
jdx Sep 6, 2026
e875321
docs: take the agent guide from main
jdx Sep 6, 2026
3293117
fix(dotfiles): layer overrides keep what they leave unsaid, exclusion…
jdx Sep 6, 2026
f3ea8fb
fix(dotfiles): repeated exclusion globs keep their place in the order
jdx Sep 6, 2026
b0eb3ca
docs(dotfiles): source links point at the dotfiles command modules
jdx Sep 6, 2026
dcc98c3
docs(dotfiles): history subcommand source links point at their own mo…
jdx Sep 6, 2026
6060528
fix(dotfiles): carried modes come from a non-protective checkpoint, a…
jdx Sep 6, 2026
f6e9dff
fix(dotfiles): carried modes are looked for past checkpoints that did…
jdx Sep 6, 2026
9d6f8dd
fix(dotfiles): take carried modes only from checkpoints that recorded…
jdx Sep 6, 2026
a86488b
fix(dotfiles): record permission-only changes and keep saved sibling …
jdx Sep 6, 2026
e3eec1c
fix(dotfiles): pending operations are listed, keys use forward slashe…
jdx Sep 6, 2026
1f3c046
fix(dotfiles): an exclusion always wins, untrack refuses to drop a re…
jdx Sep 6, 2026
4d3200b
fix(dotfiles): a permission-only change is listed among a checkpoint'…
jdx Sep 6, 2026
73261e0
fix(dotfiles): an excluded part of a referenced source is reported, a…
jdx Sep 6, 2026
cd471b3
fix(dotfiles): preserve baselines and discard rejected no-op runs
jdx Sep 6, 2026
5b8677e
fix(bootstrap): allow tracking around managed file footprints
jdx Sep 6, 2026
8c11025
fix(bootstrap): protect tracked children from managed directory writes
jdx Sep 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/test-impl.yml
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,12 @@ jobs:
# The full E2E suite runs on Linux. Tests whose filenames contain `macos`
# are also discovered and exercised here for platform-specific coverage.
- run: mise run test:e2e macos
# Generation snapshots shell out to git and need the Xcode Command
# Line Tools guard exercised on a real macOS runner.
- run: mise run test:e2e e2e/cli/test_dotfiles_history_bootstrap
- run: mise run test:e2e e2e/cli/test_dotfiles_history
- run: mise run test:e2e e2e/cli/test_dotfiles_track
- run: mise run test:e2e e2e/cli/test_dotfiles_history_policies
Comment thread
greptile-apps[bot] marked this conversation as resolved.

lint:
runs-on: ${{ !inputs.trusted && 'ubuntu-latest' || 'namespace-profile-endev-linux-amd64-large;overrides.cache-tag=cache' }}
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ See the [contributing guide](https://mise.jdx.dev/contributing).

## mbx build cache

`mise install` installs [mbx](https://mr-boxington.jdx.dev) 1.4. The normal
`mise install` installs [mbx](https://mr-boxington.jdx.dev) at the version pinned in `mise.toml`. The normal
`mise run build`, `mise run test:unit`, and `mise run lint` workflows activate
its transparent Cargo wrapper and therefore use the cache while invoking Cargo
normally. Standalone Cargo commands require an activated mise shell. To bypass
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ toml_edit = { version = "0.25", features = ["parse"] }
ubi = { version = "0.12", default-features = false }
url = "2"
urlencoding = "2"
uuid = { version = "1", features = ["v7"] }
usage-lib = { version = "6", features = ["docs"] }
versions = { version = "7", features = ["serde"] }
vfox = { path = "crates/vfox", default-features = false }
Expand Down
29 changes: 29 additions & 0 deletions docs/.vitepress/cli_commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,41 @@ export const commands: { [key: string]: Command } = {
edit: {
hide: false,
},
history: {
hide: false,
subcommands: {
describe: {
hide: false,
},
diff: {
hide: false,
},
ls: {
hide: false,
},
show: {
hide: false,
},
},
},
paths: {
hide: false,
},
save: {
hide: false,
},
status: {
hide: false,
},
track: {
hide: false,
},
unapply: {
hide: false,
},
untrack: {
hide: false,
},
},
},
files: {
Expand Down
4 changes: 4 additions & 0 deletions docs/.vitepress/sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,10 @@ export const sidebar: SidebarItem[] = [
text: "User Login Shell",
link: "/bootstrap/user",
},
{
text: "Dotfiles history",
link: "/history",
},
],
},
{
Expand Down
16 changes: 16 additions & 0 deletions docs/bootstrap.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,13 @@ preflight prevents a missing input from leaving a partially provisioned host.
17. `mise run bootstrap` runs a task named `bootstrap`, if one exists.
18. `[bootstrap.hooks.final]` runs after the bootstrap task, if configured.

Every mutating run — the full `mise bootstrap`, each `mise bootstrap <part>
apply`, and the commands that change dotfiles or bootstrap config in place
(`dotfiles add`, `unapply`, `edit`, `packages use`, `import`, brew `tap`) —
records a pair of [history checkpoints](/history.html): the tracked files
before and after the run, plus a journal of what the run changed. Dry runs
record nothing.

Use `mise bootstrap --skip <part>` to skip specific parts. Supported parts are
`accounts`, `plugins`, `packages`, `files`, `services`, `firewall`, `compose`, `repos`, `dotfiles`, `mise-shell-activate`,
`macos-defaults`, `macos-launchd-agents`, `linux-systemd-units`, `user`, `tools`,
Expand Down Expand Up @@ -215,6 +222,15 @@ mise bootstrap firewall status
mise bootstrap user status
```

Use `mise bootstrap dotfiles history` to see the checkpoints bootstrap has recorded — a pair per
mutating run, with the tracked files before and after. See [History](/history.html).

```sh
mise bootstrap dotfiles history
mise bootstrap dotfiles history show latest
mise bootstrap dotfiles history diff 11 12
```

`mise bootstrap status --missing` checks the whole declarative bootstrap
surface in one command. The narrower `mise bootstrap packages status --missing`
and `mise bootstrap dotfiles status --missing` commands are useful when you only
Expand Down
5 changes: 5 additions & 0 deletions docs/cli/bootstrap/dotfiles.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,10 @@ Manage dotfiles from `[dotfiles]`
- [`mise bootstrap dotfiles apply [FLAGS] [TARGET]…`](/cli/bootstrap/dotfiles/apply.md)
- [`mise bootstrap dotfiles diff [TARGET]…`](/cli/bootstrap/dotfiles/diff.md)
- [`mise bootstrap dotfiles edit [FLAGS] <TARGET>`](/cli/bootstrap/dotfiles/edit.md)
- [`mise bootstrap dotfiles history [FLAGS] [SUBCOMMAND]`](/cli/bootstrap/dotfiles/history.md)
- [`mise bootstrap dotfiles paths [-J --json] [--preview <PATH>]`](/cli/bootstrap/dotfiles/paths.md)
- [`mise bootstrap dotfiles save [FLAGS] [PATH]…`](/cli/bootstrap/dotfiles/save.md)
- [`mise bootstrap dotfiles status [-J --json] [--missing] [TARGET]…`](/cli/bootstrap/dotfiles/status.md)
- [`mise bootstrap dotfiles track [FLAGS] <PATH>…`](/cli/bootstrap/dotfiles/track.md)
- [`mise bootstrap dotfiles unapply [FLAGS] [TARGET]…`](/cli/bootstrap/dotfiles/unapply.md)
- [`mise bootstrap dotfiles untrack <PATH>…`](/cli/bootstrap/dotfiles/untrack.md)
42 changes: 42 additions & 0 deletions docs/cli/bootstrap/dotfiles/history.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<!-- @generated by usage-cli from usage spec -->
# `mise bootstrap dotfiles history`

- **Usage:** `mise bootstrap dotfiles history [FLAGS] [SUBCOMMAND]`
- **Effect:** read-only
- **Source code:** [`src/cli/dotfiles/history/mod.rs`](https://github.com/jdx/mise/blob/main/src/cli/dotfiles/history/mod.rs)

Browse the checkpoints of your dotfiles

Every save, every mutating bootstrap command, and the watcher record a
checkpoint of the tracked files: the global mise config directory, the
dotfiles root, and every `[dotfiles]` entry. A checkpoint holds files,
never package or service state: restoring one restores files. Without a
subcommand this lists them, newest first.

## Flags
- **`-J --json`** — Output in JSON format
- **`-n --limit <LIMIT>`** — Show at most this many checkpoints (0 for all)

**Default:** `20`
- **`--path <PATH>`** — Only checkpoints where this path (or something under it) changed
- **`--trigger <TRIGGER>`** — Only checkpoints with this trigger (edit, save, bootstrap, …)
- **`--pending`** — Only checkpoints recorded by operations that did not finish
- **`-h --help`** — Print help

## Subcommands

- [`mise bootstrap dotfiles history describe <REF> <TEXT>`](/cli/bootstrap/dotfiles/history/describe.md)
- [`mise bootstrap dotfiles history diff [FLAGS] [A] [B]`](/cli/bootstrap/dotfiles/history/diff.md)
- [`mise bootstrap dotfiles history ls [FLAGS]`](/cli/bootstrap/dotfiles/history/ls.md)
- [`mise bootstrap dotfiles history show [FLAGS] [REF]`](/cli/bootstrap/dotfiles/history/show.md)

Examples:

```
mise bootstrap dotfiles history
mise bootstrap dotfiles history --path ~/.config/hypr/bindings.lua
mise bootstrap dotfiles history show latest
mise bootstrap dotfiles history diff # the working tree against the latest checkpoint
mise bootstrap dotfiles history diff 11 12 --patch
mise bootstrap dotfiles save --description "before the theme change"
```
15 changes: 15 additions & 0 deletions docs/cli/bootstrap/dotfiles/history/describe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!-- @generated by usage-cli from usage spec -->
# `mise bootstrap dotfiles history describe`

- **Usage:** `mise bootstrap dotfiles history describe <REF> <TEXT>`
- **Effect:** modifies state
- **Source code:** [`src/cli/dotfiles/history/describe.rs`](https://github.com/jdx/mise/blob/main/src/cli/dotfiles/history/describe.rs)

Set the description of a checkpoint

## Arguments
- **`<REF>`** — Checkpoint id, `latest`, `latest~N`, or a uuid prefix
- **`<TEXT>`** — The new description

## Flags
- **`-h --help`** — Print help
22 changes: 22 additions & 0 deletions docs/cli/bootstrap/dotfiles/history/diff.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<!-- @generated by usage-cli from usage spec -->
# `mise bootstrap dotfiles history diff`

- **Usage:** `mise bootstrap dotfiles history diff [FLAGS] [A] [B]`
- **Effect:** read-only
- **Source code:** [`src/cli/dotfiles/history/diff.rs`](https://github.com/jdx/mise/blob/main/src/cli/dotfiles/history/diff.rs)

Compare checkpoints, or the working tree against one

Without arguments, shows what changed by hand since the latest
checkpoint. With one reference, shows what that checkpoint changed
against the one before it. With two, compares the two states.

## Arguments
- **`[A]`** — Checkpoint id, `latest`, `latest~N`, or a uuid prefix
- **`[B]`** — Compare `A` with this checkpoint instead of its predecessor

## Flags
- **`-p --patch`** — Print the full patch instead of a per-file summary
- **`--path <PATH>`** — Restrict to one path (a file or a directory)
- **`--exit-code`** — Exit 1 when the two sides differ
- **`-h --help`** — Print help
19 changes: 19 additions & 0 deletions docs/cli/bootstrap/dotfiles/history/ls.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!-- @generated by usage-cli from usage spec -->
# `mise bootstrap dotfiles history ls`

- **Usage:** `mise bootstrap dotfiles history ls [FLAGS]`
- **Aliases:** `list`
- **Effect:** read-only
- **Source code:** [`src/cli/dotfiles/history/ls.rs`](https://github.com/jdx/mise/blob/main/src/cli/dotfiles/history/ls.rs)

List checkpoints, newest first

## Flags
- **`-J --json`** — Output in JSON format
- **`-n --limit <LIMIT>`** — Show at most this many checkpoints (0 for all)

**Default:** `20`
- **`--path <PATH>`** — Only checkpoints where this path (or something under it) changed
- **`--trigger <TRIGGER>`** — Only checkpoints with this trigger (edit, save, bootstrap, …)
- **`--pending`** — Only checkpoints recorded by operations that did not finish
- **`-h --help`** — Print help
17 changes: 17 additions & 0 deletions docs/cli/bootstrap/dotfiles/history/show.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!-- @generated by usage-cli from usage spec -->
# `mise bootstrap dotfiles history show`

- **Usage:** `mise bootstrap dotfiles history show [FLAGS] [REF]`
- **Effect:** read-only
- **Source code:** [`src/cli/dotfiles/history/show.rs`](https://github.com/jdx/mise/blob/main/src/cli/dotfiles/history/show.rs)

Show one checkpoint: what triggered it, what changed, and its journal

## Arguments
- **`[REF]`** — Checkpoint id, `latest` (the default), `latest~N`, or a uuid prefix

## Flags
- **`-J --json`** — Output in JSON format
- **`--files`** — List every file in the snapshot
- **`--path <PATH>`** — Resolve `latest~N` among the checkpoints where this path changed
- **`-h --help`** — Print help
18 changes: 18 additions & 0 deletions docs/cli/bootstrap/dotfiles/paths.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<!-- @generated by usage-cli from usage spec -->
# `mise bootstrap dotfiles paths`

- **Usage:** `mise bootstrap dotfiles paths [-J --json] [--preview <PATH>]`
- **Effect:** read-only
- **Source code:** [`src/cli/dotfiles/paths.rs`](https://github.com/jdx/mise/blob/main/src/cli/dotfiles/paths.rs)

Show what history tracks and under which policies

Every entry is listed with the file that declared it, its policies, and
how many files it currently covers. Declarations that history could not
honour are listed as invalid, omitted, or incomplete, so a failed
enrollment is never mistaken for protection.

## Flags
- **`-J --json`** — Output in JSON format
- **`--preview <PATH>`** — Show what tracking this path would capture
- **`-h --help`** — Print help
26 changes: 26 additions & 0 deletions docs/cli/bootstrap/dotfiles/save.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<!-- @generated by usage-cli from usage spec -->
# `mise bootstrap dotfiles save`

- **Usage:** `mise bootstrap dotfiles save [FLAGS] [PATH]…`
- **Effect:** modifies state
- **Source code:** [`src/cli/dotfiles/save.rs`](https://github.com/jdx/mise/blob/main/src/cli/dotfiles/save.rs)

Save a checkpoint of the tracked files now

Fails when history cannot save or a requested path is not tracked, so a
script or an agent gets a trustworthy result; a save that finds nothing
changed succeeds as a no-op. `--best-effort` turns save errors into a
warning for `set -e` update scripts.

## Arguments
- **`[PATH]…`** — Paths to save; every one must be tracked

## Flags
- **`-d --description <TEXT>`** — A description for the checkpoint
- **`--trigger <TRIGGER>`** — What is saving: save (the default), agent, or update

**Default:** `save`
- **`--task <ID>`** — The task an agent is working on
- **`--label <LABEL>`** — A label to find the checkpoint by later
- **`--best-effort`** — Warn instead of failing when history cannot save
- **`-h --help`** — Print help
39 changes: 39 additions & 0 deletions docs/cli/bootstrap/dotfiles/track.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<!-- @generated by usage-cli from usage spec -->
# `mise bootstrap dotfiles track`

- **Usage:** `mise bootstrap dotfiles track [FLAGS] <PATH>…`
- **Effect:** modifies state
- **Source code:** [`src/cli/dotfiles/track.rs`](https://github.com/jdx/mise/blob/main/src/cli/dotfiles/track.rs)

Track a file or directory where it is

Adds a `[dotfiles]` entry with `mode = "track"`: the file stays where it
is, nothing is copied or linked, and history saves a checkpoint of it
right away. With the history watcher service running, later edits are
saved automatically; without it, `mise bootstrap dotfiles save` saves them.

`--os` and `--profile` declare a variant: a separate shared stream for
machines matching that platform or mise environment, so a Mac and a
Linux box can share the same live path with different contents.

## Arguments
- **`<PATH>…`** — Paths to track (absolute or starting with ~/)

## Flags
- **`--os <OS>`** — Declare a variant for this platform (macos, linux, linux/arm64, …)
- **`--profile <PROFILE>`** — Declare a variant for this mise environment
- **`--no-autosave`** — Save only on `mise bootstrap dotfiles save <path>`, never automatically
- **`--no-share`** — Keep the file out of the shared setup (still backed up)
- **`--no-backup`** — Keep the file out of remote backups (still protected locally)
- **`--local`** — Write to config.local.toml (this machine only) instead of config.toml
- **`-y --yes`** — Accept without prompting
- **`-h --help`** — Print help

Examples:

```
mise bootstrap dotfiles track ~/.zshrc ~/.config/hypr
mise bootstrap dotfiles track ~/.zshrc --os macos
mise bootstrap dotfiles track ~/.config/app/state.json --no-autosave
mise bootstrap dotfiles track ~/.ssh/config --no-share
```
24 changes: 24 additions & 0 deletions docs/cli/bootstrap/dotfiles/untrack.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<!-- @generated by usage-cli from usage spec -->
# `mise bootstrap dotfiles untrack`

- **Usage:** `mise bootstrap dotfiles untrack <PATH>…`
- **Effect:** modifies state
- **Source code:** [`src/cli/dotfiles/untrack.rs`](https://github.com/jdx/mise/blob/main/src/cli/dotfiles/untrack.rs)

Stop tracking a file or directory

Removes the `[dotfiles]` track entry (or switches an inherited one off in
config.local.toml) and stops future captures. The file itself and its
existing checkpoints are left exactly as they are.

## Arguments
- **`<PATH>…`** — Paths to stop tracking

## Flags
- **`-h --help`** — Print help

Examples:

```
mise bootstrap dotfiles untrack ~/.zshrc
```
9 changes: 9 additions & 0 deletions docs/cli/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,17 @@
- [`mise bootstrap dotfiles apply [FLAGS] [TARGET]…`](/cli/bootstrap/dotfiles/apply.md)
- [`mise bootstrap dotfiles diff [TARGET]…`](/cli/bootstrap/dotfiles/diff.md)
- [`mise bootstrap dotfiles edit [FLAGS] <TARGET>`](/cli/bootstrap/dotfiles/edit.md)
- [`mise bootstrap dotfiles history [FLAGS] [SUBCOMMAND]`](/cli/bootstrap/dotfiles/history.md)
- [`mise bootstrap dotfiles history describe <REF> <TEXT>`](/cli/bootstrap/dotfiles/history/describe.md)
- [`mise bootstrap dotfiles history diff [FLAGS] [A] [B]`](/cli/bootstrap/dotfiles/history/diff.md)
- [`mise bootstrap dotfiles history ls [FLAGS]`](/cli/bootstrap/dotfiles/history/ls.md)
- [`mise bootstrap dotfiles history show [FLAGS] [REF]`](/cli/bootstrap/dotfiles/history/show.md)
- [`mise bootstrap dotfiles paths [-J --json] [--preview <PATH>]`](/cli/bootstrap/dotfiles/paths.md)
- [`mise bootstrap dotfiles save [FLAGS] [PATH]…`](/cli/bootstrap/dotfiles/save.md)
- [`mise bootstrap dotfiles status [-J --json] [--missing] [TARGET]…`](/cli/bootstrap/dotfiles/status.md)
- [`mise bootstrap dotfiles track [FLAGS] <PATH>…`](/cli/bootstrap/dotfiles/track.md)
- [`mise bootstrap dotfiles unapply [FLAGS] [TARGET]…`](/cli/bootstrap/dotfiles/unapply.md)
- [`mise bootstrap dotfiles untrack <PATH>…`](/cli/bootstrap/dotfiles/untrack.md)
- [`mise bootstrap files <SUBCOMMAND>`](/cli/bootstrap/files.md)
- [`mise bootstrap files apply [FLAGS]`](/cli/bootstrap/files/apply.md)
- [`mise bootstrap files status [FLAGS]`](/cli/bootstrap/files/status.md)
Expand Down
Loading
Loading