fix(git): hard-sync target branch to origin instead of bare pull

_sync_target_branch ran a bare `git pull` after checkout; on a workspace
clone whose local target branch diverged from origin (inevitable once
remote history is rewritten) modern git fatals with "Need to specify how
to reconcile divergent branches". On the CEO approve-and-merge path the
GitHub merge had already landed, so the failure surfaced as a spurious
400 "Merge failed" and every retry re-hit the same wedged clone.

Sync is now fetch + `reset --hard origin/<branch>` — remote-authoritative,
matching the helper's intent and self-healing the divergence for all
call sites (CEO merge, PM 409-retry sync, post-merge best-effort sync).
This commit is contained in:
Renn F
2026-07-19 00:06:33 +02:00
parent ec74298faa
commit 945ce006fd
2 changed files with 20 additions and 12 deletions
+7 -8
View File
@@ -918,7 +918,7 @@ async def test_push_propagates_non_gh001_error_unchanged() -> None:
@pytest.mark.asyncio
async def test_sync_target_branch_uses_local_ref_when_present() -> None:
"""If the target branch already exists locally, just checkout + pull."""
"""If the target branch exists locally, checkout + hard-sync to origin."""
svc = _service()
calls: list[list[str]] = []
@@ -926,8 +926,6 @@ async def test_sync_target_branch_uses_local_ref_when_present() -> None:
calls.append(args)
if args[:2] == ["checkout", "feature/backend/parent"]:
return MagicMock(returncode=0, stdout="", stderr="")
if args[:1] == ["pull"]:
return MagicMock(returncode=0, stdout="", stderr="")
if args[:2] == ["log", "-1"]:
return MagicMock(returncode=0, stdout="local-tip-sha", stderr="")
return MagicMock(returncode=0, stdout="", stderr="")
@@ -938,8 +936,10 @@ async def test_sync_target_branch_uses_local_ref_when_present() -> None:
)
assert sha == "local-tip-sha"
assert ["checkout", "feature/backend/parent"] in calls
assert ["pull"] in calls
assert ["fetch", "origin", "feature/backend/parent"] not in calls
assert ["fetch", "origin", "feature/backend/parent"] in calls
assert ["reset", "--hard", "origin/feature/backend/parent"] in calls
assert ["pull"] not in calls
assert ["checkout", "-b", "feature/backend/parent"] not in [c[:3] for c in calls]
@pytest.mark.asyncio
@@ -956,8 +956,6 @@ async def test_sync_target_branch_fetches_and_tracks_when_local_ref_missing() ->
return MagicMock(returncode=0, stdout="", stderr="")
if args[:3] == ["checkout", "-b", "feature/backend/parent"]:
return MagicMock(returncode=0, stdout="", stderr="")
if args[:1] == ["pull"]:
return MagicMock(returncode=0, stdout="", stderr="")
if args[:2] == ["log", "-1"]:
return MagicMock(returncode=0, stdout="origin-tip-sha", stderr="")
return MagicMock(returncode=0, stdout="", stderr="")
@@ -975,7 +973,8 @@ async def test_sync_target_branch_fetches_and_tracks_when_local_ref_missing() ->
"feature/backend/parent",
"origin/feature/backend/parent",
] in calls
assert ["pull"] in calls
assert ["reset", "--hard", "origin/feature/backend/parent"] in calls
assert ["pull"] not in calls
@pytest.mark.asyncio