not equal Github.
自分の理解のために書いたので、困っている人は最後の「参考」ブロックに貼ってあるリンク順に読んだほうがわかりやすいと思います (小声)。
改行コード
世界には 3 種類の代表的な改行コードが存在する。
だいたい、というかこれだけ覚えておけば早々困らないけど、他には NEL など別の改行コードも存在する。
なんなら自作アプリケーションなら \kaigyo
とかしたら改行コードとして見なす、みたいにしても良いわけだ。 これも広義の意味では改行コードたりえる。
Unicodeでは、CR (U+000D) とLF (U+000A) に加えて、「次の行」 (next line) を示すNEL (U+0085)、行区切り文字 (line separator) を示すLS (U+2028)、段落区切り文字 (paragraph separator) を示すPS (U+2029) が提供される。
個人的には調べて初めて「えー HTTP って CR+LF なの!?」というのを知ったし、単純に名称として CR・LF を覚えていたのを、以下のように「あーなるほど、頭出しなのか要は」と納得したのだった。 意外と面白い。
すなわち、プリンタヘッドを新しい行の先頭に移動するという「改行」の動作を、現在行の先頭に移動するCR(キャリッジリターン→横移動)の動作と、新しい行に移動するLF(ラインフィード→縦移動)という2つの動作に分割し、それぞれ独立して制御するよう設計されていた。
上記 wikipdia 記事の歴史項より
Git が扱う改行コード
話が大幅にそれたけどここからが本題。
Git が扱う改行コードは、基本的に git
コマンドを実行する環境に依存している (core.eol: native
つまりデフォルト動作)。 すなわち Windows なら CR+LF だし Unix/Linux なら LF というように。
なにが問題になるか
実行する環境に依存する、ということは Windows と macOS 環境で開発している人とか、 Windows で開発して本番は Linux、などという異なる OS で動作させる時に「改行の動作が揃わない (認識されない! もしくは CR, LF で分解されて改行が意図した形にならない! 行末に ^M
のように BOM が付与される!)」 となる。
どう解決するか
core.autocrlf
という設定で git が扱う (リモートに push したり、ローカルに pull してきたり) タイミングで、管理対象の改行コードをよしなにしてくれるオプションがある。 以下のように使う。
git config --global core.autocrlf (true|input|false)
autocrlf
前述の通り、改行コードを自動変換してくれるオプション。 人によって様々な意見があるけど、これを有効にして解決する……というわけではない。
以下の参考元がわかりやすいが、雑に記載すると Windows 環境だと以下のような変換が走る。
autocrlf: true
- リモートに push
- CR+LF → LF
- ローカルに pull
- LF -> CR+LF
注意するべき点として、 CR+LF で git に登録されたファイルを pull してきたとき LF へ変換されない。以下のような動きですね。
- ローカルに pull
- CR+LF -> CR+LF
autocrlf: input
- リモートに push
- なにもしない
- ローカルに pull
- LF -> CR+LF
autocrlf: false
なにもしない
基本的に LF 方向へ変換される
というのが git の改行コード変換の基本動作。 また、上記の通り「CR+LF で git に登録されたファイルを pull してきたとき LF へ変換されない」という動作があり、このようなパターンは基本救えない。 (これは明示的に CR+LF で git に登録されてくる、という例外前提っぽい)
ということがわかると自然と解決策が 作業環境も LF に揃える
のがよさそうだ、となる。
設定
強制的に揃えるなら以下のようになる。
Windows
CLI から 設定する場合は以下。
git config --global core.autocrlf false git config --global core.eol lf
直接 .gitconfig
などを編集する場合は以下。
[core] ... # ここから autocrlf = false eol = lf
Unix/Linux
何もしなくて大丈夫。 あえて設定で表現すると以下のような状態。
git config --global core.autocrlf false git config --global core.eol native
push/pull するとき改行コードを触らず、かつ改行コードは一貫して OS に依存した LF のみ扱う (CR+LF が紛れ込んでいても残置する) となる。
問題
たとえばこれプロジェクト的に「Windows 向けアプリ作っててビルドもなんもかんも CR+LF の世界なんだけど!」という場合はどうすればいいのか、となる。
これは git の説明ページの core.eol
に以下のように書いてある。
Setting this variable to "true" is the same as setting the text attribute to "auto" on all files and core.eol to "crlf".
この変数を「true」に設定することは、すべてのファイルのテキスト属性を「auto」に設定し、core.eol を「crlf」に設定することと同じです。
つまり以下のようにすればよさそう (もし CR+LF なプロジェクトも同時に管理しているなら、対象のワーキングディレクトリに移動して git config --local
で実行すればよさそう)。
git config --global core.autocrlf true git config --global core.eol crlf
.gitconfig
に書くなら以下。
[core] ... # ここから autocrlf = true # Windows なら native でも eol = crlf
なぜ突然こんな話を
インフラメンテナンス担当している Rails 案件で「動かない〜」という相談が相次いでいて、流石におかしいと思ったので「development で動かしてみるか!」と様子見でコンテナ立ち上げようとしたら rescue in _decrypt
が出て、確認したら developmeny.yml.enc に謎の改行が紛れ込んでいて「そりゃ動かねえよ!」となったので調べていた。
どのエディタで開いても改行コードは LF で検出される。 のでさすがに、「自分の環境が悪いのか?」となり
core.autocrlf = false
- main ブランチを ZIP でダウンロード
いずれも全く同じく改行が見える。 しかし Github UI 上だと、逆に単一行として改行が見えない……ので、なんだこれは、CR+LF がバラされているのか? git が悪さしているのか? となって調べていた。
オチとしては、コード側メンテナーの人がなんかのアドオンだかエクステンションで、「CTRL+S
すると必ず改行を挿入する」という動作を入れており、バックポートを持ってきた時に development.yml.enc が conflict して、手動で解消したら意図せず改行が挿入されてしまった、ということだった。
たしかに diff とかで前後を比較すると以下のように No newline at end of file
が検出されないので、単純に改行が悪い、という当初の見立て通りだった。
--- a/config/credentials/development.yml.enc +++ b/config/credentials/development.yml.enc @@ -1 +1 @@ - ... \ No newline at end of file + ... lines 1-14/14 (END) ... --- a/config/credentials/development.yml.enc +++ b/config/credentials/development.yml.enc @@ -1 +1 @@ - ... \ No newline at end of file + ... \ No newline at end of file
おまけ:デフォルト値
core.eol
は以下のように native
、つまり実行環境に依存すると明言されている。
The default value is native.
しかし、 core.autocrlf
はデフォルト値がない。
StackOverflow で以下のように答えている外人兄貴がいた。
Checking the git source code, core.autocrlf is set to false by default. (And has been since the property's original introduction on Feb 13, 2007, though it has since been converted from a static value to a constant.)
The Windows installer does require you to pick a value for this property which is explicitly set in the git system config.
git ソース コードを確認すると、core.autocrlf はデフォルトで false に設定されています。 (このプロパティは 2007 年 2 月 13 日に最初に導入されて以来、静的な値から定数に変換されました。)
Windows インストーラーでは、git システム構成で明示的に設定されるこのプロパティの値を選択する必要があります。
そんなことある?! と思ってリンク先見たらちょっと古かったので現代は以下。
確かに定数じゃん……!? で、これがセットされていない時は参照先がないので false となる。
なので git をインストールする時、関連するソフトウェアやインストーラーで core.autocrlf
の定義なり .gitconfig
を配置して占有的に参照先を設定する、などをなんらかしているはず。
は〜、なるほど。