スキップしてメイン コンテンツに移動

【Day 10】Git for WindowsとDockerの共存(改行コードCRLF問題とパーミッション)

Day 10 アイキャッチ
▲ Day 10: Git for WindowsとDockerの共存 / 改行コードCRLF問題とパーミッション完全対策
🐳
皆さん、こんにちは! Docker/コンテナ実践講座の専任講師です。
Windows上で長年Visual StudioやC#を使い倒し、堅牢なエンタープライズシステムを構築してきたベテランの皆様、心より歓迎いたします!
Windows開発者がDockerコンテナ(Linux世界)へ踏み出したとき、「ほぼ100%の確率で最初に遭遇し、半日〜数日を溶かす最大の落とし穴」が存在します。それが「改行コード(CRLF / LF)問題」と「ファイル実行権限(パーミッション)」の壁です。
「ファイルは間違いなく存在するのに、なぜか ./entrypoint.sh: not found と言われてコンテナが起動しない……」という不可解な現象を、本日はGitの仕組みと合わせて根本から完全撲滅しましょう!

① 導入・本日の達成目標

WindowsとLinuxは、根本的なファイルシステムの思想や改行の表現方式が異なります。 従来のように「Windowsマシンだけで完結するC#開発」を行っている間は、この違いを意識する必要はほとんどありませんでした。
しかし、「WindowsでソースコードやDockerfileを編集し、Linuxコンテナ内で実行する」というハイブリッド環境においては、不可視の1文字や1ビットの差異が致命的な停止障害を引き起こします。

本日の講義を終える頃には、以下の3つの目標を完全にクリアできるようになります。

  • CRLFとLFのバイナリ差異を理解し、Linuxコンテナでスクリプトが落ちる根本原因(シバンの誤認識)を完全特定できる。
  • 個人のPC設定(core.autocrlf)に頼らず、リポジトリ共通ルールとして改行コードを自動統制する .gitattributes を正しく設計できる。
  • Windows環境からでもLinuxの実行権限(chmod +x)をGitインデックスに記録し、コンテナ内での「Permission denied」を根絶できる。

② 改行コードの罠:CRLF vs LF の正体とエラーの真相

テキストファイルの「改行」は、画面上ではただの空白行に見えますが、内部的には特定の制御文字バイトが記録されています。

改行コードCRLF vs LFの罠とエラー原因
▲ 【図解①】WindowsのCRLF(\r\n)とLinuxのLF(\n)の決定的違いと、コンテナ内で発生する不可解なエラーの真相

OSごとの改行コードの仕様は以下の通りです。

  • Windows(CRLF): (0x0D 0x0A の2バイト)。タイプライターの「復帰(Carriage Return)」と「改行(Line Feed)」に由来。
  • Linux / macOS(LF): (0x0A の1バイト)。

なぜ「./entrypoint.sh: not found」という謎エラーが起きるのか?

Windowsのエディタで作成したシェルスクリプトの先頭行には、通常以下のようなシバン(Shebang)を書きます。

#!/bin/sh

しかし改行コードがCRLFの場合、末尾に不可視の (キャリッジリターン)が付着しています。 Linuxカーネルはこれを行末ではなく「コマンド名の一部」として解釈するため、システム上から /bin/sh という名前の実行ファイルを探そうとします。

当然、Linux上に /bin/sh などというファイルは存在しないため、Linuxは「そんなファイルやディレクトリはありません(No such file or directory / not found)」というエラーを吐き出して即座に異常終了します。
開発者は「./entrypoint.sh は目の前にあるのに、なぜ『not found』なんだ!?」と大混乱に陥るわけです。

③ 旧来のファイル共有(VM/Samba)と現代のGit+Docker管理の対比

かつて物理サーバーやVMware時代にも、Windows共有フォルダ(SMB)経由でLinuxにスクリプトをコピーして改行コードが壊れるトラブルが多発していました。

比較項目 従来のファイル共有(SMB / FTP) 現代のGit + Docker管理
改行コードの保持 エディタ保存時の設定依存(事故多発) .gitattributes で自動正規化・強制固定
実行権限(chmod) Linux側で手動 chmod +x 実行が必須 Gitインデックス(100755)で自動追跡
チーム開発の再現性 手順書による属人的な注意喚起のみ 誰がcloneしても100%同一の動作を保証
トラブルシューティング nkfやdos2unixコマンドを手動実行 コミット時点でGitが不正混入を事前ブロック

④ .gitattributes によるリポジトリレベルの完全自動統制

「Git for Windowsをインストールした時に core.autocrlf = true にしたから大丈夫」と考えるのは非常に危険です。
個人のグローバル設定(~/.gitconfig)は、新メンバーの参加時やCI/CD環境(GitHub Actions / GitLab CI)において設定漏れが発生しやすく、再現性が担保できません。

.gitattributesによる改行コード自動統制
▲ 【図解②】.gitattributesによるリポジトリ全体での改行コード自動統制と推奨ルール

チーム開発において唯一にして最強の解決策は、「リポジトリ直下に .gitattributes を配置し、Git自身にファイル種別ごとの改行ルールを強制させること」です。

【決定版】C# + Docker向け .gitattributes 設定ファイル

# -----------------------------------------------------------------------------
# 1. デフォルト設定:すべてのテキストファイルを自動判別し、Git保管時はLFへ正規化
# -----------------------------------------------------------------------------
* text=auto

# -----------------------------------------------------------------------------
# 2. Linux / Docker 実行スクリプト:Windows上であっても【絶対にLF固定】
# -----------------------------------------------------------------------------
*.sh text eol=lf
*.bash text eol=lf
entrypoint.sh text eol=lf
Dockerfile text eol=lf
docker-compose*.yml text eol=lf
*.env text eol=lf

# -----------------------------------------------------------------------------
# 3. C# / .NET 関連コード:差分アルゴリズムの最適化と柔軟な管理
# -----------------------------------------------------------------------------
*.cs text diff=csharp
*.csx text diff=csharp
*.csproj text
*.sln text eol=crlf
*.props text
*.targets text
*.json text
*.xml text
*.config text

# -----------------------------------------------------------------------------
# 4. バイナリファイル:改行コード変換の完全抑止
# -----------------------------------------------------------------------------
*.dll binary
*.exe binary
*.pdb binary
*.so binary
*.png binary
*.jpg binary
*.ico binary

この設定ファイルをリポジトリのルートに置いてコミットするだけで、Windows上のエディタ(Visual Studio / VS Code)がCRLFで保存したとしても、Gitにコミット(ステージング)される瞬間に自動的にLFへ変換され、Linuxコンテナ内には常に純粋なLFとして渡されるようになります。

⑤ ファイル実行権限(パーミッション)の落とし穴と解決法

改行コード問題をクリアしても、次に立ちはだかるのが「実行権限(Executable Permission)」の壁です。

ファイル実行権限パーミッションの落とし穴と解決法
▲ 【図解③】Windowsには存在しないLinux実行ビット(chmod +x)をGitインデックス経由で永続管理する技

Windowsの標準ファイルシステム(NTFS)には、LinuxのようなPOSIX実行権限ビット(rwxr-xr-x)の概念がありません。
そのため、Windows上で新規作成した entrypoint.sh を通常通り git add してコミットすると、ファイルモードは 100644(通常の読み書きファイル / 実行権限なし) として記録されます。

これをDockerビルドでコンテナ内に COPY して実行しようとすると、以下の非情なエラーに直面します。

/bin/sh: ./entrypoint.sh: Permission denied

Windowsから一発解決する「git update-index」コマンド

Linuxマシンを用意したりWSL2側で chmod +x を叩き直さなくても、Git for Windowsのコマンド1行でGitインデックス上のパーミッションを直接変更できます。

# Windows PowerShell または コマンドプロンプトから実行可能
git update-index --chmod=+x scripts/entrypoint.sh

# 変更を確認(ファイルモードが 100644 ➡ 100755 に昇格していることを確認)
git ls-files --stage scripts/entrypoint.sh
# 出力例: 100755 3b18e512... 0 scripts/entrypoint.sh

# 変更をコミット
git commit -m "chore: add executable permission to entrypoint.sh"

ファイルモード 100755 でコミットされたスクリプトは、Linuxコンテナ内へ COPY された瞬間に自動的に実行可能ビットが有効になり、RUN chmod +x をDockerfileに書かなくてもそのまま安全に起動します!

⑥ C# / .NET 現場での実践:理想のGitリポジトリ構造

C#ソースコードとDockerインフラ資産、そしてGit統制設定が調和した理想的なリポジトリ構成を確認しましょう。

C#とDockerが共存する理想のGitリポジトリ構造
▲ 【図解④】C#コード・Docker環境資産・Git統制ルールが美しく調和する理想のチーム開発リポジトリ構造

推奨ディレクトリツリー構成

MyEnterpriseApp/
├── .git/
├── .gitattributes              # 【最重要】改行コード&diff統制ルール
├── .gitignore                  # bin/, obj/, .vs/ の除外
├── .dockerignore               # Dockerビルドコンテキストの最適化
├── Dockerfile                  # マルチステージビルド定義
├── docker-compose.yml          # ローカル開発用スタック定義
├── scripts/
│   └── entrypoint.sh           # LF固定 & 権限100755(DB待機やマイグレーション処理)
└── src/
    ├── MyEnterpriseApp.sln
    └── OrderService/
        ├── Program.cs
        ├── Controllers/
        └── OrderService.csproj

⑦ 実践コマンド集:既存リポジトリの改行コード一括再正規化

「途中で .gitattributes を追加したけれど、既にCRLFでコミットされてしまったファイルがある……」という場合の安全な一括修復手順です。

# 1. 念のため現在の作業変更をコミット
git commit -am "WIP: save before renormalize"

# 2. .gitattributesの定義に従ってインデックス全体を一括再評価・再正規化
git add --renormalize .

# 3. 差分を確認(改行コードのみがLFに修正されたファイルがステージされる)
git status

# 4. コミットしてリモートへプッシュ
git commit -m "chore: renormalize line endings using .gitattributes"
git push origin main

⑧ 4大AIエージェントへの指示プロンプト例

🤖 Antigravity / Claude Code への指示プロンプト:

「Windows環境でC#(.NET 8)Web APIを開発しており、Dockerコンテナ(Linux)との間で改行コードCRLF事故やスクリプト実行権限エラー(Permission denied)を根本防止したいです。リポジトリルートに配置すべき最適な.gitattributesファイルを作成し、既存のscriptsフォルダ内の*.shファイルに対してgit update-index --chmod=+x を適用して一括コミットする手順を提示してください。」

⚠️ 30年選手がハマりやすい現場の落とし穴

「VS Code右下のステータスバーで『CRLF ➡ LF』に変更して満足してしまう罠」
VS Codeの画面下部で個別ファイルを手動でLFに切り替えても、他の開発メンバーがVisual Studioで開いて保存したり、Gitのブランチを切り替えた瞬間にCRLFへ戻ってしまうことがよくあります。
個人のエディタ操作という「努力目標」で改行コードを管理するのは絶対にやめましょう。「.gitattributes でGitリポジトリそのものにルールを埋め込む」ことが、チーム全員の時間を守る唯一のプロの流儀です!

📌 本日のまとめ & 明日へのステップ
  • 改行コードCRLF( )が混入すると、Linuxシバンが /bin/sh を探して「not found」で即死する。
  • .gitattributes をリポジトリルートに配置し、*.sh text eol=lf を指定することで、OSに関わらずLFを強制統制する。
  • Windowsからでも git update-index --chmod=+x を実行することで、Linux実行権限(100755)をGit上で安全に管理できる。
  • 既存リポジトリで改行コードが散乱している場合は git add --renormalize . で一括クリーニングを行う。
次回【Day 11】予告:
いよいよ実践編突入!『最初のコンテナ起動(docker run hello-world から nginx まで)』〜Docker Hubからのイメージ取得とポートマッピングの仕組み〜

コメント

このブログの人気の投稿

【Perfume】Perfume 3rd Tour 「JPN」さいたまスーパーアリーナに行って参りました~

Perfume 3rd Tour 「JPN」1月28日、29日の2daysで参戦して参りました。 ファンクラブ会員の選考抽選会に28日、29日の両日で申し込んでいたんですが、両方とも当選していたという嬉しい誤算。 仕事だぁ、なんだかんだと紆余曲折ありまして28日の参戦は危ぶまれていたのですが、なんとかかんとか28日は40分遅刻しながらも参戦、29日はフル参戦する事が出来ました(∩´∀`)∩

Perfume、2025年末で“コールドスリープ(活動休止)”へ──東京ドーム2daysの記録と、公式・各界・ファンの声

  1) 公式発表・基本情報 活動休止(コールドスリープ)を正式発表 2025年9月21日、公式サイト「 Perfumeより 」で、2026年から一度コールドスリープに入ると発表。再始動の意思(“新しいPerfume”として戻る)も明記。 Perfume Official Site 今後の運用告知(配信・上映など) 同21日付の「 今後のPerfumeに関して 」で、9/23(火・祝)東京ドーム公演の LIVESHIP全世界生配信 および 全国ディレイビューイング 決定を案内。特設サイトも併記。 Perfume Official Site +1 公式グッズ **「Perfume Calendar 2026」**発売決定(B2壁掛け/表紙+2カ月1枚×6枚+ポスター)。テーマは“フルーツ”。 Perfume Official Site 2) 東京ドーム2days(9/22・23)要点 公演タイトル: ZO/Z5 Anniversary “ネビュラロマンス” Episode TOKYO DOME 。日程・開場/開演・会場・物販等の実務情報は特設で公開。 Perfume Official Site 9/23公演を世界配信(LIVESHIP) /ディレイビューイング実施。 Perfume Official Site 海外向け報道(英語)も「 indefinite hiatus 」として広く配信。 The Times of India 国内英字メディアも速報。 朝日新聞 3) 現地レポ( メリ爺 )から見える空気 あなたの現地記録(9/24公開)を、ファクトと現場情景の両面で反映: 両日参戦 。22日は アリーナ 、23日は 1階席から俯瞰 。前日の発表を受け、開演前のザワつき→MC後に“いつもの一体感”へ。開演は22日 18:45 頃。オープニングは**P³ツアー東京ドーム(2020/2)**と同趣向で“回収”の演出。 メリ爺のゲーム万歳 MC所感 :解散ではなく前向きな休止で不安を和らげる内容。 かしゆか の涙、 のっち の気丈さ、 あ〜ちゃん の思い出語り──3人の結束と「 また戻る 」約束が強く刻まれた。 メリ爺のゲーム万歳 体感時間 : “3時間弱”級のボリューム ながら“過去一...

ニンテンドースイッチでオンラインゲームを遊ぶには?

モンスターハンターライズが発売になって、家族でモンハン楽しみたい人が増えたみたいですね。 某ブログの検索キーワードを調べると、モンハンを家族でやるにはどうしたらいいのか?を調べている人が沢山いるのがわかります。 ※これでも一部  家族で協力するにはSwitch2台、ソフトも2つ購入する必要があります。 1台のスイッチでは遊べませんし、ソフト1つでも遊べません。 でも、1台のスイッチで別々アカウントがあれば交代で遊ぶこともできますよ。セーブデータもしっかり分かれます。 Switchのオンラインゲームを家族で遊ぶ方法については以下の記事にまとめてますのでよろしければ参考にしてみてくださいね。 家族でモンスターハンターライズDL版のオンラインプレーを楽しむ方法