くりにっき

フルスタックキュアエンジニアです

Gitlab Merge Request Builder Plugin で Could not merge が出た時の対処法

tl;dr

Jenkins上でマージするのを諦めよう

github.com

使ってるバージョン

  • Jenkins v1.643
  • Gitlab Merge Request Builder Plugin v2.0.0
  • Git client plugin v1.19.1
  • Git plugin v2.4.1

エラー詳細

こんな感じのエラーです

19:58:57  > git rev-parse origin/develop^{commit} # timeout=10
19:58:57  > git config core.sparsecheckout # timeout=10
19:58:57  > git checkout -f origin/develop
19:58:57  > git merge -s recursive --no-ff 70659b22c6503833c8d3f71b7754dd3e16e2d71e # timeout=10
19:58:57  > git config core.sparsecheckout # timeout=10
19:58:57  > git checkout -f 70659b22c6503833c8d3f71b7754dd3e16e2d71e
19:58:57 ERROR: Branch not suitable for integration as it does not merge cleanly: Could not merge AnyObjectId[70659b22c6503833c8d3f71b7754dd3e16e2d71e]
19:58:57 Finished: FAILURE

大した差分でもないしGitLab上でもコンフリクト起こしていないしアクセプトボタンも押せる状態なのに、なぜかJenkins上でマージできずにエラーになるということがたまにありました

2年くらい使ってる自分の経験則では

  • fast forwardでマージできる場合にはエラーは起きないが、fast forwardでマージできない場合にエラーになる
  • MergeRequestのsource branch(送り元のトピックブランチ)とtarget branch(送り先のブランチ)の差分が大きいとエラーになりやすい

という感じでした。

Git flowを使っている場合に、リリースブランチからdevelopブランチへのマージ*1は問題ないのに、masterブランチへのマージ*2でエラーになるのでなかなか厳しいものがありました。(つらい)

f:id:sue445:20160202234130p:plain

エラーが発生してる場所

Jenkinsのコンソールログだけだと特定しづらかったですが、JGitでのマージに失敗してるようでした。 https://github.com/jenkinsci/git-plugin/blob/git-2.4.2/src/main/java/hudson/plugins/git/extensions/impl/PreBuildMerge.java#L76

そりゃJenkinsサーバのgitのバージョンを上げても直らないわけだ。。。

設定をいろいろいじった

f:id:sue445:20160202232135p:plain

思いっきし「This feature is not fully implemented in JGIT.(この機能はJGITでは完全にサポートされていない)」って書いてるなw

f:id:sue445:20160202232138p:plain

Fast-forward modeを --no-ff にした状態でMerge strategyは全種類試しましたが解決しませんでした。。。

対処法

Additional Behavioursを消した

Before

Gitlab Merge Request Builder Pluginのドキュメントに書いてる設定 f:id:sue445:20160202232925p:plain

After

修正後

f:id:sue445:20160202232953p:plain

Merge before buildを削除。要はsource branchをtarget branchにマージした状態でテストするのではなく、source branch自体をテストするというわけです

「マージした状態でビルドしなくて大丈夫か?」とも思うかもしれませんが、

  • 差分がでかい時にマージエラーが起きるくらいならマージしないでビルドしたい
  • ビルドに時間がかかるとrebaseしてビルドし直すコストが高い *3
  • マージした先のdevelopブランチやmasterブランチもJenkinsでビルドをしている *4

と判断で外しました。

ちなみに同プラグインGitHub版の GitHub pull request builder plugin だと ${sha1} (マージしない状態のPullRequestのコミットID)でテストをしていました

しばらく運用してみた

上記設定で1週間くらい運用してみました

ビルドスクリプトを修正してmasterにコミットした時にトピックブランチ側が古い状態でビルドしてエラーになることがありましたが、それ以外はそれなりに快適にやってます。まぁその辺はトレードオフなんじゃないかと。

*1:差分はCHANGELOGくらい

*2:developに比べたら差分はたくさんある

*3:今メインで開発してるアプリだと1ビルド10分前後

*4:MergeRequestをビルドしているような人がmasterブランチをビルドしないわけないw