diff --git a/scripts/check-worktree.py b/scripts/check-worktree.py index c682e712..a9503cc4 100644 --- a/scripts/check-worktree.py +++ b/scripts/check-worktree.py @@ -107,16 +107,19 @@ def local_work_outside(child, expected): """2026-10-05 修复:pinned-history 检查此前用 --all --reflog,把 refs/remotes 也 计入——pin 在 feature 顶端的子仓因 origin/main 不在 pin 历史内而永远无法 finish (实测被迫删远端引用+清 reflog 绕过,损害现场)。只认「本地独有」工作: - 本地分支、stash、以及 HEAD 的 reflog(最近检出轨迹里的独有提交); - refs/remotes 一律不算——远端有副本即已保全。""" - if git(child, "rev-list", "--branches", "--not", expected).strip(): - return True - if git(child, "stash", "list").strip(): - return True + 不在任何远端跟踪引用历史内的提交才算。克隆默认分支停在 origin/main 顶端、 + reflog 里的检出轨迹等「远端有副本」的状态一律不算;stash 恒为本地独有。""" + candidates = git(child, "rev-list", "--branches", "--not", expected).split() for line in git(child, "reflog", "show", "HEAD", "--format=%H").splitlines(): tip = line.strip() - if tip and git(child, "rev-list", "-1", tip, "--not", expected).strip(): + if tip: + candidates.append(tip) + for tip in dict.fromkeys(candidates): # 去重保序 + # 远端任一引用可达 ⇒ 已保全,不算本地独有 + if git(child, "rev-list", "-1", tip, "--not", "--remotes").strip(): return True + if git(child, "stash", "list").strip(): + return True return False diff --git a/tests/test_task.py b/tests/test_task.py index b972a0e3..e6947d14 100644 --- a/tests/test_task.py +++ b/tests/test_task.py @@ -758,6 +758,23 @@ class FinishGuardFixTests(unittest.TestCase): self.assertEqual(result.returncode, 0, result.stdout + result.stderr) self.assertFalse(wt.exists()) + + def test_local_default_branch_at_origin_main_does_not_block(self): + """克隆默认分支停在 origin/main 顶端(pin 为 feature 顶端时不在其历史内) + 且 HEAD reflog 含克隆/检出轨迹——均为远端有副本的状态,不得阻断 finish。""" + self.add_submodule_pinned_off_main() + wt = self.worktree() + self.git(wt, "submodule", "update", "--init", "--recursive") + (self.repo / "tracked").write_text("implementation done\n") + self.git(self.repo, "add", "-A") + self.git(self.repo, "commit", "-q", "-m", "done") + self.git(self.repo, "push", "-q", "origin", "feature/guard") + self.git(self.repo, "merge", "--no-ff", "-q", "-m", "Merge feature/guard", "feature/guard") + self.git(self.repo, "push", "-q", "origin", "main") + result = self.task(wt, "finish", check=False) + self.assertEqual(result.returncode, 0, result.stdout + result.stderr) + self.assertFalse(wt.exists()) + def test_local_unique_commit_still_preserved(self): self.add_submodule_pinned_off_main() wt = self.worktree()