fix(auto): prevent nested worktree creation inside existing worktrees (#511)
* fix(auto): prevent nested worktree creation inside existing worktrees When auto-mode starts inside a manual worktree (e.g., /worktree memory-db), it unconditionally created an auto-worktree for the milestone, nesting .gsd/worktrees/M001 inside the existing worktree. This caused GSD to chdir into the inner worktree, read state from the wrong repo, and report "All milestones complete" or loop on artifact verification. Add detectWorktreeName() guard to both the start and resume paths: if already inside a worktree, skip auto-worktree creation and work directly on the current branch. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
parent
27d07a35d7
commit
f59301e4ba
1 changed files with 19 additions and 2 deletions
|
|
@ -69,11 +69,13 @@ import {
|
|||
getProjectTotals, formatCost, formatTokenCount,
|
||||
} from "./metrics.js";
|
||||
import { dirname, join } from "node:path";
|
||||
import { sep as pathSep } from "node:path";
|
||||
import { readdirSync, readFileSync, existsSync, mkdirSync, writeFileSync, unlinkSync } from "node:fs";
|
||||
import { execSync, execFileSync } from "node:child_process";
|
||||
import {
|
||||
autoCommitCurrentBranch,
|
||||
captureIntegrationBranch,
|
||||
detectWorktreeName,
|
||||
getCurrentBranch,
|
||||
getMainBranch,
|
||||
MergeConflictError,
|
||||
|
|
@ -505,7 +507,8 @@ export async function startAuto(
|
|||
if (currentMilestoneId) setActiveMilestoneId(base, currentMilestoneId);
|
||||
|
||||
// ── Auto-worktree: re-enter worktree on resume if not already inside ──
|
||||
if (currentMilestoneId && originalBasePath && !isInAutoWorktree(basePath)) {
|
||||
// Skip if already inside a worktree (manual /worktree) to prevent nesting.
|
||||
if (currentMilestoneId && originalBasePath && !isInAutoWorktree(basePath) && !detectWorktreeName(basePath) && !detectWorktreeName(originalBasePath)) {
|
||||
try {
|
||||
const existingWtPath = getAutoWorktreePath(originalBasePath, currentMilestoneId);
|
||||
if (existingWtPath) {
|
||||
|
|
@ -668,8 +671,22 @@ export async function startAuto(
|
|||
|
||||
// ── Auto-worktree: create or enter worktree for the active milestone ──
|
||||
// Store the original project root before any chdir so we can restore on stop.
|
||||
// Skip if already inside a worktree (manual /worktree or another auto-worktree)
|
||||
// to prevent nested worktree creation.
|
||||
originalBasePath = base;
|
||||
if (currentMilestoneId) {
|
||||
|
||||
const isUnderGsdWorktrees = (p: string): boolean => {
|
||||
// Prevent creating nested auto-worktrees when running from within any
|
||||
// `.gsd/worktrees/...` directory (including manual worktrees).
|
||||
const marker = `${pathSep}.gsd${pathSep}worktrees${pathSep}`;
|
||||
if (p.includes(marker)) {
|
||||
return true;
|
||||
}
|
||||
const worktreesSuffix = `${pathSep}.gsd${pathSep}worktrees`;
|
||||
return p.endsWith(worktreesSuffix);
|
||||
};
|
||||
|
||||
if (currentMilestoneId && !detectWorktreeName(base) && !isUnderGsdWorktrees(base)) {
|
||||
try {
|
||||
const existingWtPath = getAutoWorktreePath(base, currentMilestoneId);
|
||||
if (existingWtPath) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue