GitでSimulinkモデルの競合を解決してマージする

# はじめに

Gitはとても便利で強力なバージョン管理ツールです。
覚える用語(コマンド)や概念が多くて最初のハードル高さは否めませんが、いったんあの便利なシステムを使って複数人で同じドキュメント(ソースコード)の管理をすれば、もはやGitなしで開発してた頃が想像つかないほどには中毒性のあるシステムだと思っています。

話は変わりまして、Simulinkモデルはグラフィカルにモデリングできる1D-Simシミュレーションモデルとしての性質もありますが、産業用途では専ら“コントローラモデル”、つまりマイコンプログラムをグラフィカルに描くためのツールとして利用されています[^2]。 そうつまり **Simulinkモデル = プログラムソースコード** なのです。

こうなってくると、これは是が非でも **Simulinkモデルをバージョン管理したい。** そして、あの強力な差分比較とマージ機能を使いたいと思ってしまうのは人間の性というもの。

しかし、Gitはプログラムソースコードなどのテキストファイル(アスキーデータ)には、とても強力な差分比較とマージ機能が使えるのですが、Simulinkモデルファイル(.slx)のような、 “実態はテキストファイルなんだけど、 **構造に意味がある系** のアスキーデータ”[^1] に対してGitでマージをかけると、構造が崩れて **最悪モデルファイルが壊れてしまいます。**

この記事では、GitでSimulinkモデルのバージョン管理したいという人に向けて、「自動で競合の解決をしてマージする」手順について説明します。

# リポジトリの事前設定

まずは事前準備として、リポジトリ直下の ``` .gitattributes ``` に以下の設定を施します。

```text
*.mlx -crlf -diff -merge
*.mat -crlf -diff -merge
*.fig -crlf -diff -merge
*.mdl -crlf -diff -merge
*.slx -crlf -diff -merge
*.mlapp -crlf -diff -merge
*.p -crlf -diff -merge
*.mdlp -crlf -diff -merge
*.slxp -crlf -diff -merge
*.sldd -crlf -diff -merge
*.slxc -crlf -diff -merge
*.mlproj -crlf -diff -merge
*.mldatx -crlf -diff -merge
*.slreqx -crlf -diff -merge
*.sfx -crlf -diff -merge
*.sltx -crlf -diff -merge
```

これは、Gitに「Simulinkモデルファイルに対して diff (差分機能)とmerge(マージ機能)を使うんじゃねえ」と明示しています。
そうです、つまり **Gitの差分比較とマージ機能は使いません。[^3]**

# Simulinkモデルファイルをブランチ別に更新してみる

事前設定が終わったので、ここからは実際にSimulinkモデルファイルを競合させてマージしてみたいと思います。
まずは競合のシチュエーションを作るために、以下に示すようにそれぞれのブランチ(master, develop)でSimulinkモデル(ex_git_merge.slx)に変更を施しcommitします。

コミットグラフはこんな感じです。

![コミットグラフ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448922/c278d6fe-232e-4ba0-4d54-a68bcad058c8.png)


それぞれのコミット(リビジョン)のモデルはこんな感じです。

![ベース](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448922/a3480573-cdb4-dde7-d50a-a918b8cb77e9.png)
![masterブランチ変更](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448922/4ec31ae6-7a2c-5705-af6c-9c17354d3734.png)
![developブランチ変更](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448922/d33aac20-4985-6737-a8c0-09d0cbb90c22.png)

masterブランチではGainブロックの設定値を変更し、developブランチではブロックを組み替えてみました。
ブランチごとにそれぞれ違うトコロを変更したので、それぞれの変更をうまいこと自動で取り込んでマージしてくれることを期待していますが、果たしてできるのか・・・？


# マージの実行 -> 競合の発生

それでは実際にマージさせてみます。
masterブランチにdevelopブランチを取り込みます。

```
$ git merge develop
```

すると、Gitから競合の発生を知らせるエラーが返ってきます。

![mergeして競合エラー](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448922/e4563c0f-3f76-7c3e-fb6e-2fea93296942.png)

Gitのマージ機能は ``` .gitattrubutes ``` で無効化しているので、両ブランチに変更があったらGitは **有無も言わず** 「競合してるよ！」と知らせておしまいです。

# MATLABの3wayマージツールを起動

ではこの状態で、MATLABでこのリポジトリを見てみましょう。
Gitがシステムにインストールされていれば、MATLABの「現在のフォルダー」ペインにもGitのステータスが表示されます。 Simulinkモデルファイルが競合マークになっていることが確認できます。
右クリックをして「ソース管理 > 競合を表示」の順にクリックします。すると、3wayマージツールが起動します。

![競合を表示](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448922/76046cd5-479d-1f2b-c0fd-1ec5bf87da0f.png)

# 3wayマージツールで競合を解決する

ここでタネあかしをすると、Simulinkモデルの競合解決はGitのマージ機能ではなく、Simulinkに搭載されている **3wayマージツール** を用いて行います。(マージコミット命令自体はGitで操作する必要があります。)

![3wayマージツール](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448922/17f8562c-0e95-469d-32db-7068266f171b.png)

3wayマージツールもGitのマージ機能に負けず劣らず優秀なツールでして、モデル内で変更箇所がかぶっていない場合(真に競合がない場合)、つまり今回のようなシチュエーションの場合は、両方の変更を取り込んで **自動でマージされた結果を表示します。** もちろんどちらの変更を採用するか手動で選択することも可能です。
競合箇所がすべて解決されていることを確認して、「確定して閉じる」を押下します。

![確定して閉じる](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448922/6ef35b27-5c69-5d31-978e-2de37976f4fb.png)

# コミットする(リベンジ)

Gitに戻り、ステータスを確認します。

```
$ git status
```

![競合解決済み](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448922/903dac0c-3fc9-e099-f533-0c1d0bbbbfb5.png)

競合が解決していることが確認できたので、再びコミットを行います。

```
$ git commit
```

無事に競合が解決され、以下のようにマージコミットが作られました。

![merge完了](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448922/80d279ac-e319-29c7-f488-b674012036bc.png)

最後にSimulinkモデルを開いてみましょう。

![merge後のモデル](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448922/26ac71b8-64d7-a608-0abf-3fc109c64fcd.png)

ちゃんと **masterブランチの変更(Gain変更)と、developブランチの変更(ブロックの組み替え)がうまく統合されていますね。** めでたしめでたし。

# おわりに

今回はGitシステムの操作とSimulink上の操作を明確に区別するために、Git側の操作は別クライアント(Git Bash)で行いましたが、MATLABからもGitの操作は可能ですので[^4]、よりシームレスにマージ作業ができることと思います。
また、今回はSimulinkの3wayマージツールの紹介だけでしたが、この他にもモデルの単純なリビジョン同士の比較なんかもできますので、もうこれで **「GitでSimulinkモデルのマージしたり比較したりするとぶっ壊れるんじゃ・・・((；ﾟДﾟ))ガクガク」** と、漠然とした不安を抱える日々を送らなくてすみますね！(ワタシがずっとそう思ってた)


[^1]: Microsoft WordやExcelファイルなんかも、実態はテキスト(XML)だけど構造に意味がある系のファイルですね。
[^2]: 拙著「電子工作にモデルベース開発(Model Based Development: MBD)を適用してみた【コントローラモデル編】」を参照下さい(https://qiita.com/mana_544/items/3fe4d150441b12d89ebf)

[^3]: この設定も含めて、MATLAB(Simulink)でGitを使う際の細かい設定は公式HPに書いてありますのでご参照下さい。[Git ソース管理の設定 - MATLAB &amp; Simulink - MathWorks 日本](https://jp.mathworks.com/help/simulink/ug/set-up-git-source-control.html)
[^4]: MATLABでGitの操作についてはコチラの方が詳しく解説されていますのでご参照下さい。「MATLABでGitを操作しよう (第1回 : プロジェクト作成とGUIの説明)」(https://qiita.com/stozaki/items/e4fa14c36f6c134e53e7)