-
Notifications
You must be signed in to change notification settings - Fork 0
fix(guardrails): align worktree creation with upstream pattern (Issue #144) #152
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -271,26 +271,34 @@ async function yardadd(dir: string, id: string) { | |||||
| const base = yard(dir) | ||||||
| const next = path.join(base, slug(id)) | ||||||
| await mkdir(base, { recursive: true }) | ||||||
|
|
||||||
| // Verify repository has commits | ||||||
| const head = await git(dir, ["rev-parse", "--verify", "HEAD"]) | ||||||
| if (head.code !== 0) { | ||||||
| throw new Error("Cannot create worktree: repository has no commits. Create an initial commit first.") | ||||||
| } | ||||||
| const made = await git(dir, ["worktree", "add", "--detach", next, "HEAD"]) | ||||||
| if (made.code !== 0) throw new Error(made.err || made.out || "Failed to create git worktree") | ||||||
| // Verify worktree actually has files (Issue #144: empty git init) | ||||||
| const files = await git(next, ["ls-files", "--cached"]).catch(() => ({ code: 1, out: "", err: "" })) | ||||||
| if (files.code !== 0 || !files.out.trim()) { | ||||||
| // Worktree might be empty — force checkout HEAD contents | ||||||
| const checkout = await git(next, ["checkout", "HEAD", "--", "."]) | ||||||
| if (checkout.code !== 0) { | ||||||
| throw new Error(`Worktree created but checkout failed: ${checkout.err || checkout.out}`) | ||||||
| } | ||||||
| // Re-verify files are present | ||||||
| const recheck = await git(next, ["ls-files", "--cached"]).catch(() => ({ code: 1, out: "", err: "" })) | ||||||
| if (recheck.code !== 0 || !recheck.out.trim()) { | ||||||
| throw new Error("Worktree is still empty after checkout — cannot proceed with delegation") | ||||||
| } | ||||||
|
|
||||||
| // Step 1: Create worktree without checking out files (upstream pattern) | ||||||
| const made = await git(dir, ["worktree", "add", "--detach", "--no-checkout", next, "HEAD"]) | ||||||
| if (made.code !== 0) { | ||||||
| await git(dir, ["worktree", "remove", "--force", next]).catch(() => {}) | ||||||
| throw new Error(made.err || made.out || "Failed to create git worktree") | ||||||
| } | ||||||
|
|
||||||
| // Step 2: Hard reset to populate working directory (upstream pattern) | ||||||
| const populated = await git(next, ["reset", "--hard"]) | ||||||
| if (populated.code !== 0) { | ||||||
| await git(dir, ["worktree", "remove", "--force", next]).catch(() => {}) | ||||||
| throw new Error(`Worktree created but population failed: ${populated.err || populated.out}`) | ||||||
| } | ||||||
|
|
||||||
| // Step 3: Verify files are actually present in the working directory | ||||||
|
||||||
| // Step 3: Verify files are actually present in the working directory | |
| // Step 3: Verify the worktree has tracked files in Git after reset |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The cleanup on Step 1 failure isn’t guaranteed to remove a partially-created directory:
git worktree removeonly works for worktrees that were successfully registered, so ifworktree addfails before registration you can still end up with a leftovernext/directory that will break subsequent retries. Consider adding a filesystem fallback (scoped to theyard(dir)base) to deletenextwhenworktree removefails/no-ops, and/or explicitly handle the “not a working tree” case.