Gitリポジトリから意図しない改行コードを出来る限り排除する

歴史上の都合により、Windowsは改行コードにCRLF、Mac及びLinuxはLFを使用しています。

Linuxやmacプラットフォーム上で動くアプリをWindowsで開発している時、例えば.sh等を書いている時は、ファイル内にCRLFが混入すると、改行コードを誤認識してしまってエラーになってしまいます。

開発環境をMacかLinuxで統一できれば特に悩む必要もないのですが、様々な理由から統一できないこともあるでしょう。

この記事では、事故を予防する為に出来る、いくつかの対策を紹介します。

その1:gitを設定する

gitがWindowsにインストールされた際、デフォルトの挙動として、チェックアウト/ステージ時にLFとCRLFを相互に変換します。この挙動により、gitには常にLFが、ワーキングツリーには常にCRLFが存在する状態になります。

これはauto-crlfという設定により有効化されるのですが、この挙動では、前述の通り、改行コードに繊細なリポジトリでは問題を引き起こす事があります。そういったケースの場合、この設定を変更することで、改行コードに関する挙動を修正することが出来ます。

auto-crlfの変更

auto-crlfの動作モードは3つあります。

名前 挙動
true CRLF<-> LFの相互変換(デフォルト)
input CRLF -> LFの一方通行変換
false 変換を一切行わない

例えばfalseに設定するには、gitリポジトリ内で以下の様にコマンドを実行します。

git config --local core.autocrlf false

このように、auto-crlfの設定変更は簡単ですが、このコマンドはローカルマシンの挙動を変える事しか出来ないので、auto-crlfで運用するには、開発で使用している/これから使用する全てのWindowsマシンで設定を統一する必要があります。

開発規模によっては非常に大変です。また、auto-crlfは全てのテキストファイルに対する設定しかできません。設定変更の手間やカスタマイズ性を考慮すると、後述の.gitattributesを利用した方が良さそうです。

.gitattributes

.gitattributesファイルを作成することで、ファイルごとに改行コードをCRLFにするか、LFにするか選ぶことが出来ます。ここで設定した内容は前述のconfigの挙動を上書きします。

例えば、.shファイルの改行コードをlfにするには以下の様に記述します。

*.sh text eol=lf

以下の様にリポジトリ直下に置きます。

[root]
├.git
└.gitattributes <==

.gitattributesはgitリポジトリ内に置くことが出来る為、gitを通じて他の環境に共有出来ます。

ただし、.gitattributesにも問題があります。これはauto-crlfにも存在する問題なのですが、これらのgitの機能で設定した内容はワーキングツリーには適用されません。その為、「手元では動いてる/手元だけでは動かない」問題の原因となる可能性があります。

以下に簡単に図にしました。環境1と環境2のワーキングツリーで改行コードが異なってしまっています。

この問題を解消するには、次項で紹介している、エディタ側の設定を変更するのが有効です。

その2:エディタを設定する

ワーキングツリーに存在するファイルの改行コードを指定するには、エディタの設定を変更する必要があります。最近のエディタツールは設定で改行コードを設定できるのが当たり前ですが、使用するエディタ一つ一つの設定を見直すのは大変です。そこで、EditorConfigという、エディタ間を跨いだ共通の設定ファイルを使用します。

editorconfig.org

root = true

[*]
end_of_line = lf

以下の様にリポジトリ直下に置きます。

[root]
├.git
├.gitattributes
└.editorconfig <==

上記の設定をすることで、対応しているエディタであれば保存時やコードフォーマットを掛けた際に自動で改行コードを修正してくれます。

EditorConfigに対応しているエディタは公式サイトで確認することが出来ます。

例えば、VS Codeはデフォルトでは対応していませんが、拡張機能をインストールすることで対応が可能です。

marketplace.visualstudio.com

こちらの拡張機能を入れておくことで、ファイルを編集し保存したタイミングで自動的に改行コードを修正してくれるようになります。

その3:CIを設定する

これまでの対応をする行うことで、リポジトリに意図しない改行コードが混入することはまず防げるかと思いますが、.gitattributesに漏れがあったり、git configは各作業環境での設定が必要だったり、.editorConfigも必ず対応しているエディタを使用しなければならなかったり、editorConfigと.gitattributesの不一致などで偶然入り込む可能性が少ないながらあり得ます。

なのでCIを回し、意図しない改行コードを検出したら警告を出すようにしましょう。以下の例はGitHub Actionsのものです。

name: Check-EditorConfig

on: push

jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - run: npm install -g editorconfig-checker
      - run: editorconfig-checker

以下の様に配置します。

[root]
├.git
├.github
│└actions
│  └check-editorconfig.yml <==
├.gitattributes
└.editorconfig

これで、pushするたびに前の項で作成した.editorconfigを読んでチェックを行い、設定に沿っていないファイルがリポジトリ内にあった場合はNot all lines have the correct end of line characterというエラーを出してくれるようになります。

このツールはnpmでインストールできるため、他のCI環境でも比較的容易に利用可能だと思います。

最後に

主にEditorConfigに対する余談ですが、これを使って統一できるのは改行コードに限らず、いわゆるコーディング規約に対してもある程度適用可能です。コーディング規約がリポジトリで定められていないと、複数人/複数環境で開発した時に余計な差分がgitに載ってしまい、レビュー効率の低下やリポジトリの無駄な肥大化を招きます。何も設定されていないよりは、特定の環境をモデルとしてチームメンバーと合意を取り、一旦統一してしまうのが良いでしょう。