Git で改行コードだけ変えた時の挙動やら autocrlf の意味やらよくわからんかったのでまとめた

Golang が LF しか扱わない件を受けて、CRLF を多用してる GitHub ユーザーの私は対処を余儀なくされている。いい機会なので、Git の改行コード変更時の挙動やら autocrlf あたりの仕様とか、そのへんをまとめることにした。safecrlf はまた今後。

Git コマンド絡み(LF でコミット済みのファイルを CRLF に直してコミットする場合)

既に改行コード LF のテキストファイル file.md がコミットされているとして。この file.md の改行コードを CRLF にしてから git 操作を行うことを考える。

git status すると?

autocrlf によらず変更が検出される。

       modified:   file.md

git add すると?

autocrlf が false の時はステージされる。コミットも行える。修正数は file.md が 100 行だとしたら 1 file changed, 100 insertions(+), 100 deletions(-) になる。

autocrlf = true または input の時はステージはされず、変更そのものが無かったことになる。CRLF に変えた file.md の改行コードは変わらず CRLF のまま。

Git コマンド絡み(CRLF でコミット済みファイルを LF に直してコミットする場合)

既に改行コード CRLF のテキストファイル file.md がコミットされているとして。この file.md の改行コードを LF にしてから git 操作を行うことを考える。

git status すると?

autocrlf によらず変更が検出される。

       modified:   file.md

git add すると?

autocrlf が false の時はステージされる。コミットも行える。修正数は file.md が 100 行だとしたら 1 file changed, 100 insertions(+), 100 deletions(-) になる。

autocrlf = true の時はステージされるが警告 warning: LF will be replaced by CRLF in file.md が出る。コミットも行える。修正数は file.md が 100 行だとしたら 1 file changed, 100 insertions(+), 100 deletions(-) になる。

autocrlf = input の時はステージされる。コミットも行える。修正数は file.md が 100 行だとしたら 1 file changed, 100 insertions(+), 100 deletions(-) になる。

Git コマンド絡み(まとめ)

改行コードだけ変えた場合の挙動は以下のとおり。

  • git status
    • 常に変更が検出される
  • git add、autocrlf=false
    • ステージする
  • git add、autocrlf=true、LF → CRLF に変換していた場合
    • ステージしない
    • 変更も無かったことになる(ただし CRLF に直したローカルのファイルはそのまま)
  • git add、autocrlf=input、LF → CRLF に変換していた場合
    • ステージしない
    • 変更も無かったことになる(ただし CRLF に直したローカルのファイルはそのまま)
  • git add、autocrlf=true、CRLF → LF に変換していた場合
    • ステージする
    • 警告 warning: LF will be replaced by CRLF in file.md が出る
  • git add、autocrlf=input、CRLF → LF に変換していた場合
    • ステージする

よりわかりやすく要点をピックアップすると、

  • false の時は常に警告無しでステージする
  • true or input の時に、LF でコミットされていたファイルを CRLF に直してもステージしない
  • true or input の時に、CRLF でコミットされていたファイルを LF に直したらステージできる
  • true の時は、改行コード違いでステージングが走った時にWarning が出る

Warning については、単に「autocrlf = true の時は、チェックアウト時に LF のファイルは全部 CRLF に変換しますんで」とお知らせしているだけ。 コミット時も チェックアウト時もとにかく表示されるので面食らうが、単なるお知らせなので身構える必要はない。

autocrlf について

core.autocrlf とは gitconfig の一種であり、コミット or チェックアウトを行う時に CRLF 派が楽するためのもの。元々 Git は LF オンリーであったが、Windows では CRLF を使う文化があるため用意されている。

コマンド

global の例で。

見る:

$ git config --global core.autocrlf
false

input に変える:

$ git config --global core.autocrlf input

true, false, input がある。未指定時のデフォルトは false

意味は以下のとおり。

  • true
    • CRLF で使いたい人用
    • コミット時は CRLF を LF に変換してコミット
    • チェックアウト時は LF を CRLF に変換してコミット
  • false
    • 何もしない
  • input
    • 手元では CRLF を使いたいけど LF 派を尊重する
    • コミット時は CRLF を LF に変換してコミット

つまり true/false で「いいから CRLF で使わせろや」するか「何もしないか」を選ぶのが基本。ただこれだけだと改行コード混在時(ファイル A は LF だが、ファイル B は CRLF になっている等)に不便なので、input という対処がある。input は「もし CRLF なファイルがあったら、Git リポジトリに入れる(コミットする)タイミングで LF にしちゃうね」オプションである。false だと CRLF なファイルが CRLF のまま入っちゃうから(Windows 圏以外の LF 前提の人たちにとっては)面倒くさい。input だと CRLF は全部 LF になって入るから CRLF が混ざる心配はない。

.gitattributes について

※詳しく見てないので触りだけ。

.gitattributes とはリポジトリに対して「このファイルの改行コードはこれにしろよ」的なルールを指定できる設定ファイル。.gitignore が「こういうファイルは管理対象から無視しろよ」的なルールを指定するのと同じ。

たとえば *.sh text eol=lf と書いておけば、sh ファイルは autocrlf = true でも常に LF になる(チェックアウト時もコミット時も LF に変換される)。 .gitattributes を使うことでプラットフォームによらず改行コードを固定できる、と。

参考