Skip to content

Worktree-per-task workflow: retire working-branch, fix check-dotfiles' checkout resolution - #29

Merged
tlockney merged 2 commits into
mainfrom
worktree-conventions
Jul 27, 2026
Merged

Worktree-per-task workflow: retire working-branch, fix check-dotfiles' checkout resolution#29
tlockney merged 2 commits into
mainfrom
worktree-conventions

Conversation

@tlockney

Copy link
Copy Markdown
Owner

Why

Asked to park ~/src/personal/dotfiles back on working-branch and establish a convention where future work happens in its own worktree on its own branch. Dogfooding that convention — this PR was built in a worktree — immediately broke three things.

What dogfooding found

1. just check reported "All 0 checks passed" from a worktree.

The recipe called ~/bin/check-dotfiles, which resolves its repo root from its own location — so from a worktree it scanned $HOME, not the worktree. $HOME is the yadm main worktree and has no .git directory of its own, so git ls-files matched nothing and every section trivially passed. A green run that checked nothing is the worst result this script can produce, and my own Justfile recipe walked straight into it.

Fixed by using ./bin/check-dotfiles. The other recipes keep ~/bin because they act on the live system rather than a checkout.

2. Nothing prevented that from recurring silently.

The script now refuses to run outside a git checkout, and refuses to report success when it matched zero files. Both verified:

$ /tmp/notarepo/bin/check-dotfiles syntax
Error: /tmp/notarepo is not a git checkout; refusing to report a pass over nothing

$ ./bin/check-dotfiles syntax        # git repo, nothing tracked
Error: no files were checked -- expected at least one match in /tmp/emptyrepo

3. Every new worktree is broken for mise-shimmed tools.

This repo ships .config/mise/config.toml, so mise treats any checkout as a project config and refuses to run until that exact path is trusted. A freshly created worktree is untrusted, so python3, node, uvx — all mise shims — exit 1 instead of running. This surfaced as 73 "parse error" failures against config files that are entirely valid.

That is not a problem with this script; it affects anything you run in a new worktree. It is now documented as a required step, and the script probes for it:

Error: python3 will not run in .../worktree-conventions:
mise ERROR Config files in .../.config/mise/config.toml are not trusted.
  If that mentions mise, this checkout is untrusted. Run: mise trust

The documented convention

~/src/personal/dotfiles stays parked on working-branch as a stable, current checkout and is not where edits happen. Each task gets ../dotfiles-worktrees/<task> on its own branch off origin/main, trusted with mise trust, validated with just check, then removed when merged.

The README also records two traps hit during this session: never git checkout main in a linked worktree (main belongs to the $HOME worktree), and never a bare git commit after a git rm — it commits the whole index and will sweep unrelated staged changes into your commit, which is exactly what happened to the lint.yml deletion in #28 before I redid those commits.

Verification

From the worktree, after mise trust:

syntax   All 39 checks passed
configs  All 77 checks passed
shell    All 3 checks passed
emacs    All 1 checks passed

configs is 77 locally vs 97 in CI because the runner has luac and this Mac does not — reported as SKIP, not a silent pass.

…trees

Running the checks from a second worktree turned up three problems, all of
which made a broken setup look fine.

`just check` invoked ~/bin/check-dotfiles, which resolves its repo root from
its own location, so from a worktree it scanned $HOME instead. $HOME is the
yadm main worktree and has no .git directory of its own, so git ls-files
matched nothing and the run reported "All 0 checks passed" -- a green result
over an empty file list. The recipe now uses ./bin/check-dotfiles so it
validates the checkout you are standing in. The other recipes keep using
~/bin because they act on the live system rather than a checkout.

The script now refuses to run outside a git checkout, and refuses to report
success when it matched no files at all, so that failure cannot recur
silently.

It also now probes python3 before using it. This repo ships
.config/mise/config.toml, which mise picks up as a project config whenever the
cwd is inside a checkout, and a freshly created worktree is untrusted by
default -- so every mise-shimmed binary exits 1 rather than running. That
surfaced as 73 "parse error" failures against config files that are perfectly
valid. The probe turns it into one message naming `mise trust`.

README documents the worktree-per-task workflow this exercised, including the
mise trust step and the reason a bare `git commit` after `git rm` is a trap.
@tlockney
tlockney marked this pull request as ready for review July 27, 2026 21:36
working-branch existed to give quick, exploratory edits somewhere to live
without the overhead of a branch and a checkout. The worktree convention
covers that case now, so keeping it around only preserves a second, softer
path where changes reach $HOME without review.

~/src/personal/dotfiles becomes the launcher: detached at origin/main, used to
read the tree and start tasks from, never edited in. Detached rather than on a
branch because a linked worktree cannot check out main -- $HOME already has it
-- and because with no branch there is nowhere for a stray edit to accumulate.

To keep starting a task as cheap as working-branch was, `just worktree <name>`
creates the worktree off origin/main, puts it on its own branch, and runs mise
trust so shimmed binaries work there. `just worktree-done <name>` removes it
again, deletes the branch with -d so unmerged work is refused rather than
discarded, and re-parks the launcher at origin/main. Both resolve the
worktrees directory whether run from the launcher or from another task
worktree, and worktree-done declines to re-park when it is not the launcher or
when the tree is dirty.

The raycast toolbox README pointed at `yadm merge working-branch`; it now
points at `yadm fetch && yadm merge origin/main`. The dated plan under
.config/dotfiles/plans/ still mentions working-branch and is left alone: it
records what was true when it was written.
@tlockney tlockney changed the title Worktree-per-task workflow, and make check-dotfiles validate the right checkout Worktree-per-task workflow: retire working-branch, fix check-dotfiles' checkout resolution Jul 27, 2026
@tlockney
tlockney merged commit ac875a8 into main Jul 27, 2026
1 check passed
@tlockney
tlockney deleted the worktree-conventions branch July 27, 2026 23:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant