🐛 fix(vscode): 删 worktree 前扫 /proc 检测进程占用,命中则中止清理
dev server 常驻在 worktree 里持续写构建产物,递归删除与写入竞态导致 rmdir 撞 ENOTEMPTY。新增 findProcessesUsingWorktree 扫 /proc 找 cwd 或 fd 落在 worktree 下的进程,三处删除调用点(拖到完成列 / 手动删 / 删整工单) 命中即弹错误 toast 列出 pid+命令并中止(不删、不杀进程),用户停掉后重试。 非 Linux 无 /proc 返回空,降级为原直接删除。
This commit is contained in:
@@ -6,7 +6,7 @@ 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 { removeWorktreeDir, resolveWorktreePath } from '../../git/worktree'
|
||||
import { findProcessesUsingWorktree, removeWorktreeDir, resolveWorktreePath } from '../../git/worktree'
|
||||
import { commands, env, ThemeColor, Uri, window, workspace } from 'vscode'
|
||||
import { getToken } from '../../auth/secrets'
|
||||
import { buildCcCommand } from '../../cc/ccCommand'
|
||||
@@ -475,6 +475,29 @@ export async function handleColumnChange(panel: KanbanWebviewPanel, issueNumber:
|
||||
mainBranch: settingsForHook.devBranch || 'main',
|
||||
customScriptPath: settingsForHook.worktreePreRemoveScript,
|
||||
})
|
||||
// 删前守门:dev server 等仍在写 worktree 的进程会让递归删除撞 ENOTEMPTY。
|
||||
// 命中就别删、别杀进程,只提示并回滚拖拽,让用户停掉后自己重试。
|
||||
const procHits = findProcessesUsingWorktree(abs)
|
||||
if (procHits.length > 0) {
|
||||
const list = procHits
|
||||
.map(h => ` pid ${h.pid}: ${h.cmd.length > 80 ? `${h.cmd.slice(0, 80)}…` : h.cmd}`)
|
||||
.join('\n')
|
||||
logger.add({
|
||||
level: 'warn',
|
||||
source: 'panel',
|
||||
message: `worktree 仍被进程占用,已中止清理 (issue #${issueNumber})`,
|
||||
details: list,
|
||||
})
|
||||
panel.postMessage({
|
||||
type: 'toast/show',
|
||||
id: makeNonce(),
|
||||
level: 'error',
|
||||
message: `工单 #${issueNumber} 有进程仍在占用 worktree,已中止清理。请先停止后重试:\n${list}`,
|
||||
dismissOnTimer: 10000,
|
||||
})
|
||||
rollback(fromColumn)
|
||||
return
|
||||
}
|
||||
try {
|
||||
await removeWorktreeDir(workspaceRoot, abs)
|
||||
logger.add({
|
||||
@@ -896,6 +919,22 @@ export async function handleDeleteIssue(panel: KanbanWebviewPanel, issueNumber:
|
||||
mainBranch: settingsForHook.devBranch || 'main',
|
||||
customScriptPath: settingsForHook.worktreePreRemoveScript,
|
||||
})
|
||||
// 删整工单也先守门:占用进程会让删除撞 ENOTEMPTY,且底层进程还在跑更不该
|
||||
// 强删。中止并提示,用户停掉后重删(保持与拖拽清理一致:占用就别删)。
|
||||
const procHits = findProcessesUsingWorktree(absWorktree)
|
||||
if (procHits.length > 0) {
|
||||
const list = procHits
|
||||
.map(h => ` pid ${h.pid}: ${h.cmd.length > 80 ? `${h.cmd.slice(0, 80)}…` : h.cmd}`)
|
||||
.join('\n')
|
||||
panel.postMessage({
|
||||
type: 'toast/show',
|
||||
id: makeNonce(),
|
||||
level: 'error',
|
||||
message: `工单 #${issueNumber} 有进程仍在占用 worktree,已中止删除。请先停止后重试:\n${list}`,
|
||||
dismissOnTimer: 10000,
|
||||
})
|
||||
return
|
||||
}
|
||||
try {
|
||||
await removeWorktreeDir(workspaceRoot, absWorktree)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import { execFile } from 'node:child_process'
|
||||
import { commands, Uri, window, workspace } from 'vscode'
|
||||
import { getToken } from '../../auth/secrets'
|
||||
import { detectRepo } from '../../git/remote'
|
||||
import { expandTilde, removeWorktreeDir, resolveWorktreePath } from '../../git/worktree'
|
||||
import { expandTilde, findProcessesUsingWorktree, removeWorktreeDir, resolveWorktreePath } from '../../git/worktree'
|
||||
import {
|
||||
runImplTabPostCloseHook,
|
||||
runImplTabPreCreateHook,
|
||||
@@ -97,6 +97,17 @@ export async function handleDeleteWorktree(panel: KanbanWebviewPanel, issueNumbe
|
||||
customScriptPath: settingsForHook.worktreePreRemoveScript,
|
||||
})
|
||||
|
||||
// 删前守门:dev server 等仍在写 worktree 的进程会让递归删除撞 ENOTEMPTY。
|
||||
// 命中就别删、别杀进程,只提示,让用户停掉后重试。
|
||||
const procHits = findProcessesUsingWorktree(abs)
|
||||
if (procHits.length > 0) {
|
||||
const list = procHits
|
||||
.map(h => `pid ${h.pid}: ${h.cmd.length > 80 ? `${h.cmd.slice(0, 80)}…` : h.cmd}`)
|
||||
.join('\n')
|
||||
void window.showErrorMessage(`有进程仍在占用 worktree,已中止删除。请先停止后重试:\n${list}`)
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
await removeWorktreeDir(workspaceRoot, abs)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user