👻

[Git] 空ディレクトリをチェックインする

2023/02/01に公開

アプリケーションのログを出力するディレクトリのように、「中身が空っぽのディレクトリをGitの管理に含めたい。ただし、そのディレクトリの中にファイルが生成されても、そのファイルはGitの管理に含めたくない。」という場合のやり方です。

ググると、割と不正確な情報がたくさん引っかかるので...

方法

以下、プロジェクトトップ階層の、logsという名前のディレクトリを例に使います。

  1. logsディレクトリ配下に、ダミーファイル「.gitkeep」もしくは「.keep」を作成します。ファイルの中身は無くてよいです。

    $ mkdir logs/
    $ touch logs/.gitkeep
    
    ダミーファイルの名前について

    ダミーファイルの名前は、Gitの決まりごというわけではなく、実際には何でもよいです。後述の.gitignoreファイルで適切に設定すれば、問題ありません。

    ただし、慣習としては、ドット付きで隠しファイル扱いにした「.gitkeep」や「.keep」というファイル名がよく使われます。
    特別な理由がない限り、これらの名前を使ったほうが、わかりやすくてよいでしょう。

  2. .gitignoreに、以下のように記載します(ダミーファイル名として「.gitkeep」を採用した場合):

    .gitignore
    # Keep empty logs/ directory.
    /logs/*
    !/logs/.gitkeep
    

    設定の意味とポイントは、次のとおりです:

    • /logs/*:トップ階層のlogsディレクトリの中身をすべて、一旦ignoreする
      (結果的に、logsディレクトリも、Gitにチェックインしないことになる(仕組みと考え方参照))

      • ディレクトリ名の先頭に/をつける

        • 無いと、「階層問わず、とにかく名前がlogsのディレクトリをignore」になってしまう
      • /logs/のあとにワイルドカード*をつける

        • 無いと、「logsディレクトリをignore」になってしまう[1]

          If there is a separator at the end of the pattern then the pattern will only match directories, otherwise the pattern can match both files and directories.

        • ignoreしたいのは「logsディレクトリ配下のファイルなんでも」
    • !/logs/.gitkeep:ファイル「logs/.gitkeep」のみチェックインを許可

      • /logs/*の行の直後に書く
        • .gitignoreファイルの末尾に.gitkeepと書く(「階層問わずどこかの.gitkeepを許可」の意味)よりも、近くに・効果の範囲を限定的に書いたほうが、何をしたいのかわかりやすい

仕組みと考え方

Gitはファイルのみを管理します。ディレクトリ単体のチェックインはできません。

ディレクトリについては、コミットされたファイルのパスを再現する際に、途中のディレクトリが無ければ、作られる...というようなイメージになります(典型的にはgit clone時など)。

そこで、空ディレクトリlogsのみをGit管理したい場合は、

  1. 仕方なくダミーのファイルを使って、「logsディレクトリがパスにあるファイル」を含めたコミットを作る
  2. ただし、logsディレクトリ配下の他のファイルはGitの管理に入らないようにする

というようにします。これで(ダミーのファイル以外は)空のlogsディレクトリが得られることになります。

脚注
  1. https://git-scm.com/docs/gitignore ↩︎

Discussion