Only count remote-unreachable commits as local work in finish guard #219

Merged
weichen merged 2 commits from feature/finish-guard-followup into main 2026-10-05 15:29:34 +00:00
2 changed files with 27 additions and 7 deletions
+10 -7
View File
@@ -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
+17
View File
@@ -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()