Fix five defects in git-trees#36
Conversation
**#18 — `init --host` / `--dir` with no value hang forever.** `shift 2` with one argument left fails and leaves `$1` in place, so `while [ $# -gt 0 ]` spins. `"${2:-}"` defends against `set -u`, which is why it read as safe; the bug is the shift. Both options now check arity first. (`clean --older-than` has the same defect and is fixed by that command's removal in #17.) **#22 — `init` printed success after post-clone steps failed.** The refspec and fetch are what give a bare clone its remote-tracking refs; without them `add` cannot resolve the default branch. They are now chained and roll back the directory on failure, matching the clone path, so a retry is not blocked by "already exists". `set-head --auto` stays unchecked — it fails harmlessly against a remote with no HEAD. **#23 — `list --json` emitted invalid JSON for a path containing a backslash.** Only `"` was escaped. Escaping is now done character by character: awk reads `"\\"` in a *replacement* string as one literal backslash, so the obvious `gsub(/\\/, "\\\\", s)` under-escapes. Control characters map to `\u00XX`. **#31 — `add` reported the wrong error for `.`, `..`, and other invalid names.** `add ..` resolved to `$root/..`, which always exists, so it failed with a directory collision; `add 'has space'` failed only after `worktree add` printed "Preparing worktree…". Names are now validated with `git check-ref-format` before anything else touches them. Leading-dash names remain unsupported and are documented under Known limitations. **#32 — `_seed_agents` operator-precedence guard.** `[ -e f ] || [ -L f ] && return 0` groups as `{ A || B; } && return 0`, so the compound status is 1 when neither test holds. Both guards are now explicit `if` blocks, and a genuine write failure reports why instead of returning bare 1. CI gains assertions for each: the missing-value cases bounded so a regression fails instead of hanging the runner, `add .` / `..` / `'has space'`, and a `list --json` round-trip through a path containing `\` and `"`. Closes #18, closes #22, closes #23, closes #31, closes #32. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
leogdion
left a comment
There was a problem hiding this comment.
what happens when an existing branch has a slash
`add feature/x` was rejected outright by a `*/*` guard that ran before any existence check, so a branch already present locally or on origin could never get a worktree — and the error told you to rename it. `list` meanwhile enumerated refs/heads unfiltered and showed `feature/x` with path `(none)`, advertising branches `add` refused to serve. The restriction was only ever about the directory name: every worktree is a direct child of the container root, so a branch's `/` cannot be a directory separator. Slug it to `-` instead and leave the branch name alone. `feature/x` and `feature-x` now compete for one directory. `_branch_at` reports which branch owns it so the collision error says what to rename, rather than inventing a suffixed variant the user cannot predict. `git check-ref-format` becomes the sole name validator — it already accepts `feature/x` and rejects `.`, `..`, `has space`, and `a//b`. Silenced, since it runs ahead of the `--print-path` branch. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
It was rejected outright, and the error was misleading. The Fixed in f0e28af by supporting them. The restriction was only ever about the directory name — worktrees are direct children of the container root and can't nest — so the directory now slugs The consequence is that
|
Merge order: 2 of 6, into
v1.0.0-integration. Cut from the same commit asmain, so it still containsclean; expect aci.ymlconflict with #35, whichdeletes that command.
Closes #18, closes #22, closes #23, closes #31, closes #32.
Five independent defects, all in
git-trees, in disjoint hunks.#18 — missing option value hangs forever
shift 2with one argument left fails and leaves$1in place, sowhile [ $# -gt 0 ]spins."${2:-}"defends againstset -u, which is why itreads as safe — the bug is the
shift, not the expansion. Both--hostand--dirnow check arity first.clean --older-thanhas the identical defect. It is not fixed here — thatcommand is deleted by #35. Merging this PR without #35 leaves that one hang in
place.
#22 —
initprinted success after post-clone steps failedThe refspec and
fetchare what give a bare clone its remote-tracking refs;without them the container has no
origin/*andaddcannot resolve thedefault branch. Now chained, with the same
rm -rf "$dir"rollback as the clonepath — so a retry isn't blocked by
init: $dir already exists.set-head --autostays unchecked; it fails harmlessly against a remote with noHEAD.
#23 —
list --jsoninvalid for paths containing\Only
"was escaped, so\sreached the output and strict parsers rejected thedocument. Fixed with a character loop rather than
gsub:Control characters now map to
\u00XX.#31 —
addreported the wrong error for invalid namesadd ..resolved to$root/.., which always exists, so it failed with adirectory collision;
add 'has space'failed only afterworktree addhadprinted
Preparing worktree…. Names are validated withgit check-ref-formatbefore anything else touches them.
git check-ref-format "refs/heads/$br"— not--branch, which expands@{-1}and needs a repo.
Leading-dash names stay unsupported (parsed as options) and are now documented
under Known limitations.
#32 —
_seed_agentsoperator precedence[ -e f ] || [ -L f ] && return 0groups as{ A || B; } && return 0, so thecompound status is 1 when neither test holds. Both guards are explicit
ifblocks now; both tests are kept, since
-eis false for a broken symlink while-Lis true. A genuine write failure now reports why instead of a bare1.Verified
bash -nandshellcheck -s bashclean. Againstfile://fixtures:init --host/--dir/org/repo --host, no valueinit --dir okdir(valid)add ...'has space'tilde~xends.locka..bPreparing worktree, none report a collisionadd feature/xback\slash "quoted"JSONDecodeError: Invalid \escape; new → parses, path round-trips byte-exact_seed_agents: absent / regular file / broken symlink / unwritable dirMINE/ leaves the link / exits 1 with a messageBoth
AGENTS.mdregressions re-checked:add feature-x→origin/feature-x,add brandnew→origin/brandnew. The full smoke block was run locally end toend before pushing.
🤖 Generated with Claude Code