GitLab:スカッシュのせいでマージが断られた・失敗した
GitLab は、スカッシュの設定がそうなっていると、マージリクエストのコミットを1つにまとめて(スカッシュして)マージします。設定がスカッシュを必須にしているのにマージがスカッシュを頼まなかったとき、またはスカッシュそのものが失敗したときは、マージされません。このときマージの API は 422 の Branch cannot be merged だけを返し、理由はマージリクエストの merge_error に残します。マージリクエストの画面に出るのもこの文です(GitLab のソース lib/api/merge_requests.rb と app/services/merge_requests/merge_service.rb・2026年10月28日に読んだもの)。理由は次のどれかです:
This project requires squashing commits when merge requests are accepted. Squashing failed: The commits have conflicting changes. Squash the commits locally, resolve the conflicts, then push the branch. Squashing failed: Squash the commits locally, resolve any conflicts, then push the branch.
スカッシュの設定
- プロジェクトの設定:Settings > Merge requests > Squash commits when merging。決めるのはメンテナーかオーナーです。Do not allow(
never)はスカッシュせず、選ぶ欄も出ません。Allow(default_off)はできるが既定で外れ、Encourage(default_on)はできて既定で選ばれ、Require(always)はいつもスカッシュし、利用者は変えられません(GitLab の説明「プロジェクトのスカッシュの設定」)。REST API ではプロジェクトのsquash_optionです。 - 保護ブランチの設定:ブランチのルールごとに、同じ4つと、自分の設定を消す Default から選べます。そのブランチへのマージリクエストでは、プロジェクトの設定よりこちらが優先されます(
ee/app/models/ee/merge_request.rb)。GitLab 17.9 でフラグつきで入り、17.10 から既定で有効、17.11 でフラグがなくなりました。GitLab Premium と Ultimate ではすべてのブランチのルールで、GitLab Free では All branches のルール(=プロジェクトの設定)だけで使えます(「スカッシュの設定を変える」)。プロジェクトのsquash_optionにはこの設定は出ません。
マージされなかった理由
- 「This project requires squashing commits when merge requests are accepted.」:効いている設定が Require なのに、マージリクエスト(Squash commits when merge request is accepted の欄・
squash)もマージ(squash=true)もスカッシュを頼んでいません。GitLab はマージの前にこれを確かめます(app/models/merge_request.rbのmissing_required_squash?・app/services/merge_requests/merge_strategies/from_source_branch.rb)。マージの API がマージリクエストのスカッシュを立てるのは、squash=trueを送ったときだけです。スカッシュを必須にしているのが対象のブランチでも文は「this project」なので、プロジェクトの設定だけを読む道具には Allow に見え、スカッシュを外したままにします。 - 「Squashing failed: The commits have conflicting changes.」:GitLab はサーバーの上でコミットをまとめます。その途中で、元のブランチのコミットどうしがぶつかりました(
app/services/merge_requests/squash_service.rb)。もう1つの「Squashing failed」の文は、スカッシュの途中のそれ以外のエラーです。 - Do not allow でマージが失敗することはありません。マージが
squash=trueを送っても、GitLab はスカッシュせずにマージします(squash_on_merge?が false)。
効いている設定の見方
- REST API:マージリクエストを読みます。
squash_on_mergeはプロジェクトと対象のブランチの設定を入れた答えで、squashは欄の値だけです。squash_on_mergeが true でsquashが false なら、スカッシュが必須です。マージが失敗したあとはmerge_errorに理由があります。 - GraphQL:
squashOnMergeと、効いている設定が Require か Do not allow のとき true になるsquashReadOnly。ブランチのルールごとのスカッシュの設定はbranchRules { squashOption { option } }で、GitLab 17.9 から試験的な欄です。
curl -H "PRIVATE-TOKEN: your-token" "https://gitlab.com/api/v4/projects/group%2Fproject/merge_requests/42"
query {
project(fullPath: "group/project") {
mergeRequest(iid: "42") { squash squashOnMerge squashReadOnly mergeError }
branchRules { nodes { name squashOption { option } } }
}
}
どうするか
- スカッシュが必須:
squash=trueをつけてマージするか、マージリクエストのスカッシュの欄を選んでからもう一度マージします。決まりを変えるなら、メンテナーかオーナーが対象のブランチのルールか、プロジェクトのスカッシュの設定を変えます。 - まとめるとコミットがぶつかる:手元でコミットをまとめ(たとえば対象のブランチの上へ
git rebase -i)、ぶつかりを直して push してから、もう一度マージします。 - スカッシュのほかのエラー:GitLab の求めも同じで、手元でまとめ、ぶつかりを直して push します。
マージの API のほかの答え(405・409・401・400)はGitLab がマージを断った理由へ。
IntelliJ IDEA で GitLab のマージリクエストを扱うなら
Lesstep の Merge Request Inbox for GitLab は、JetBrains IDE(2024.1 以降)のプラグインで、IDE からマージリクエストをマージできます。マージの画面は、GitLab がそのマージリクエストをどうスカッシュするか(squashOnMerge・squashReadOnly)を読むので、保護された対象のブランチのスカッシュの設定も入ります。必須ならスカッシュの欄を選んで固定、認めていなければ外して固定します。マージが 422 で失敗したときは、GitLab が残した理由(merge_error。「This project requires squashing commits when merge requests are accepted.」など)を出します。1.0.19 より前は、プロジェクトの設定だけを見ていました。見るのは無料、承認・コメント・マージは Pro(月 US$1.50・30日間の無料試用つき)です。画面は日本語です。
GITLAB は GitLab Inc. の商標、IntelliJ IDEA は JetBrains s.r.o. の商標です。このページは GitLab Inc.・JetBrains のいずれとも提携しておらず、承認も受けていません。
ほかに:GitLab のマージの断り(405・409・422) · GitLab の自動マージの断り(405)・取り消し · GitLab のリベースの断り・失敗(403・409) · GitLab の 429「Retry later」(回数の上限) · GitLab の「compare_timeout」(差分の上限) · JetBrains の IDE で GitLab のマージリクエストを扱う · English