diff --git a/app/lib/git.js b/app/lib/git.js index 28b9bfd..eb6c880 100644 --- a/app/lib/git.js +++ b/app/lib/git.js @@ -97,25 +97,28 @@ export class Git { * @returns {{ hasConflict: boolean, files: string[] }} */ detectConflict(target, source) { - // 建立暫時的本地 target 分支,嘗試以 --no-commit 合併 source - const tmp = `__conflict_check_${target}`; + // 建立暫時的本地 target 分支,嘗試以 --no-commit 合併 source。 + // 名稱帶 PID,避免並行或前次殘留造成命名衝突。 + const tmp = `__conflict_check_${target}_${process.pid}`; this._git(['checkout', '-B', tmp, `refs/remotes/pr/${target}`]); - const merge = this._git(['merge', '--no-commit', '--no-ff', `refs/remotes/pr/${source}`]); - let hasConflict = merge.status !== 0; - let files = []; + try { + const merge = this._git(['merge', '--no-commit', '--no-ff', `refs/remotes/pr/${source}`]); + const hasConflict = merge.status !== 0; + let files = []; - if (hasConflict) { - const unmerged = this._git(['diff', '--name-only', '--diff-filter=U']); - files = unmerged.stdout.split('\n').map((s) => s.trim()).filter(Boolean); + if (hasConflict) { + const unmerged = this._git(['diff', '--name-only', '--diff-filter=U']); + files = unmerged.stdout.split('\n').map((s) => s.trim()).filter(Boolean); + } + + return { hasConflict, files }; + } finally { + // 無論成敗都還原工作區並清除暫存分支 + this._git(['merge', '--abort']); + this._git(['checkout', '--detach']); + this._git(['branch', '-D', tmp]); } - - // 還原工作區 - this._git(['merge', '--abort']); - this._git(['checkout', '--detach']); - this._git(['branch', '-D', tmp]); - - return { hasConflict, files }; } /**