YAMADA TAISHI’s diary

ゲームについてとか私の日記とか。このブログのあらゆるコードは好きにどうぞ。利用規約があるものは記事内のGitHubのRepositoryのリンクで貼られていると思うので、そちらを参照ください。

git大文字・小文字ファイルリネームの問題

こんにちは、やまだたいし( 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に設定することで意識しなくてもリネーム扱いになります。
プロジェクトでもこれを推奨するところが多いと思います。

あと、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できるはず。

まとめ


皆プロジェクトのルールには従おうな?
以上、やまだたいしでした。