fix: handle already-merged PRs + retry worktree config.lock
Some checks are pending
CI / lint-and-test (push) Waiting to run
Some checks are pending
CI / lint-and-test (push) Waiting to run
Two fixes for the 18-PR merge blockage: 1. When cherry-pick returns "already merged" (all commits empty because content is already on main), close the PR directly instead of trying to push the stale branch SHA to main. The branch ref points at old commits that aren't descendants of current main, so the push would always fail as non-fast-forward. 2. Retry worktree add once with jittered delay when config.lock contention occurs from parallel domain merges. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
ff357c4bbc
commit
f38b1e3c01
1 changed files with 23 additions and 0 deletions
23
lib/merge.py
23
lib/merge.py
|
|
@ -318,6 +318,10 @@ async def _cherry_pick_onto_main(branch: str) -> tuple[bool, str]:
|
|||
# Delete stale local branch if it exists from a previous failed attempt
|
||||
await _git("branch", "-D", clean_branch)
|
||||
rc, out = await _git("worktree", "add", "-b", clean_branch, worktree_path, "origin/main")
|
||||
if rc != 0 and "could not lock config" in out:
|
||||
await asyncio.sleep(random.uniform(0.5, 2.0))
|
||||
await _git("branch", "-D", clean_branch)
|
||||
rc, out = await _git("worktree", "add", "-b", clean_branch, worktree_path, "origin/main")
|
||||
if rc != 0:
|
||||
return False, f"worktree add failed: {out}"
|
||||
|
||||
|
|
@ -1456,6 +1460,25 @@ async def _merge_domain_queue(conn, domain: str) -> tuple[int, int]:
|
|||
failed += 1
|
||||
continue
|
||||
|
||||
# Content already on main — close PR, skip push, clean up branch.
|
||||
# Cherry-pick returns "already merged" when all commits are empty.
|
||||
# The branch ref still points at old commits (not a descendant of main),
|
||||
# so pushing branch_sha:main would fail as non-fast-forward.
|
||||
if "already" in pick_msg.lower():
|
||||
conn.execute(
|
||||
"UPDATE prs SET status = 'merged', merged_at = datetime('now'), last_error = NULL WHERE number = ?",
|
||||
(pr_num,),
|
||||
)
|
||||
db.audit(conn, "merge", "merged", json.dumps({"pr": pr_num, "branch": branch, "note": "content already on main"}))
|
||||
leo_token = get_agent_token("leo")
|
||||
await forgejo_api("POST", repo_path(f"issues/{pr_num}/comments"),
|
||||
{"body": f"Content already on main — closing.\nBranch: `{branch}`"})
|
||||
await forgejo_api("PATCH", repo_path(f"pulls/{pr_num}"), {"state": "closed"}, token=leo_token)
|
||||
await _delete_remote_branch(branch)
|
||||
logger.info("PR #%d already merged (content on main), closed", pr_num)
|
||||
succeeded += 1
|
||||
continue
|
||||
|
||||
# Local ff-push: cherry-picked branch is a descendant of origin/main.
|
||||
# Regular push = fast-forward. Non-ff rejected by default (same safety).
|
||||
# --force-with-lease removed: Forgejo categorically blocks it on protected branches.
|
||||
|
|
|
|||
Loading…
Reference in a new issue