feat: configurable merge method with server-side fast-forward#2101
feat: configurable merge method with server-side fast-forward#2101NNTin wants to merge 2 commits into
Conversation
Add a per-project `mergeMethod` config option (default "squash", backward compatible) consumed by the dashboard merge action via `scm.mergePR`. Supported strategies: - "squash" / "merge" / "rebase" — native GitHub merge-button methods - "merge-with-ff" — AO composite strategy: when the PR branch is strictly ahead of base (no divergence) it fast-forwards the base ref server-side via the Git Refs API (PATCH .../git/refs/heads/<base> with force=false) and deletes the head branch; when the branches have diverged it falls back to a merge commit. GitHub exposes no fast-forward merge button, so this cannot go through `gh pr merge` (which only offers merge/squash/rebase). The GitLab SCM throws an explicit error for "merge-with-ff" rather than silently ignoring it, since it has no equivalent per-merge flag. Closes AgentWrapper#2095 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
…with-ff Address PR review on merge-with-ff: - Type getCompareStatus's return as a CompareStatus union instead of string. - Fast-forward on "identical" as well as "ahead" so a zero-diff branch no-ops via the Refs API instead of attempting a pointless merge commit. - Wrap the base-ref PATCH so a rejected fast-forward (protected branch or a base that advanced since the comparison) surfaces a clear, actionable error instead of a raw API failure, and document the protected-branch limitation on fastForwardBase. Add tests for the identical-branch FF path and the rejected-update error. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Addressing code review feedbackA code review of this PR's What I implemented1.
2. Protected base branches break the fast-forward path with an opaque error.
What I deliberately did not change, and whyRetry logic for the compare→PATCH race. The review suggested retrying if the base moves between the Best-effort head-branch deletion. The review noted the post-FF Verification
Thanks for the review. |
Summary
Adds a per-project
mergeMethodconfig option so users can choose how the dashboard merge action merges PRs. Default remains"squash"(backward compatible). Consumed by the dashboard merge route viascm.mergePR.Strategies
squash(default)mergerebasemerge-with-ffmerge-with-ffGitHub has no fast-forward merge button —
gh pr mergeonly offers merge/squash/rebase, and--mergealways creates a merge commit even when the branch could fast-forward. Somerge-with-ffcan't go throughgh pr merge; it uses the Git Refs API directly:GET /repos/{o}/{r}/compare/{base}...{head}).PATCH /repos/{o}/{r}/git/refs/heads/{base}withforce=false(GitHub rejects anything that isn't a true fast-forward), then delete the head branch.--mergecommit.This preserves linear history (no merge commit, no squash, no rebased SHAs) whenever possible.
Config Usage
Options:
"squash"(default),"merge","rebase","merge-with-ff"Files Changed
packages/core/src/types.ts— Add"merge-with-ff"toMergeMethod(with JSDoc), addmergeMethod?toProjectConfigpackages/core/src/config.ts— AddmergeMethodtoProjectConfigSchema(default"squash")packages/plugins/scm-github/src/index.ts—mergePR()implementsmerge-with-ffvia compare + Git Refs fast-forward, else merge commitpackages/plugins/scm-gitlab/src/index.ts—mergePR()throws for the unsupported"merge-with-ff"(no GitLab equivalent) instead of silently ignoring itpackages/web/src/app/api/prs/[id]/merge/route.ts— Readsproject.mergeMethodinstead of hardcoding"squash"Tests
scm-github:merge-with-fffast-forwards via Git Refs API when ahead (and never touchesgh pr merge); falls back to--mergewhen divergedscm-gitlab:merge-with-ffthrows and never shells out toglabsquash; reads and passes throughproject.mergeMethodCaveats
Closes #2095
🤖 Generated with Claude Code