😢

gitブランチ名の大文字・小文字違いでハマった件

2024/06/04に公開

git push まわりでハマった事象のトラブルシューティングメモです。結論大した原因ではなかったのですが、状況を言語化するのが少々厄介で、特に初学者だと解決へのアプローチが難しい気がしたので書き留めておきます。

事象概要

あ…ありのまま今起こった事を話すぜ!

「git pushでリモート反映済みのコミットが、ローカルではpushされていないことになっていた…」

何を言っているのかわからねーと思うが

  • 手元の作業ブランチコミットをGitHubのリモートブランチへpush
  • GitHubリポジトリ側で対象コミットは反映されている状態
  • なぜかローカルのgit上では未push扱いになっている

普段はSourceTreeでブランチの管理をしているので、たまに起きるSourceTreeのバグだろうと思ったのですが、VSCodeのSource Controller上でも同じ扱いとなっていたため、ローカルのgitに何か問題が起きているものと推察しました。

困った時の再起動?

まずは、SourceTreeやgitのロックファイルで何か掴んだまま残っていたりする可能性を考慮して、各ツールとマシンを再起動。

が、残念ながら状況変わらず。

ブランチ名を確認

コピペで確認しても同名のブランチのはずですが、そこはかとない既視感を覚えました。
そういえば1年ほど前、ファイルパスの大文字・小文字問題にハマったような…
https://zenn.dev/unsoluble_sugar/articles/978015611f482f

GitHub上のブランチを改めて確認すると、なんとびっくり、同名のブランチが2つ存在していました。

そして片方のブランチ名 feature の先頭が大文字の Featureになっていることに気付きます。

な、なにィーーーーーッ…!?

顛末

issue作成時にブランチとの紐づけを行うため、Development から新規ブランチを作成していました。手元へ対象ブランチをpullして作業し、最終的にプルリクマージすると同時に、紐づいたissueも自動closeされるという運用です。

https://docs.github.com/ja/issues/tracking-your-work-with-issues/creating-a-branch-for-an-issue

で、どうやら今回のブランチ作成時、誤ってブランチ名の先頭を大文字の Feature としてしまっていたようです。

おそらくIME変換で選択ミスったやつですね。

gitはデフォルト設定では大文字/小文字を区別しない

前述の記事内でも言及していますが、gitはデフォルト設定だとパスの大文字/小文字を区別しない設定になっています。

If true, this option enables various workarounds to enable Git to work better on file systems that are not case sensitive, like FAT. For example, if a directory listing finds "makefile" when Git expects "Makefile", Git will assume it is really the same file, and continue to remember it as "Makefile".

The default is false, except git-clone[1] or git-init[1] will probe and set core.ignoreCase true if appropriate when the repository is created.

core.ignoreCase | Git - git-config Documentation

手元の環境でこの設定を確認してみると、案の定、大文字/小文字の区別を無視するデフォルト設定のままになっていました。

$ git config -l --local | grep core.ignorecase
core.ignorecase=true

前回記事の環境であるMacでは設定変更済みだったものの、今回作業を行っていたWindows環境では未設定の状態でした。

そのため、GitHubのリモートリポジトリからpullした際のブランチ名は先頭小文字の feature になっていました。

一方、GitHub側ではパスの大文字/小文字の識別がされるため、pushした際に先頭大文字/小文字の異なる同名ブランチが生成されてしまっていたのです。

つまりどういうことだってばよ

少々ややこしいので整理すると

  • 最初にリモート上で作成したのは大文字 Featureブランチ
  • pullした際に生成されたのが小文字 feature ブランチ?
  • pushしたブランチは小文字 feature ブランチ
  • リモート上に小文字 feature ブランチが作成・更新される
  • リモート上の大文字 Featureブランチは更新されずそのまま
  • ローカルのgitが差分参照しているリモートブランチは大文字 Feature の方?
  • 大文字 Feature ブランチは更新がないため、未push扱いとなっていた

いくつか腑に落ちない点はありますが、概ねこんな感じっぽいです。

ブランチの統合とcore.ignoreCaseの設定変更

「まぁ、そういうものなのかな」という話ですが、パッと見で大文字/小文字の判別ができず、頭を悩まされてしまいました。

状況が整理できたので、不要な先頭大文字のブランチを破棄し、小文字ブランチに統合することにしました。これでリモートとローカルのブランチ名が完全一致したため、未push扱いとなっていた差分も無事解消されました。

同じ轍を踏まぬよう、対象環境でもcore.ignoreCaseの設定変更を行い、一件落着です。

$ git config core.ignorecase false
$ git config -l --local | grep core.ignorecase
core.ignorecase=false

ファイル名やパスの大文字/小文字違いで生じる問題は、目視で原因にたどり着くのがなかなか困難です。可能なかぎり設定等で事前に検知できるようにしておきましょう。

Discussion