例えばWebサイトのバックエンドでアップロードされたファイルを/storage/
フォルダ内に入れているとする。その場合、Gitではアップロードされた/storage/
内の各ファイルは無視したいが、/storage/
フォルダ自体は残しておきたいということがよくある。しかしGitで管理できるのはファイルだけなので、ファイルが一つも入っていないフォルダをGitで表現することはできない。そのために.gitkeep
というダミーの空ファイルを作成してGitで管理することでフォルダを保持するということが頻繁に行われている。
ここではそのような場面でこれまでよく解説されている.gitignore
の書き方とは異なる、より柔軟で単純な書き方を発見したので解説する。
結論
- 保持したいフォルダ構造を作成。ここでは
/storage/
フォルダ以下のフォルダ構造をgitで保持したいとする。 - 各末端のフォルダに空のファイル
.gitkeep
を作成。 -
.gitignore
に以下を書く。
/storage/**
!/storage/**/
!/storage/**/.gitkeep
以上。
これで/storage/
内の各.gitkeep
は追跡され、それ以外のファイルは無視される。
/storage/
内のフォルダ構造は任意の構造にできる。例えば以下のような複雑な構造でも問題ない。
/
└ storage/
├ img/
│ ├ user_icon/
│ │ ├ file
│ │ └ .gitkeep
│ ├ post/
│ │ ├ file
│ │ └ .gitkeep
│ └ file
├ pdf/
│ ├ file
│ └ .gitkeep
└ file
この場合でも各file
は全て無視され、かつ各.gitkeep
は全て追跡対象になる。
この方法でのポイントは.gitignore
の記述が/storage/
内の保持したいフォルダ構造に依存しないことである。後で/storage/
内にサブフォルダが追加されても、サブフォルダの中にさらにサブフォルダができても.gitignore
はたった3行のまま、編集する必要がない。
よってこの.gitignore
の書き方は、特にフォルダ構造が複雑になる可能性がある場合に、保守性も可読性も高いと言える。
参考: 従来の方法
よく解説されている方法で書いた上記の場合の.gitignore
は以下である。
/storage/*
!/storage/img/
/storage/img/*
!/storage/img/user_icon/
/storage/img/user_icon/*
!/storage/img/user_icon/.gitkeep
!/storage/img/post/
/storage/img/post/*
!/storage/img/post/.gitkeep
!/storage/pdf/
/storage/pdf/*
!/storage/pdf/.gitkeep
とても長いしフォルダ構造を変えた場合.gitignore
も変更しなければならない。
なんでこんなに長くなってしまうのかは各所で解説されてるので説明しないが、とにかくこうやって全てのサブフォルダの名前を.gitignore
の中に書く必要がある方法しか出てこなかった(私が調べた限り)。
実行環境情報
UbuntuとmacOS両方で挙動を確認した。
Ubuntu
$ git --version
git version 2.17.1
$ head -n2 /etc/os-release
NAME="Ubuntu"
VERSION="18.04.4 LTS (Bionic Beaver)"
macOS
$ git --version
git version 2.30.1 (Apple Git-130)
$ sw_vers
ProductName: macOS
ProductVersion: 11.4
BuildVersion: 20F71