こんにちは、やまだたいし( https://twitter.com/OrotiYamatano )です。
最近gitで大文字小文字を意識せずにリネーム対応をしている方が身の回りにいたので
今回は怒りの記事です。
なぜ大文字小文字をリネームすると問題が発生するのかなどなど解説して行こうと思います。
目次
大文字・小文字をリネームすると他の人の環境で何が起きるのか
もし、大文字小文字が違う変更を上げた場合、 他の人の環境ではどの様なエラーが出るのか。
それは
error: Your local changes to the following files would be overwritten by checkout:
xxxxxxx
というエラーが出るようになります。
直訳すると
次のファイルに対するローカルの変更は、チェックアウト xxxxxxx によって上書きされます。
というエラーです。
なぜこのエラーが発生するのかというと、
「通常時は」ローカルの変更をコミットしていない状態でpullをした場合に変更したファイルがサーバーもとい、リモートのデータで上書きしようとした際に発生します。

ではなぜ大文字小文字を変えただけで他の人の環境ではエラーが出てしまうのでしょうか?
それはgitは基本、大文字小文字のファイルを区別するように管理するからです。
ローカルで
A.txtというファイルがあったとして
a.txtというファイルへ置き換えたとします。
その場合、gitはA.txtをa.txtに変更したのではなく、
a.txtを追加したと判断します。
この状態でコミットをするとA.txtとa.txtがリモートに上がります。

とはいえ、削除コミットをあげれば問題なさそうに見えますね?

問題はここからで、各ローカルの設定が違うと問題が起こります。
コマンドでいうと git config core.ignoreCase という設定です。
falseとtrueがそれぞれ設定ができます。
デフォルトではtrueになっており、
大文字小文字のファイルを別のものだと判断する。
しかし、falseの場合は基本同一ファイルと認識するようになる。
基本、trueの場合でもfalseの場合でもしっかり元ファイルを管理して削除してくれれば問題ないのですが、
trueの状態で大文字小文字をリネームすると元のファイルは消えず、リネーム後のファイルの追加として処理されます。
その場合にfalse設定になってる人がいるとリモート上にあるA.txtとa.txtで上書きがローカルで発生しまうためエラーとして処理されてしまうのです!!

解決策
いくつかの解決策があります。
1.git rmコマンドで明示的に消す
git rmコマンドで明示的に消してしまうことだ。
これであれば core.ignoreCase がfalseだろうとtureだろうと 問題なく削除できる

2. core.ignoreCaseをfalseに設定する
git config core.ignoreCase falseでcore.ignoreCaseをfalseに設定することで意識しなくてもリネーム扱いになります。
プロジェクトでもこれを推奨するところが多いと思います。
3. 2回プッシュする(非推奨)
いわゆる、これは大文字小文字だけで変換するから起こる問題です。
であれば大文字・小文字以外の名前変更が含まれれば問題なく動作します。
まず、例としてA.txtをa.txtに変えたいとします。
一度A.txtを→A.txtに変え、コミット/プッシュ します。
全員がアセット更新したのを確認したら
再度リネーム、A.txtをa.txtに変え コミット/プッシュ します。
一度アンダーバーのついた名前変更を挟むことで正しい変更を行わせる手段です。
ただし、一気に更新する人がいる場合、ローカルのgitは大文字、小文字の変換ととらえられてしまうので、
うまく機能しないです。
あと、error: Your local changes to the following files would be overwritten by checkout: xxxxxxx がエラー出てしまった人の対応方法
一時的に git config core.ignoreCase tureとすることでローカルに大文字・小文字が両方存在するのを許容します。
すべてを落としたあとに git config core.ignoreCase false で元に戻せば上げた人が重複ファイルを消していれば問題なくpullできるはず。
まとめ
皆プロジェクトのルールには従おうな?
以上、やまだたいしでした。