目次

gitignore とは何であるか

gitignore ファイルは、意図的に track されていないファイルを指定しそれらを Git に無視させるためのファイルです。 このことは公式のリファレンス (https://git-scm.com/docs/gitignore) に次のような形で書かれています。

NAME

gitignore - Specifies intentionally untracked files to ignore

DESCRIPTION

A gitignore file specifies intentionally untracked files that Git should ignore. Files already tracked by Git are not affected; see the NOTES below for details.

ただし、ここで言う “gitignore” は、リポジトリのルートに置かれたあの .gitignore file のみのことではありません。 $XDG_CONFIG_HOME/git/ignore (Linux では ~/.config/git/ignore) および $GIT_DIR/info/exclude (たいていの場合 .git/info/exclude) および (リポジトリのルートに限らない様々な場所にある) .gitignore のことを総称して “gitignore” と呼びます。 実際、”gitignore” と題された公式のリファレンスの冒頭は次のようになっています。

SYNOPSIS

$XDG_CONFIG_HOME/git/ignore, $GIT_DIR/info/exclude, .gitignore

gitignore とは何のためのものか

Git に勝手に git add されたくないファイルや、そもそも「track されていない」と表示されてさえほしくないファイルがあれば、これを無視するために使うとよいでしょう。 これは公式のドキュメントである Pro Git book で紹介されている用法です。 “2.2 Git Basics - Recording Changes to the Repository” (https://git-scm.com/book/en/v2/Git-Basics-Recording-Changes-to-the-Repository#_ignoring) には次のようにあります。

Ignoring Files

Often, you’ll have a class of files that you don’t want Git to automatically add or even show you as being untracked. These are generally automatically generated files such as log files or files produced by your build system. In such cases, you can create a file listing patterns to match them named .gitignore.

gitignore は「ファイルを track されていない状態に変えるもの」ではない

「gitignore ファイルは、ファイルを track されていない状態にするためのものである」という説明は不正確です。 gitignore ファイルは「track されていない状態のファイルを無視させる」あるいは同じことだが「track されていない状態のファイルを track されていない状態に保つ」機能を持ちます。しかし「すでに track されている状態のファイルを track されていない状態に戻す」のような機能は持ちません。

gitignore について表面的にのみ解説している説明はたいていこの区別について曖昧に (おそらくこの区別を理解せずに) 書かれています。そのような説明の例としては次があります。

まずはgitignoreとは何かについて知っておきましょう。gitignoreはGitで使われる特殊なファイル名で、このファイルに書かれたファイルは上から順に処理されて、Gitのトラッキングの対象外になります。

gitignoreを設定して無視するファイルを指定しよう | 侍エンジニア塾ブログ(Samurai Blog) - プログラミング入門者向けサイト1

多くの人がこの不適切な説明に混乱させられていることは、「gitignore」で Google 検索をすると「gitignore あとから」というフレーズがサジェストされる2ことから察せられます。 「gitignore あとから」というフレーズが多く検索されることの説明として「gitignore がファイルを track されていない状態に変える機能だと理解されているからだ」という説明は自然であるためです。

なお、この「ファイルを track されていない状態に変える」という目的で使うべき機能は git rm です。

ファイルを track されていない状態に保ちたいだけなら git add しなければよい

foo.txt というファイルと bar.txt というファイルがあり、共に新規に作成したものであり共に track されていないとします。このとき foo.txt だけを commit に含めるにはどうすればよいでしょうか? これはもちろん $ git add foo.txt とすればよいです。.gitignorebar.txt という行を追加する必要はありません。

.gitignore が (実際には必須でない機能であるにも関わらず) ほとんど必須のものとして理解されている背景として、ファイルを index に追加するための機能として多くの人が $ git add . というやり方以外を知らない (ファイルを個別に index に追加するという発想がない) ことが予想されます。 しかし $ git add . はあまり丁寧なコマンドとは言えません。 「手元で実験用に書いたスクリプト (認証情報などを含む) が間違えて commit に含まれてしまっていたが、気付かず push してしまった」という状況はたまに見かけます。 何が commit に含まれるのかは $ git status や commit message の編集画面などで確認できるので、注意しながら commit を作りましょう。

$XDG_CONFIG_HOME/git/ignore$GIT_DIR/info/exclude.gitignore をどう使いわけるべきか

使い分けについても、公式のリファレンス (https://git-scm.com/docs/gitignore) にあります。 以下のようなことが書かれています。

  • バージョン管理され git clone によって共有されるべきパターン (つまり、すべての開発者が無視したいと思うようなパターン) は .gitignore ファイルに書くべきです。
  • 特定のリポジトリに固有であるが他の開発者と共有する必要のないパターン (たとえば、ひとりのユーザのワークフローに特有の補助的なパターン) は $GIT_DIR/info/exclude に書くべきです。
  • あるユーザがすべての状況で無視したいようなパターン (たとえば、そのユーザの利用しているエディタによって生成されるバックアップファイルや一時ファイルについてのパターン) は $XDG_CONFIG_HOME/git/ignore に書くべきです。

必ずしも core.excludesfile を指定する必要はない

グローバルな gitignore を利用するために core.excludesfile を指定する必要はありません。 そのデフォルト値である $XDG_CONFIG_HOME/git/ignore を使えばよいためです。 これはたいていは $HOME/.config/git/ignore に一致します。 また $XDG_CONFIG_HOME が未設定の場合にも $HOME/.config/git/ignore が用いられます。

core.excludesfile を利用した説明は多く見られますが、それらは「$XDG_CONFIG_HOME/git/ignore が追加される前に書かれた古い文章である」「$XDG_CONFIG_HOME の値が何であっても動作するようにするため、$XDG_CONFIG_HOME に依存しない方法を意図的に選んで紹介している」「古いバージョンの git コマンドでも動作するようにするため、古くからある機能を意図的に選んで紹介している3」「他の文章をあまり理解せずそのままコピペしてきて書かれた」のいずれかでしょう。 たとえば Pro Git book (Git - Git の設定) でも GitHub Docs (ファイルを無視する - GitHub Docs) でも core.excludesfile を用いていますが、これは「$XDG_CONFIG_HOME の差を避けるために意図的に選んで紹介している」のだと思われます。

パターンの書き方

公式のリファレンス (https://git-scm.com/docs/gitignore#_pattern_format) に書いてあることがすべてです。

  • 空行は無視される
  • # から始まる行は無視される
  • 特殊な意味を持つ記号は \ で escape できる
  • 行末の空白は無視される
  • 行頭に ! を書くとその行の内容は反転 (無視されていたものを無視しないようにする)する。ただし、すでに無視されているディレクトリは (もしそのディレクトリの中に .gitignore が置かれていたとしても) 処理されることはないので注意が必要である
  • / はディレクトリの区切りとして認識される (訳中: Windows であっても \ でなく / を使う)
  • 行末以外の場所に / を含む行は、.gitignore の置かれた場所からの相対パスとして扱われる。foo/bar/foo/bar と同じ意味であることに注意しよう
  • パターンの指定には *?[a-zA-Z] のような fnmatch(3) に由来する記法が使える
  • パターンの指定には ** という記法が使える。これは / を 0 個以上含むようなパスにマッチする

余談: この記事はなぜ書かれたのか

個人 OSS 開発をしていると “Add .gitignore” とか “Update .gitignore” というプルリクエストが送られてくることがあります。 たいていはその送り主が独自に利用しているエディタや環境のための設定が含まれています。 それは「あまりコードが書けない人でも作れるようなプルリクエスト4なので気軽に送られてきて」「なにもしていないのに巻き込まれる自転車置場の議論」であり「なにかエンドユーザの利益になるわけではない」ために、受け取るとなんとなくもやっとした気持ちになります5

この記事は、そのような気持ちになったために、とりあえず .gitignore について調べ直した結果をまとめたものです。 .gitignore の機能自体がかなり小さなものであったので、実質的に man page の全体の翻訳となっています6。 特になにかを意見を主張するための記事ではありません。

当初は、.gitignore に批判的な立場から「たとえば node_modules/ のような言語依存だが実質的に常に無視されるべきファイルについても $XDG_CONFIG_HOME/git/ignore に書くべきだ。そのようなファイルは (JavaScript 以外の) すべてのリポジトリで無視して問題ないものであり、また無視されるべきである。そのような、すべてのリポジトリで無視されるべきものを .gitignore に書くべきではない。」を主張しようとしていました。しかし「このような思想の人は少なそう」「この方針では .gitignore についてのプルリクが来ることは避けられず、毎回説明が発生して面倒である」「多数派に逆らってまでこの方針での運用にこだわるほどの利益はまったくない」ために主張は取り下げられました。

現在は「.gitignore には、リポジトリで使われているワークフローや言語に依存するファイル (例: node_modules/) を書く。個人のエディタや IDE や環境に依存するファイル (例: *.swp .vscode .DS_Store) は書かない。」という (常識的な) 方針が面倒や不和を減らす意味で適切だろうと考えています。

参考

脚注

  1. ちなみに他にもいろいろ変です。たとえば「gitignoreは……ファイル名で、このファイルに……」であり、「ファイル名」と「ファイル」の区別すら曖昧です。 

  2. 少なくとも現時点の私の環境では 

  3. core.excludesfile はより古くからある機能ですが、そのデフォルト値は 2012年8月に公開された Git v1.7.12 で追加されました (https://lwn.net/Articles/512976/, git/Documentation/RelNotes/1.7.12.txt

  4. そのようなプルリクエストそのものが悪いわけではありません。誰しもそのようなレベルから初めるものであり、また、技術的に簡単であるかどうかとユーザにとって価値があるかは無関係です。 

  5. 特に、個人の環境にのみ依存したそのリポジトリに無関係なファイルについての指定を .gitignore に含めてしまうと、それとは別の個人の環境に依存した別のファイルについての指定を追加しろという別のプルリクエストを呼び込んでしまうだろうという問題があり、たいてい reject の方向で対応しています。 

  6. この記事を書くよりも、この man page を翻訳してプルリクエストを投げる方が適切だった可能性はあります。