🐛 fix(vscode): 完成列/删 worktree 时自动杀掉占用进程再删目录

This commit is contained in:
2026-08-05 13:31:00 +08:00
parent 23e6f67373
commit 29aaabdabf
4 changed files with 133 additions and 41 deletions
+15 -28
View File
@@ -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 { findProcessesUsingWorktree, removeWorktreeDir, resolveWorktreePath } from '../../git/worktree'
import { killProcessesUsingWorktree, removeWorktreeDir, resolveWorktreePath } from '../../git/worktree'
import { commands, env, ThemeColor, Uri, window, workspace } from 'vscode'
import { getToken } from '../../auth/secrets'
import { buildCcCommand } from '../../cc/ccCommand'
@@ -474,28 +474,18 @@ 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
// dispose 终端后仍可能有 dev server 等残留;杀掉再删,占用不再回滚拖拽
const killed = killProcessesUsingWorktree(abs)
if (killed.length > 0) {
const list = killed
.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})`,
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)
@@ -933,21 +923,18 @@ 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
// 先杀占用再删,与拖到完成 / 删 worktree 同一路径。
const killed = killProcessesUsingWorktree(absWorktree)
if (killed.length > 0) {
const list = killed
.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,
logger.add({
level: 'warn',
source: 'panel',
message: `删除工单前已杀掉占用 worktree 的进程 (issue #${issueNumber})`,
details: list,
})
return
}
try {
await removeWorktreeDir(workspaceRoot, absWorktree)
+11 -8
View File
@@ -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, findProcessesUsingWorktree, removeWorktreeDir, resolveWorktreePath } from '../../git/worktree'
import { expandTilde, killProcessesUsingWorktree, removeWorktreeDir, resolveWorktreePath } from '../../git/worktree'
import {
runImplTabPostCloseHook,
runImplTabPreCreateHook,
@@ -97,15 +97,18 @@ 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
// 先杀占用进程(dev server 等),再删目录,避免 ENOTEMPTY 竞态
const killed = killProcessesUsingWorktree(abs)
if (killed.length > 0) {
const list = killed
.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
logger.add({
level: 'warn',
source: 'panel',
message: `删除 worktree 前已杀掉占用进程 (issue #${issueNumber})`,
details: list,
})
}
try {