Gitの.gitignoreで、フォルダーの一部だけを管理する方法
.gitignore で無視したフォルダーの中の一部のファイルだけを Git で管理するには、フォルダーを logs/ ではなく logs/* と書き、その下の行に !logs/.gitkeep のような「!」付きの行を書きます。logs/ と書くとフォルダーごと無視され、あとから「!」を書いても効きません。ログやキャッシュのフォルダーを空のまま残したいとき(.gitkeep を置く方法)や、データ用フォルダーにある説明ファイル(README など)だけをコミットしたいときに使う書き方です。
検証環境は Ubuntu 24.04、Git 2.43.0 です。作者の名前とメールアドレスには例示用の値(Neko <neko@example.com>)を設定し、コミットの日時は環境変数 GIT_AUTHOR_DATE と GIT_COMMITTER_DATE で決めました。Windows・macOS や、.git/info/exclude、グローバルの除外設定(core.excludesFile)での書き方は試していません。
例のリポジトリ:logs フォルダーの .gitkeep だけを残したい
logs/ の中に、.gitkeep(空のファイル)と、アプリが書き出す app.log、error.log がある状態から始めます。管理したいのは .gitkeep だけです。
$ ls -A logs
.gitkeep
app.log
error.log
$ git status --short
?? logs/
git status は、追跡していないフォルダーを logs/ のようにまとめて表示します。-uall を付けると、フォルダーの中のファイルが1つずつ表示されます(git status の公式リファレンスにある -u の説明)。この記事では、どのファイルが無視されたかを見るために -uall を付けます。
$ git status --short -uall
?? logs/.gitkeep
?? logs/app.log
?? logs/error.log
logs/ と書くと、「!」を足しても戻らない
まず、logs/ でフォルダーを無視し、次の行に !logs/.gitkeep を書きます。
$ cat .gitignore
logs/
!logs/.gitkeep
$ git status --short -uall
?? .gitignore
logs/.gitkeep は一覧に出てきません。どの行で無視されたのかは、git check-ignore -v で確かめられます。出力は「ファイル名:行番号:パターン」と、対象のパスです。
$ git check-ignore -v logs/.gitkeep
.gitignore:1:logs/ logs/.gitkeep
1行目の logs/ で無視されたままで、2行目の !logs/.gitkeep は使われていません。git add で追加しようとしても、無視されているのは logs フォルダーだと言われます。
$ git add logs/.gitkeep
The following paths are ignored by one of your .gitignore files:
logs
hint: Use -f if you really want to add them.
hint: Turn this message off by running
hint: "git config advice.addIgnoredFile false"
gitignore の公式リファレンスには、親のフォルダーが除外されているファイルは、「!」で戻せないと書かれています。Git は処理を速くするために、除外したフォルダーの中を見ません。そのため、中のファイルについて書いた行は、どこに書いても効きません。
logs/* と書くと、.gitkeep だけが管理の対象に戻る
1行目を logs/* に変えます。logs/* は「logs フォルダーの中にあるもの」に一致するので、logs フォルダー自体は無視されません。Git はフォルダーの中を見て、無視するかどうかをファイルごとに判断します。
$ cat .gitignore
logs/*
!logs/.gitkeep
$ git status --short -uall
?? .gitignore
?? logs/.gitkeep
git check-ignore -v は、「!」付きの行に一致して無視されないファイルも、その行と一緒に表示します。.gitkeep は2行目の「!」付きの行に一致し、ログの2つは1行目に一致しています。付けている -n は、どの行にも一致しないファイルも表示するためのオプションです。
$ git check-ignore -v -n logs/.gitkeep logs/app.log logs/error.log
.gitignore:2:!logs/.gitkeep logs/.gitkeep
.gitignore:1:logs/* logs/app.log
.gitignore:1:logs/* logs/error.log
git add -n .(実際には追加せず、追加されるファイルを表示する)でも、.gitkeep だけが入ることが分かります。
$ git add -n .
add '.gitignore'
add 'logs/.gitkeep'

この状態でコミットすると、logs フォルダーからは .gitkeep だけが入ります。
$ git add . && git commit -q -m "logs フォルダーを .gitkeep だけ管理する"
$ git ls-files
.gitignore
app.js
logs/.gitkeep
$ git log --stat -1
commit 7495bd05aae5ac549f112523d698a950e6fe8ab5
Author: Neko <neko@example.com>
Date: Fri Nov 13 10:00:00 2026 +0900
logs フォルダーを .gitkeep だけ管理する
.gitignore | 2 ++
logs/.gitkeep | 0
2 files changed, 2 insertions(+)
コミットのあとに app.log へ書き足しても、git status には何も出ません。
$ echo "next" >> logs/app.log && git status --short -uall
「!」の行は、無視する行より下に書く
同じ .gitignore の中では、一致した行のうち最後の行で結果が決まります(gitignore の公式リファレンスにある優先順位の説明)。順番を逆にして、!logs/.gitkeep を先に書くと、.gitkeep もあとの logs/* で無視されます。
$ cat .gitignore
!logs/.gitkeep
logs/*
$ git status --short -uall
?? .gitignore
$ git check-ignore -v logs/.gitkeep
.gitignore:2:logs/* logs/.gitkeep
深い階層のファイルだけを戻すときは、途中のフォルダーも戻す
次は、data/ の中の data/samples/readme.md だけを管理したい場合です。data/ には raw/big.csv と samples/small.csv もあります。data/* と !data/samples/readme.md の2行だけでは、readme.md は戻りません。
$ cat .gitignore
logs/*
!logs/.gitkeep
data/*
!data/samples/readme.md
$ git status --short -uall
M .gitignore
$ git check-ignore -v data/samples/readme.md
.gitignore:3:data/* data/samples/readme.md
data/* は data の中にある samples フォルダーにも一致します。親の samples フォルダーが除外されるので、logs/ のときと同じく、中の readme.md を「!」で戻せません。
そこで、途中のフォルダーを「!」で戻し、そのフォルダーの中身をもう一度 /* で無視してから、残したいファイルを戻します。
$ cat .gitignore
logs/*
!logs/.gitkeep
data/*
!data/samples/
data/samples/*
!data/samples/readme.md
$ git status --short -uall
M .gitignore
?? data/samples/readme.md
$ git check-ignore -v -n data/raw/big.csv data/samples/small.csv data/samples/readme.md
.gitignore:3:data/* data/raw/big.csv
.gitignore:5:data/samples/* data/samples/small.csv
.gitignore:6:!data/samples/readme.md data/samples/readme.md
3つのファイルが、それぞれ別の行で判断されています。公式リファレンスにも、/*、!/foo、/foo/*、!/foo/bar の4行で foo/bar 以外を除外する、同じ形の例があります。どちらも、途中のフォルダーについて「フォルダーを戻す行」と「その中身を無視する行」を書いています。
.gitignore を変えずに git add -f で追加する方法もある
.gitignore は logs/ のままにして、特定のファイルだけを git add -f で追加することもできます。-f は、無視されるファイルの追加を許すオプションです(git add の公式リファレンス)。
$ cat .gitignore
logs/
$ git add logs/manual.txt
The following paths are ignored by one of your .gitignore files:
logs
hint: Use -f if you really want to add them.
hint: Turn this message off by running
hint: "git config advice.addIgnoredFile false"
$ git add -f logs/manual.txt && git status --short
A logs/manual.txt
これをコミットして追跡を始めると、.gitignore に一致していても、変更が git status に出ます。
$ git commit -q -m "logs/manual.txt を追加" && git status --short
$ echo "edited" >> logs/manual.txt && git status --short
M logs/manual.txt
このとき git check-ignore -v logs/manual.txt は何も表示せず、終了コード 1 で終わります。追跡しているファイルなので、無視の対象として扱われないためです。.gitignore のどの行に一致しているかを見たいときは、インデックス(追跡しているファイルの情報)を見ない --no-index を付けます(git check-ignore の公式リファレンス)。
$ git check-ignore -v --no-index logs/manual.txt
.gitignore:1:logs/ logs/manual.txt
git add -f で追加しても、.gitignore は logs/ の1行のままです。どのファイルを例外にしたかを .gitignore に書いて残したいなら、logs/* と「!」の書き方が向いています。




