【Git初心者向け】空のディレクトリが追跡できない?3つの解決方法と.gitkeepの使い方

プロジェクトの開発を進めていると、こんな経験はありませんか?

「ログファイルを保存するための logs/ ディレクトリを作ったのに、GitHubにpushしたら消えている...😱」

実は、Gitには「空のディレクトリは追跡しない」という仕様があります。たまに、この問題にぶち当たり、これまで色々な方法で対応してきましたが、もっとシンプルで素敵な解決方法があることを知って驚きました!今回は、その発見までの道のりを共有します。

なぜ空のディレクトリは追跡できないのか?

基本的なお話。

Gitファイルの変更履歴を管理するシステムです。ディレクトリ自体ではなく、ディレクトリ内のファイルを追跡しているのです。そのため、ファイルが1つも入っていないディレクトリは、Gitにとって「存在しないもの」として扱われてしまいます。

# 例えばこんな感じ
project/
├── src/
│   └── main.js
├── logs/          # 空のディレクトリ
└── README.md

この状態で git add . を実行しても、logs/ ディレクトリはバージョン管理の対象になりません。

解決方法1 … README.md を置く(私が使っていた方法)

私が最初に採用したのは、そのディレクトリの目的を説明するREADME.mdを置く方法でした。

例えば以下のようなファイルをおきます。

README.md

# Logs Directory

このディレクトリにはアプリケーションのログファイルが保存されます。

## 注意事項
- ログファイルは.gitignoreで除外されています
- 本番環境では外部ログサービスの使用を推奨

ファイルを作成後に以下のように、Git管理に追加します。これでOKです。

$ git add README.md
$ git commit -m "Add logs directory with README"

この方法の良いところは

  • ディレクトリの目的が明確(説明あるし)
  • 他の開発者への情報共有になる
  • 特に新しいメンバーがプロジェクトに参加した時に親切

実用的で、今でもよく使っています。ただ、「単純に空ディレクトリを保持したいだけなのに、説明文を書くのは少し手間だな」と感じることもありました🤔

解決方法2 … .gitignoreを使う(これもよく使っていた)

もう一つ私がよく使っていたのが、.gitignore ファイルを置く方法です。リポジトリのルートに.gitignoreを置くのと同様に、空のディレクトリにも.gitignoreを作成するというものです。

$ git add .gitignore
$ git commit -m "Add cache directory"

この方法は、「将来的にファイルが入るけど、それらはGitで追跡したくない」というケースに最適です。

例えば

  • cache/ - キャッシュファイル置き場
  • temp/ - 一時ファイル置き場
  • uploads/ - ユーザーアップロードファイル置き場

実用性が高く、目的にも合っているので重宝していました👍

ただ、これも「中身を除外する必要がない空ディレクトリの場合は、ちょっと大袈裟かも?」という思いがありました。

解決方法3 … .gitkeepを使う

そして、つい最近知ったのが .gitkeep という方法です。 正直、最初にこのファイル名を見た時は「え、なにこれ?Gitの公式機能?」と混乱しました😅

調べてみると、これはGitの公式機能ではなく、開発者コミュニティで広く使われている慣習だったのです!そして、そのシンプルさに驚きました。

.gitkeepの使い方

使い方はシンプルです。

# 空のディレクトリに移動
$ cd logs/

# .gitkeepファイルを作成
$ touch .gitkeep

# Gitに追加
$ git add .gitkeep
$ git commit -m "Add logs directory"

たったこれだけ!🎉

READMEを書く必要も、.gitignoreの設定を書く必要もありません。ただ空のファイルを置くだけで、空のディレクトリがGitで追跡されるようになります。

なんだ、こんなシンプルな方法があったのか!と、目から鱗でした😳

なぜ.gitkeepという名前?

名前の由来は「このディレクトリをGitkeep(保持)する」という意味からきています。わかる🤗

ファイル名自体に特別な意味はなく、単に「空でないディレクトリにするためのプレースホルダー」として機能します。実は、ファイル名は何でも良いのですが、.gitkeep が広く使われているようです。このあたりは、開発チームの規約に合わせて選ぶのが良いでしょう。

ファイルの中身は完全に空で問題ありませんが、README.mdと同様に説明の文言をいれてもよいです。

# 中身が空でもOK
$ touch .gitkeep

# または一言メッセージを入れても良い
$ echo "This directory is for log files" > .gitkeep

なぜもっと早く知らなかったんだろう...

この方法を知った後、過去のプロジェクトを見返してみると、わざわざREADMEを書いていた場所がいくつもありました💦

もちろん、READMEで説明を残すことも大切ですが、「単に空ディレクトリを保持したいだけ」という場合は、.gitkeep が圧倒的にシンプルです!

実務で気をつけたいポイント

.gitkeepを使い始めて気づいたこともあります。ちょっと役立つTipsです。

1. ルートの.gitignoreに注意

プロジェクトのルートに .gitignore がある場合、ドットファイル全体を無視していると .gitkeep も無視されてしまいます。

こんな時は、.gitkeep だけを例外にしましょう:

# プロジェクトルートの.gitignore
.*        # すべてのドットファイルを無視
!.gitignore
!.gitattributes
!.gitkeep   # .gitkeepだけは追跡

これで安心です😊

2. 生成物を明示的に無視する

logs/ のように実行時にファイルが生成されるディレクトリは、.gitkeep だけだと生成物を誤ってコミットしてしまいがちです。

そこで、.gitkeep.gitignore両方配置するのがおすすめです:

$ cd logs/

# ディレクトリを追跡するための.gitkeep
$ touch .gitkeep

# 生成物を無視するための.gitignore
$ cat > .gitignore << 'EOF'
# このディレクトリの全ファイルを無視
*
# ただし.gitignoreと.gitkeepは追跡
!.gitignore
!.gitkeep
EOF

$ git add .gitkeep .gitignore
$ git commit -m "Add logs directory with gitkeep and gitignore"

これで、ディレクトリ構造は保持しつつ、ログファイルは自動で無視されます👍

3. リリース時の配慮

パッケージ配布やリリースアーカイブ.gitkeep を含めたくない場合は、.gitattributes で除外できます。

# .gitattributes
.gitkeep export-ignore

これで、git archive などでエクスポートする際に .gitkeep が含まれなくなります。

どの方法を選ぶべき?

3つの方法を知った今、私はこんな使い分けをしています:

方法 適しているケース メリット 注意点
README.md ディレクトリの目的を説明したい 情報共有になる、新メンバーに親切 単に保持したいだけなら冗長
.gitignore 中身を追跡したくないディレクト 実用的、将来のファイルを自動除外 例外指定の漏れに注意
.gitkeep シンプルに空ディレクトリを保持したい 最もシンプル、慣習として広く認知されている 生成物を誤コミットしやすい

私は以下のように使用しています。

  • 基本的には .gitkeep を使う(シンプルで分かりやすい!)
  • 説明が必要なら README.md を追加する
  • 中身を除外するなら .gitignore を使う(.gitkeepと併用がベスト)

もちろん、複数を組み合わせることもできます。

以前は全部README.mdを書いてもいましたが、今は目的に応じて使い分けられるようになりました!スッキリして気持ちいいです😊

おわりに

.gitkeep という慣習を知った時は、「こんなエレガントな解決方法があったのか!」と本当に驚きました😄 これまでREADME.gitignoreで対応していた私にとって、この発見は大きな学びでした。

皆さんも、プロジェクトのディレクトリ構造を整える時に、ぜひこれらの方法を使い分けてみてください!特に.gitkeepを知らなかった方は試してみてはどうでしょうか?