Skip to content

fix(worktree): prune and remove only this workspace's sets - #35

Merged
gold-silver-copper merged 24 commits into
mainfrom
fix/meta-stable-dotmeta
Oct 28, 2026
Merged

gold-silver-copper merged 24 commits into
mainfrom
fix/meta-stable-dotmeta

Conversation

@gold-silver-copper

@gold-silver-copper gold-silver-copper commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor
  • prune finds sets only through records in the workspace's repos and keeps a set with any foreign member; remove refuses another workspace's set (also with --force), names that workspace, and lists parts of the workspace it couldn't read.
  • Run from inside a set, worktree commands (create, list, remove, prune) find sets where the checkout the set stands for keeps them; a set created there records that checkout as its project, and its .gitignore entry goes there.
  • create and add place each repo at its path from the meta config (as --recursive already did), so a set mirrors the workspace layout; a plan has one worktree per place (one branch each; a conflict is refused), parents (derived from places, found by path) first; add compares places as paths (Windows separators); worktree exec --include takes project names, also in a set without its root.
  • add dedupes by place too (a repo given by name and by path is one worktree; on two branches it is refused before git runs). add also compares real destinations, so a member behind a link is found before git runs, and refuses a place that already holds something (a nested repo already in the set, or files in the way, named as such). Automatic parents come only from the workspace's projects (looked up through only the configs on the parent's path), so a set never holds a repo remove would call foreign and a broken unrelated nested config doesn't stop create. worktree exec takes names through set_config and repo_names, reading configs only with a filter.
  • Hooks read the workspace's config (owner_dir) and run in its directory, worked out before anything is deleted, so remove/prune run from inside the set they delete still fire post-destroy/post-prune.
  • Skipped parents print a visible warning; the dry run notes a project at a link; --no-deps help says a nested repo still gets its parent project.
  • meta git clone escapes the URL it echoes.
  • create --all --recursive covers every nested level; add doesn't print ✓ Added before a failed record write; a bad --ttl gives one error; prune lists a kept set once.
  • Unknown subcommands, recursive alias errors, rejected commit-ish/--meta/--from-pr values, the PR branch, the dry-run preview, prune's kept names and clap errors are escaped (clap errors via meta_cli::args::escaped_error).
  • The "orphaned (all source repos removed from project)" prune reason is gone: such a set is no longer the workspace's (see the root PR).

Part of the meta stability set: gitkb/meta#128 has the full description and how it was verified. Merge together with it (same branch name, so CI builds them together).

Implements [[tasks/harmony-2793]]

prune finds sets only through the records in this workspace's repos, no
longer by listing the worktree root, so a shared or foreign
META_WORKTREES adds nothing. Every candidate's members are checked: a
set with a worktree from another workspace's repository is kept, with
the reason. remove refuses such a set, naming the workspace its record
names; --force doesn't override this. remove now needs a meta workspace.

The "all source repos removed from project" prune reason is gone: such
a set is no longer this workspace's (its check compared set paths with
project names, too). Records prune can't use are named after their set,
and prune lists each kept set once.

create's rollback also exempts missing records (a write that failed
after other worktrees were recorded). create --all --recursive includes
every repo of the nested tree, not only the top level.

[[tasks/harmony-2793]]
…error

add no longer prints "✓ Added" for a worktree whose record write then
failed; it is reported in the error only. A worktree argument that clap
rejects (a bad --ttl, say) prints clap's message once as the error,
not "error: error:" followed by the whole git help.

[[tasks/harmony-2793]]
Adapt to meta_core's Result-returning config lookups: a config that
can't be read, or two configs in one directory, is an error instead of
"no config".

[[tasks/harmony-2793]]
@coderabbitai

coderabbitai Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: fdfd1e98-1a04-4569-92e2-015a83a2ea97
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

…adable parts

An unknown worktree subcommand is escaped, and a clap error is rendered
from the escaped arguments, so a value can't move the cursor or forge a
line. remove's refusal lists the parts of the workspace it couldn't
read.

[[tasks/harmony-2793]]
Clap errors go through meta_cli::args::escaped_error.

[[tasks/harmony-2793]]
Recursive alias errors are escaped. Prune says when this workspace has
no sets.

[[tasks/harmony-2793]]
Records whose project is another workspace's (one sharing the root's
git dir) are not this workspace's to forget or list. Kept names are
escaped in the final warning. A relative gitdir (worktree.useRelativePaths)
finds its set.

[[tasks/harmony-2793]]
…lues

Rejected commit-ish values, --meta values and the PR branch are escaped.

[[tasks/harmony-2793]]
…ry-run

A set whose project is gone is no longer this workspace's. The dry-run
preview escapes commit-ish, PR spec and metadata.

[[tasks/harmony-2793]]
… for

Its .gitignore entry goes there too. The diff heading escapes --base.

[[tasks/harmony-2793]]
… URL

The owning checkout is computed once in create.

[[tasks/harmony-2793]]
worktree exec selects by the set's project names. Help text says name
or path.

[[tasks/harmony-2793]]
worktree exec finds names in the set's config or the workspace's above.

[[tasks/harmony-2793]]
A set elsewhere without its root takes names from the recorded
project's config.

[[tasks/harmony-2793]]
… uses set_config

worktree add refuses one repo given by name and path on two branches before git runs. Automatic parents come only from the workspace's projects. worktree exec reads names through set_config and repo_names, only with a filter.

Implements [[tasks/harmony-2793]]
…ehind links

project_at reads only the configs on a parent's path, so a broken unrelated nested config doesn't stop create. add compares real destinations with existing members before git runs.

Implements [[tasks/harmony-2793]]
…o-deps help

Skipped parents print a warning on stderr; the dependency line escapes its names; the dry run notes a project at a link; --no-deps help says a nested repo still gets its parent project.

Implements [[tasks/harmony-2793]]
A plain directory on a repo's path is no parent and needs no warning.

Implements [[tasks/harmony-2793]]
worktree exec --include/--exclude name a nested repo whose parent the set lacks, as the host does.

Implements [[tasks/harmony-2793]]
…eleting

remove and prune run from inside the set they delete fire post-destroy/post-prune from owner_dir; create's post-create too.

Implements [[tasks/harmony-2793]]
The strict recursive scan failed on sets holding a submodule or an unreadable directory. A nested repo already in the set is caught because its place holds something.

Implements [[tasks/harmony-2793]]
@gold-silver-copper
gold-silver-copper merged commit bfa2aa8 into main Oct 28, 2026
7 checks passed
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