プロジェクトの開発を進めていると、こんな経験はありませんか?
「ログファイルを保存するための logs/ ディレクトリを作ったのに、GitHubにpushしたら消えている...😱」
実は、Gitには「空のディレクトリは追跡しない」という仕様があります。たまに、この問題にぶち当たり、これまで色々な方法で対応してきましたが、もっとシンプルで素敵な解決方法があることを知って驚きました!今回は、その発見までの道のりを共有します。
- なぜ空のディレクトリは追跡できないのか?
- 解決方法1 … README.md を置く(私が使っていた方法)
- 解決方法2 … .gitignoreを使う(これもよく使っていた)
- 解決方法3 … .gitkeepを使う
- 実務で気をつけたいポイント
- どの方法を選ぶべき?
- おわりに
なぜ空のディレクトリは追跡できないのか?
基本的なお話。
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という名前?
名前の由来は「このディレクトリをGitでkeep(保持)する」という意味からきています。わかる🤗
ファイル名自体に特別な意味はなく、単に「空でないディレクトリにするためのプレースホルダー」として機能します。実は、ファイル名は何でも良いのですが、.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を知らなかった方は試してみてはどうでしょうか?