このヘージと関連するページ一覧

  • 一人でイチから始めるGIT 導入編
  • 一人でイチから始めるGIT gitignore
  • 一人でイチから始めるGIT push
  • 一人でイチから始めるGIT merge
  • 一人でイチから始めるGIT conflict

  • このページの最終更新日 2020/10/25

    一人でイチから始めるGIT gitignore

     このページは一人でイチから始めるGIT 導入編の続きのページです。導入編を見ていない人は、導入編のページに目を通してから本ページを読み進めて下さい。

    1、gitignore

     「.gitignore」はgitでの管理から除外したいファイルを定義します。単に特定の1つファイルを管理させたくないだけならルールは単純なのですが、この拡張子を除外したいとか、このディレクトリ内にあるファイルを除外したいとか、逆にこのファイルだけを管理したいとなってくると、簡単なようで慣れてないと手間取ることもあったりします。特にgitignoreのスラッシュ「/」やワイルドカード「*」の挙動を理解するのは案外難しかったりもします。
     本ページでは1日目と同様に、「自分の手を動かして体で覚える」ことをコンセプトとしてgitignoreについて纏めていきたいと思います。

     まず空の作業ディレクトリを用意しそのディレクトリ内で「mkdir d1 d2 d1/d1 d1/d2 d1/d1/d2」と打って5つのディレクトリを作成します。次に「touch f.dat f.log f.txt」と打ってファイルを3つ作成します。さらに「cp f.* d1/ ; cp f.* d2/ ; cp f.* d1/d1/ ; cp f.* d1/d2/ ; cp f.* d1/d1/d2/」と打って、3つのファイルを5つのディレクトリにコピーします。これで合計3×6=18個のファイルが出来上がりました。
     ここで「git init ; git add * ; git ls-files」と打ち、Gitのローカルリポジトリを作成し、ファイルを登録してからGitで管理されている全てのファイルの一覧を表示します。result.0のように18個のファイルが表示されるでしょう。

    - result.0 -
    d1/d1/d2/f.dat
    d1/d1/d2/f.log
    d1/d1/d2/f.txt
    d1/d1/f.dat
    d1/d1/f.log
    d1/d1/f.txt
    d1/d2/f.dat
    d1/d2/f.log
    d1/d2/f.txt
    d1/f.dat
    d1/f.log
    d1/f.txt
    d2/f.dat
    d2/f.log
    d2/f.txt
    f.dat
    f.log
    f.txt
    

    ・例1、特定のファイルのみを除外する。

     まず始めの例として特定のファイルのみを除外したい場合を考えます。ここでは「f.dat」ファイルと「d1/d2/f.log」ファイルの2つを除外したいとします。まず「vi .gitignore」と打ってviを起動し「.gitignore」ファイルを作成・編集します。

    - define.1 - 「.gitignore」ファイル
    /f.dat
    /d1/d2/f.log
    

     define.1のように各行の頭にスラッシュを付けて、除外したいファイルを定義します。次に「git reset ; git add * ; git ls-files」と打って登録されたファイルの一覧を表示します。コマンドはセミコロン「;」で区切って複数のコマンドを1行に纏めて書いています。「git reset」は先ほど「git add」で登録したファイルを取り消しています。git add * とワイルドカードを使ってファイルを指定していますが、「.gitignore」ファイルのようにピリオドで始まるファイルは対象にはなりません。
     表示されるファイルの一覧は result.1 のようになります。黒太字の行が実際には表示されている行で、薄青色細字の箇所は実際に表示されていません。18個のファイルからgitignoreで定義された2つのファイルが除外されています。

    - result.1 -
    d1/d1/d2/f.dat
    d1/d1/d2/f.log
    d1/d1/d2/f.txt
    d1/d1/f.dat
    d1/d1/f.log
    d1/d1/f.txt
    d1/d2/f.dat
    d1/d2/f.log
    d1/d2/f.txt
    d1/f.dat
    d1/f.log
    d1/f.txt
    d2/f.dat
    d2/f.log
    d2/f.txt
    f.dat  
    f.log
    f.txt
    

    ・例2、特定のファイルのみを除外する(失敗例)

     define.1 では各行の頭にスラッシュを付けていましたが、付けないでdefine.2 のようにgitignoreファイルを書いた場合はどうなるのでしょう。

    - define.2 - 「.gitignore」ファイル
    f.dat
    d1/d2/f.log
    

     先ほどと同様に「git reset ; git add * ; git ls-files」とコマンドを打つと、result.2 のように表示されます。

    - result.2 -
    d1/d1/d2/f.dat
    d1/d1/d2/f.log
    d1/d1/d2/f.txt
    d1/d1/f.dat
    d1/d1/f.log
    d1/d1/f.txt
    d1/d2/f.dat
    d1/d2/f.log
    d1/d2/f.txt
    d1/f.dat
    d1/f.log
    d1/f.txt
    d2/f.dat
    d2/f.log
    d2/f.txt
    f.dat  
    f.log
    f.txt
    

     単に「f.dat」だけ書いてしまうと、作業ディレクトリをルートとする「f.dat」ファイルだけでなくサブディレクトリ内を含む全ての「f.dat」ファイルが除外されてしまいます。しかし、このルールを憶測しますと「d1/d2/f.log」と書いた場合には「d1/d1/d2/f.log」のファイルも無視されるような気がしますがそうではなく「d1/d1/d2/f.log」はバッチリGitに登録されてしまっています。この辺りが初めてgitignoreをいじくるときに「あるぇ~??」と思うようなところでもあります。
     これは「d1/d1/f.log」のようにスラッシュが複数あったり、「/f.dat」のようにスラッシュが冒頭にある場合には作業ディレクトリをルートとする相対パスとして扱われるのですが、「f.dat」のようにスラッシュなしでファイル名を書いたり、「d2/」のようにスラッシュが末尾だけにあるようにディレクトリ名を書いたりすると、全てのサブディレクトリの中に含まれるファイル・ディレクトリが除外されることになるのです。


    ・例3、特定の拡張子のみを除外する。

     例えば拡張子が「.txt」のファイルのみを除外したい場合はdefine.3 のように記述します。

    - define.3 - 「.gitignore」ファイル
    *.txt
    

     「git reset ; git add * ; git ls-files」とコマンドを打つと result.3のように表示されます。「git reset ; git add * ; git ls-files」は次からコマンド①と省略して書くことにします。なおGitのコマンドインターフェス上で上矢印キーを押下すると、以前に入力したコマンドを再表示させることができます。

    - result.3 -
    d1/d1/d2/f.dat
    d1/d1/d2/f.log
    d1/d1/d2/f.txt
    d1/d1/f.dat
    d1/d1/f.log
    d1/d1/f.txt
    d1/d2/f.dat
    d1/d2/f.log
    d1/d2/f.txt
    d1/f.dat
    d1/f.log
    d1/f.txt
    d2/f.dat
    d2/f.log
    d2/f.txt
    f.dat
    f.log
    f.txt
    

    ・例4、特定のディレクトリ内にあるファイルを除外する。

     まず、全てのd2ディレクトリ内にあるファイルを無視したいとします。.gitignore ファイルは define.4aのように定義します。

    - define.4a - 「.gitignore」ファイル
    d2/
    

     コマンド①を叩きこみます。

    - result.4a -
    d1/d1/d2/f.dat
    d1/d1/d2/f.log
    d1/d1/d2/f.txt
    d1/d1/f.dat
    d1/d1/f.log
    d1/d1/f.txt
    d1/d2/f.dat
    d1/d2/f.log
    d1/d2/f.txt
    d1/f.dat
    d1/f.log
    d1/f.txt
    d2/f.dat
    d2/f.log
    d2/f.txt
    f.dat
    f.log
    f.txt
    

     作業ディレクトリをルートとするd2ディレクトリのみを無視したい場合にはdefine.4b のようにgitignoreファイルを記述します。例1で申し上げたように頭にスラッシュが入っている場合は、作業ディレクトリをルートとする相対パスとなります。

    - define.4b - 「.gitignore」ファイル
    /d2/
    

     コマンド①を叩くと今度はresult.4bのように出力されます。

    - result.4b -
    d1/d1/d2/f.dat
    d1/d1/d2/f.log
    d1/d1/d2/f.txt
    d1/d1/f.dat
    d1/d1/f.log
    d1/d1/f.txt
    d1/d2/f.dat
    d1/d2/f.log
    d1/d2/f.txt
    d1/f.dat
    d1/f.log
    d1/f.txt
    d2/f.dat
    d2/f.log
    d2/f.txt
    f.dat
    f.log
    f.txt
    

    ・例5、除外したディレクトリの中に管理したいファイルが存在する場合

     ルートディレクトリのd1ディレクトリのファイルは基本的にGitの管理からは外したいが、「d1/f.log」というファイルは例外的に管理したい、という場合には define.5a のように記載します。gitignoreでビックリマーク「!」を行の頭につけると、このファイルやディレクトリは管理から除外しないことを意味します。コマンド①の出力結果は result.5aのようになるはずです。

    - define.5a - 「.gitignore」ファイル
    /d1/*
    !/d1/f.log
    
    - result.5a -
    d1/d1/d2/f.dat
    d1/d1/d2/f.log
    d1/d1/d2/f.txt
    d1/d1/f.dat
    d1/d1/f.log
    d1/d1/f.txt
    d1/d2/f.dat
    d1/d2/f.log
    d1/d2/f.txt
    d1/f.dat
    d1/f.log
    d1/f.txt
    d2/f.dat
    d2/f.log
    d2/f.txt
    f.dat
    f.log
    f.txt
    

     ところでこれを define.5b のように記述しては駄目なのでしょうか。実際に自分の手を動かして試してみて下さい。出力結果はresult.5bのようになります。

    - define.5b - 「.gitignore」ファイル
    /d1/
    !/d1/f.log
    
    - result.5b -
    d1/d1/d2/f.dat
    d1/d1/d2/f.log
    d1/d1/d2/f.txt
    d1/d1/f.dat
    d1/d1/f.log
    d1/d1/f.txt
    d1/d2/f.dat
    d1/d2/f.log
    d1/d2/f.txt
    d1/f.dat
    d1/f.log
    d1/f.txt
    d2/f.dat
    d2/f.log
    d2/f.txt
    f.dat
    f.log
    f.txt
    

     define.5bでは「d1/f.log」ファイルは管理対象とはならずに除外されてしまっています。一体何が問題なのでしょうか。あまり見た目には解りにくいことですが、これはgitignoreでは「ファイル」が除外されているかということと、「ディレクトリ」が除外されているということとが違うことに起因しています。define.5aのように「/d1/*」と書いた場合は、「d1」ディレクトリそのものは無視されてはいません。あくまで「d1」ディレクトリの配下にあるファイルやディレクトリが無視されていることになります。
     一方define.5bのように「/d1/」と書いてしまった場合は、「d1」ディレクトリそのものが無視されている状態にある訳です。「!」マークを付けた場合、無視したくないファイルが無視されているディレクトリの中にある場合には、これが無効になってしまうのです。すなわち define.5bの場合は「d1/f.log」を無視したくないが、そもそも「d1」ディレクトリが除外されてしまっているため、「!」マークの行は無効になってしまうということです。

     もう少し難しくなりますが、ルートディレクトリのd1ディレクトリのファイルは基本的にGitの管理からは外したいが、「d1/d1/d2/f.log」というファイルは例外的に管理したい場合はどのようにすれば良いでしょうか。この場合、define.5cのようにすれば目的は達成出来ます。

    - define.5c - 「.gitignore」ファイル
    /d1/*
    !/d1/d1/
    /d1/d1/*
    !/d1/d1/d2
    d1/d1/d2/*
    !/d1/d1/d2/f.log
    

     全てを説明はしませんが、対象となっているのはどの「ファイルとディレクトリ」なのかを考えると理解し易いと思います。2行目の「!/d1/d1/」と書いた場合は、「d1/d1」ディレクトリ自身も含めて「d1/d1/f.log」ファイルや「d1/d1/d2」ディレクトリも無視しないものの対象となっています。一方、3行目で「d1/d1/*」と書いた場合は「d1/d1」ディレクトリ自身が含まれていないことが要点です。結果は result.5c のようになります。

    - result.5c -
    d1/d1/d2/f.dat
    d1/d1/d2/f.log
    d1/d1/d2/f.txt
    d1/d1/f.dat
    d1/d1/f.log
    d1/d1/f.txt
    d1/d2/f.dat
    d1/d2/f.log
    d1/d2/f.txt
    d1/f.dat
    d1/f.log
    d1/f.txt
    d2/f.dat
    d2/f.log
    d2/f.txt
    f.dat
    f.log
    f.txt
    

     まぁ元も子もないことを言うと、管理すべきファイルとすべきでないファイルが複雑に混在しているようならそもそもの管理ファイルの構成を見直す方が先かなとも思いますが、gitignoreというのはお気楽に考えていると手痛い目に合ったりすることもあるので、勉強しておいて頂ければ良いかなという感じですね。また、この辺りの挙動は過去のバージョンのGit 2.7.0 では仕様が違っているようですので、情報を漁る場合には注意して下さい。


    ・例6、特定のファイルだけを管理したい

     最後に、「特定のファイルを無視したい」ではなく「特定のファイルだけを管理したい」場合の記述方法について書き留めておきます。このような書き方は「ホワイトリスト形式」と呼ばれることが多いようです。まず、「d1/d1/f.dat」ファイルのみを管理したい場合は define.6a のように.gitignoreファイルを作成します。

    - define.6a - 「.gitignore」ファイル
    *
    !*/
    !/d1/d1/f.dat
    
    - result.6a -
    d1/d1/d2/f.dat
    d1/d1/d2/f.log
    d1/d1/d2/f.txt
    d1/d1/f.dat
    d1/d1/f.log
    d1/d1/f.txt
    d1/d2/f.dat
    d1/d2/f.log
    d1/d2/f.txt
    d1/f.dat
    d1/f.log
    d1/f.txt
    d2/f.dat
    d2/f.log
    d2/f.txt
    f.dat
    f.log
    f.txt
    

     「.log」拡張子のファイルのみを管理したい場合はdefine.6b のようにします。1・2行目はdefine.6aと同じです。

    - define.6b - 「.gitignore」ファイル
    *
    !*/
    !*.log
    
    - result.6b -
    d1/d1/d2/f.dat
    d1/d1/d2/f.log
    d1/d1/d2/f.txt
    d1/d1/f.dat
    d1/d1/f.log
    d1/d1/f.txt
    d1/d2/f.dat
    d1/d2/f.log
    d1/d2/f.txt
    d1/f.dat
    d1/f.log
    d1/f.txt
    d2/f.dat
    d2/f.log
    d2/f.txt
    f.dat
    f.log
    f.txt
    

     「d1/d1」ディレクトリ以降のファイルを管理したい場合は define.6c のように記述します。二重のアスタリスクは0個以上のファイルやディレクトリに一致することを示します。

    - define.6c - 「.gitignore」ファイル
    *
    !*/
    !/d1/d1/**
    
    - result.6a -
    d1/d1/d2/f.dat
    d1/d1/d2/f.log
    d1/d1/d2/f.txt
    d1/d1/f.dat
    d1/d1/f.log
    d1/d1/f.txt
    d1/d2/f.dat
    d1/d2/f.log
    d1/d2/f.txt
    d1/f.dat
    d1/f.log
    d1/f.txt
    d2/f.dat
    d2/f.log
    d2/f.txt
    f.dat
    f.log
    f.txt