💭

GitHub Actionsで、git mergeができなくてハマった話し

2023/12/24に公開

はじめに

GitHub Actionsで、リリース用のworkflowを作っていてハマってしまったので、その解消方法を備忘録として残す。

経緯

今回作成していたのは、以下の様なworkflowである。

(略)

jobs:
  merge-release-changes
    runs-on: ubuntu-latest
  steps:
      - name: Checkout (GitHub)
        uses: actions/checkout@v3
      - リリースする最新バージョン番号を決めるstep
      - developブランチからリリースブランチを切るstep
      - CHANGELOGなどのバージョンに関連するファイル一式を更新するstep
      - name: Commit changes and merge(リリースブランチで行った変更をdevelop, mainへマージ)
        run: |
          git add.
          git commit -m "release: {最新バージョン}"
          git checkout develop
          git merge {リリースブランチ}
          git checkout main
          git merge {リリースブランチ}
	  (略)

ブランチの運用としては、俗に言うGitflowに近い物になっており、atlassianのGitflowについての紹介記事をお借りすると以下の様なグラフになる。
また、本記事の本筋とは関係ないが、この記事はGitflowの内容が個人的にはかなり分かりやすく紹介されているので、もしGitflowについて知りたい方は一読しておくと良いかも。

しかし、上記のworkflowを走らせてみると、以下の様なエラーに遭遇した。

Switched to branch 'develop'
Your branch is up to date with 'origin/develop'.
Updating f3d992a..f7becf1
Fast-forward
 sample.md | 1 +
 1 file changed, 1 insertion(+)
Switched to a new branch 'main'
branch 'main' set up to track 'origin/main'.
fatal: refusing to merge unrelated histories

developブランチへreleaseブランチをマージするのは成功しているが、その後のmainへのマージに失敗している様子。

対処法

結論から言うと、上記のエラーは、GitHub Actionsの環境(今回はhosted-runnerを使用)で必要なGitの履歴を取得していない事が原因。
そして、その対処方法は以下の様にactions/checkoutfetch-depth: 0を追加するだけ。

      - name: Checkout (GitHub)
        uses: actions/checkout@v3
        with:
          fetch-depth: 0 # これが必要

actions/checkoutのリポジトリのREADMEを読むと、デフォルトではworkflowをtriggerした時のref/SHAのみを取得する動作になっているらしい[1]

そのため、全ブランチ/タグの全履歴を取得してくるためには、fetch-depth: 0を指定する必要がある。規模が大きいリポジトリだと、全履歴を取ってくるのにもそれなりに時間がかかると思うので、今回の様に履歴が必要な操作を行わない場合は、デフォルトでも良いのかもしれない。

解決にこぎつけるまで

※ここからは自分がこの問題に遭遇した時の考察を残しているだけなので、スキップして頂いても大丈夫です

まず今回マージ時に出力された以下のエラーは、一般的に共通の根本を持たないブランチ同士をマージする際に出力される。

fatal: refusing to merge unrelated histories

マージするブランチとされる側のブランチの履歴のどこかに共通のコミットが存在すれば、Gitがそこを起点にマージを試みる事ができるが(※マージしようとした結果、コンフリクトが発生する事もある)、そもそもその共通のコミットが見つからないと一体どこを基準にしてマージすれば良いのか分からないのでこのエラーが出力される、と自分は理解している。
考えられるケースとしては、最初は別々のリポジトリA、Bで開発していた物を、何らかの理由で1個のリポジトリにまとめたい時などはこのエラーが発生しそう。
また、Web上でこのエラーメッセージの解決方法について調べると、以下の様にオプションをつけるとマージできるよ!という記事が結構見つかる。

git merge --allow-unrelated-histories {マージするブランチ}

しかし、よくよく考えると今回のケースでは、そもそも共通のコミットがないという事はありえないはず。
なぜなら、上記のグラフを見てもらうとわかる様に、mainをベースとしてdevelopは作成されているし、更にdevelopをベースとしてリリースブランチは作成されているので、よっぽどおかしい事が起きていない限り、過去を辿っていくとそれぞれに共通のコミットが存在するはず。
他の手がかりとしては、上記のworkflowで行っているブランチ操作を、そのままローカルの開発環境で試してみると問題なくマージできる事もポイントだった(workflow実装時にやっていたが念のため再チェックした)。やはり、GitHub Actionsで詰まった際は、初手でローカルで同じ処理をなぞってみて、再現するかどうかをチェックするのが良さそう。

参考

https://github.com/actions/checkout

脚注
  1. https://github.com/actions/checkout ↩︎

Discussion