🐛 fix(vscode): worktree 清理改 rm -rf + prune,绕开 gitignored 产物导致的目录非空
git worktree remove 只删跟踪文件+admin 注册,不删 .next/node_modules 等 gitignored 产物,删完残留把目录撑住、最后 rmdir 撞 ENOTEMPTY。新增 removeWorktreeDir(带路径护栏的递归强删 + git worktree prune),替换 3 处 worktree remove 调用点。
This commit is contained in:
1 parent
cace658ac1
commit
235cd9ea65
3 files changed
+47
-57
No files matched your search
@@ -1,13 +1,12 @@
|
||||
import type { IssueColumn } from '../../gitea/types'
|
||||
import type { KanbanWebviewPanel } from '../KanbanPanel'
|
||||
import { Buffer } from 'node:buffer'
|
||||
import { execFile } from 'node:child_process'
|
||||
import { randomUUID } from 'node:crypto'
|
||||
import * as fs from 'node:fs'
|
||||
import { promises as fsp } from 'node:fs'
|
||||
import * as os from 'node:os'
|
||||
import * as path from 'node:path'
|
||||
import { resolveWorktreePath } from '../../git/worktree'
|
||||
import { removeWorktreeDir, resolveWorktreePath } from '../../git/worktree'
|
||||
import { commands, env, ThemeColor, Uri, window, workspace } from 'vscode'
|
||||
import { getToken } from '../../auth/secrets'
|
||||
import { buildCcCommand } from '../../cc/ccCommand'
|
||||
@@ -450,9 +449,8 @@ export async function handleColumnChange(panel: KanbanWebviewPanel, issueNumber:
|
||||
if (worktreePath) {
|
||||
const abs = resolveWorktreePath(worktreePath, workspaceRoot)
|
||||
if (fs.existsSync(abs)) {
|
||||
// worktree 还被占用时(实施/测试会话终端 cwd 在里面、cc/codex 持有 git
|
||||
// 锁或打开文件)git worktree remove 会失败。先 dispose 该工单的全部会话
|
||||
// 终端,再等一小会让进程退出释放占用,然后再删。
|
||||
// 删前先 dispose 该工单的全部会话终端并等一小会:实施/测试会话可能仍在
|
||||
// worktree 里跑(写构建产物、持有 cwd),先让它们退出,避免边删边被写。
|
||||
let disposedAny = false
|
||||
for (const [terminal, origin] of panel.terminalOrigin) {
|
||||
if (origin.issueNumber === issueNumber) {
|
||||
@@ -481,21 +479,7 @@ export async function handleColumnChange(panel: KanbanWebviewPanel, issueNumber:
|
||||
customScriptPath: settingsForHook.worktreePreRemoveScript,
|
||||
})
|
||||
try {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
execFile(
|
||||
'git',
|
||||
['-C', workspaceRoot, 'worktree', 'remove', '--force', abs],
|
||||
{ timeout: 30_000 },
|
||||
(err, _stdout, stderr) => {
|
||||
if (err) {
|
||||
const detail = (stderr ?? '').trim() || err.message
|
||||
reject(new Error(detail))
|
||||
return
|
||||
}
|
||||
resolve()
|
||||
},
|
||||
)
|
||||
})
|
||||
await removeWorktreeDir(workspaceRoot, abs)
|
||||
logger.add({
|
||||
level: 'info',
|
||||
source: 'panel',
|
||||
@@ -956,7 +940,7 @@ export async function handleDeleteIssue(panel: KanbanWebviewPanel, issueNumber:
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 删 worktree(如有)— git worktree remove --force,失败立即停
|
||||
// 5. 删 worktree(如有)— 递归强删目录(removeWorktreeDir),失败立即停
|
||||
if (worktreePath) {
|
||||
const absWorktree = resolveWorktreePath(worktreePath, workspaceRoot)
|
||||
if (fs.existsSync(absWorktree)) {
|
||||
@@ -972,21 +956,7 @@ export async function handleDeleteIssue(panel: KanbanWebviewPanel, issueNumber:
|
||||
customScriptPath: settingsForHook.worktreePreRemoveScript,
|
||||
})
|
||||
try {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
execFile(
|
||||
'git',
|
||||
['-C', workspaceRoot, 'worktree', 'remove', '--force', absWorktree],
|
||||
{ timeout: 30_000 },
|
||||
(err, _stdout, stderr) => {
|
||||
if (err) {
|
||||
const detail = (stderr ?? '').trim() || err.message
|
||||
reject(new Error(detail))
|
||||
return
|
||||
}
|
||||
resolve()
|
||||
},
|
||||
)
|
||||
})
|
||||
await removeWorktreeDir(workspaceRoot, absWorktree)
|
||||
}
|
||||
catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err)
|
||||
|
||||
Reference in new issue
Block a user