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 Untrivial-ai#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. |
|
Closing as part of a backlog sweep: Agent Orchestrator was rewritten from the ground up (Go backend + Electron/React frontend), and this PR's changes target files from the pre-rewrite TypeScript codebase that no longer exist in the current tree, so it cannot be rebased onto main. If the underlying change still makes sense for the current app, please open a fresh PR against the new codebase. Thanks for the contribution! |
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