From d27bf457406d9db6e9bb53719df44727a4ef92f5 Mon Sep 17 00:00:00 2001 From: Lex Christopherson Date: Sun, 15 Mar 2026 09:05:03 -0600 Subject: [PATCH] fix(auto-worktree): use execFileSync for git commands with user content MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Shell string interpolation of multi-line commit messages breaks on Windows — the closing quote gets consumed mid-message, causing the branch name suffix to be parsed as a second argument to git merge (producing "fatal: No remote for the current branch"). Switch to execFileSync with argument arrays for merge, commit, and add commands that include user-generated content. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/resources/extensions/gsd/auto-worktree.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/resources/extensions/gsd/auto-worktree.ts b/src/resources/extensions/gsd/auto-worktree.ts index c1801e3c4..7dd510d60 100644 --- a/src/resources/extensions/gsd/auto-worktree.ts +++ b/src/resources/extensions/gsd/auto-worktree.ts @@ -8,7 +8,7 @@ import { existsSync, readFileSync, realpathSync, utimesSync } from "node:fs"; import { join, resolve } from "node:path"; -import { execSync } from "node:child_process"; +import { execSync, execFileSync } from "node:child_process"; import { createWorktree, removeWorktree, @@ -308,7 +308,7 @@ export function mergeSliceToMilestone( // Merge --no-ff (with self-healing retry for transient failures) try { withMergeHeal(cwd, () => { - execSync(`git merge --no-ff -m "${message.replace(/"/g, '\\"')}" ${sliceBranch}`, { + execFileSync("git", ["merge", "--no-ff", "-m", message, sliceBranch], { cwd, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8", @@ -361,7 +361,8 @@ function autoCommitDirtyState(cwd: string): boolean { encoding: "utf-8", }).trim(); if (!status) return false; - execSync('git add -A && git commit -m "chore: auto-commit before milestone merge"', { + execFileSync("git", ["add", "-A"], { cwd, stdio: "pipe" }); + execFileSync("git", ["commit", "-m", "chore: auto-commit before milestone merge"], { cwd, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8", @@ -451,7 +452,7 @@ export function mergeMilestoneToMain( // 8. Commit (handle nothing-to-commit gracefully) let nothingToCommit = false; try { - execSync(`git commit -m ${JSON.stringify(commitMessage)}`, { + execFileSync("git", ["commit", "-m", commitMessage], { cwd: originalBasePath_, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8",