feat: hotfix version script worktree - #22
Closed
jopmiddelkamp wants to merge 6 commits into
Closed
Conversation
is_working_tree_clean_at / stage_all_at / commit_at run via -C (the remove_current_worktree precedent; CommandRunner untouched) and remove_worktree removes a worktree by path with --force. Flags-table rows red-first; MockGit records path-bearing encodings and gains an add_worktree_error knob.
Second trait method (changing run's signature would break every mock encoding): re-derives the script path relative to the repo root inside dir and spawns with cwd = dir — repo content applies to the tree it lives in. ScriptCli's spawn stays one zero-policy helper; the mock's failure knobs and run counter are shared across both entry points.
…hemeral worktree Spec change: replaces the mutation-pinned hotfix_no_checkout_skips_script (mutation-audit trap 9, 'the script must never run without a checkout'). The invariant 'release/hotfix branches carry their version' now holds in every mode: after create_branch_no_checkout, bflow adds a temporary worktree, runs the branch's own script copy there, commits, removes the worktree, and pushes once — the user's checkout is never touched. Script failure falls back to warn-and-continue with the manual recovery steps (M2 precedent): a broken script must never block the hotfix.
Script failure: warn, remove the worktree, still push (mutation-verified: propagating the error instead fails both tests; dropping the cleanup fails three). add_worktree failure: nothing to remove, script never runs, push still proceeds.
…ons.md README: no-checkout hotfix section rewritten (script runs via temp worktree; warning only when the script itself fails), --no-checkout positioned as the low-level escape hatch under worktree mode. decisions.md: Landing Modes entry for the mechanism and the trap-9 supersede; Boundaries note extended for the _at primitive family.
There was a problem hiding this comment.
Pull request overview
Adds temporary worktree support so checkout-less hotfixes can run and commit version scripts without modifying the user’s checkout.
Changes:
- Adds temporary worktree paths and Git operations.
- Runs version scripts inside the hotfix worktree.
- Adds tests and updates user/architecture documentation.
Architecture: Keep the temporary-worktree approach after fixing discovery, error propagation, and crash recovery. It preserves version invariants but adds resource-lifecycle complexity; reversal is moderately costly due to the expanded ports and documented behavior.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
src/flows/mod.rs |
Orchestrates temporary worktree execution. |
src/flows/start.rs |
Integrates execution into hotfix creation. |
src/git/mod.rs |
Adds worktree-targeted Git primitives. |
src/version_script.rs |
Executes scripts in another worktree. |
src/worktree.rs |
Generates temporary worktree paths. |
tests/common/mod.rs |
Extends test mocks. |
tests/start_test.rs |
Tests checkout-less hotfix scenarios. |
tests/git_cli_test.rs |
Verifies new Git commands. |
tests/worktree_test.rs |
Tests temporary path generation. |
README.md |
Documents user-facing behavior. |
.claude/skills/bflow/SKILL.md |
Updates workflow guidance. |
.claude/skills/architecture/decisions.md |
Records the architectural decision. |
Suppressed comments (1)
src/flows/start.rs:325
- The
VersionScriptoption was resolved from the invoking worktree (main.rs:57-60), but--no-checkoutmay auto-discover a hotfix from any current branch (cli.rs:148-196). If that current branch lacks the script whilemain(and therefore the new hotfix branch) contains it, this call is never reached and the hotfix is pushed unversioned. Discover script presence in the temporary target worktree before deciding to skip so the branch-own-copy guarantee actually holds.
if let Err(e) = run_version_script_in_temp_worktree(git, script, &branch, &next) {
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+325
to
+326
| if let Err(e) = run_version_script_in_temp_worktree(git, script, &branch, &next) { | ||
| eprintln!("⚠ Version script failed in a temporary worktree: {e}"); |
Comment on lines
+249
to
+250
| let path = crate::worktree::temp_worktree_path(&repo_root, branch); | ||
| git.add_worktree(&path, branch)?; |
| ## Boundaries & Extensibility | ||
|
|
||
| - **`Git` is 48 fine-grained primitives** so ordering logic lives in flows and mocks can record exact sequences. Rejected: coarse `finish_release()`-style methods (untestable ordering). One deliberate exception to cwd-relative primitives: `remove_current_worktree` runs via `-C <main root>` (git refuses to remove the worktree it runs in) and must be the *last* git call of a flow — the process cwd is deleted afterwards, so remote-branch deletion is ordered before it. | ||
| - **`Git` is 48 fine-grained primitives** so ordering logic lives in flows and mocks can record exact sequences. Rejected: coarse `finish_release()`-style methods (untestable ordering). Deliberate exceptions to cwd-relative primitives: `remove_current_worktree` runs via `-C <main root>` (git refuses to remove the worktree it runs in) and must be the *last* git call of a flow — the process cwd is deleted afterwards, so remote-branch deletion is ordered before it; and the `_at` family (`is_working_tree_clean_at`/`stage_all_at`/`commit_at`, plus `remove_worktree(path)`) targets the ephemeral version-script worktree via `-C <dir>` — no last-call constraint there, the process never stands in it. `CommandRunner` stays cwd-free in both cases: the directory travels in the arg vector. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.