你不知道的.gitignore

你不知道的.gitignore

0. 幾個概念

  • 被gitignore規則命中,即被gitignore規則匹配到的文件或目錄,不會被Git追蹤,即不會被Git給track

1. 簡介

  • .gitignore,是用來顯式指定哪些文件或文件夾應該被Git忽略的一個文件
  • $HOME/.gitignore_global, $HOME/.config/git/ignore, $GIT_DIR/info/exclude, .gitignore這些地方指定的ignore規則都會在Git倉庫中生效

2. 描述

一個.gitignore文件顯式地指定了哪些文件不該被Git追蹤,即被Git忽略掉。在被gitignore以前已經被Git追蹤的文件不受gitignore規則的影響。關於gitignore規則的詳情請繼續往下看。html

.gitignore文件中的每一行都指定了一種匹配模式。一般來講,Git會從多個可能的規則源獲取gitignore規則來決定Git是否要忽略某一個具體的路徑path,以下按照優先級列出了各類規則源,越靠前的規則優先級越高(在一個規則源內部,若是有多個gitignore匹配,以最後匹配的爲準)linux

  • 從命令行輸入的規則
  • 該路徑下的.gitignore文件,或者父級目錄的.gitignore中定義的規則。其中,越靠近具體路徑的.gitignore文件的優先級越高,同目錄下的.gitignore文件優先級最高。項目倉庫中一般都有.gitignore文件,裏面會包含忽略項目build自動生成的文件的規則
  • $GIT_DIR/info/exclude中定義的規則
  • Git配置變量core.excludeFile指定的規則

具體講gitignore規則定義在哪一個文件中取決於該規則的做用(域):git

  • 若是一個gitignore規則應該被Git追蹤,別人clone倉庫後規則也生效,那麼它就應該被定義在.gitignore文件中
  • 若是某個規則只想在某一個特定的倉庫中生效,就把它定義在$GIT_DIR/info/exclude中吧
  • 若是你的gitignore規則要在任何狀況下都生效,這種規則最好放在core.excludesFile這一變量中,這個變量定義在用戶目錄下-~/.gitconfig,該變量的默認值是$XDG_CONFIG_HOME/git/ignore,若是$XDG_CONFIG_HOME是空的,Git會使用$HOME/.config/git/ignore

Git的底層管道工具,好比git ls-filesgit read-tree,只從命令行參數||命令行參數指定的文件中讀取gitignore規則。上層的Git工具,好比git statusgit add,會從上述規則源中讀取gitignore規則shell

3. gitignore規則

  • 空行不匹配任何文件,因此能夠用空行來加強gitignore規則的可讀性
  • 註釋行以#開頭。能夠在#前加一個反斜槓轉義之,使之可以匹配包含#字符的文件夾或文件
  • 若是每一行最後尾隨的空格沒有用反斜槓轉義,那麼這些空格是無效的,不會做爲規則的一部分
  • 使用!前綴來否認以前的規則。若是一個文件被前面的gitignore規則給匹配到了,那麼該文件不會被Git追蹤,可是若是後面的規則使用!匹配到了該文件,那麼該文件又會被Git追蹤。固然,若是一個文件的父目錄都被Git忽略了,那麼不管如何,這個文件都不會被Git追蹤。出於性能考慮,Git不會遍歷被忽略的目錄,所以,定義在被忽略目錄下的gitignore規則都是無效的。有時候,咱們真的是想忽略以感嘆號!開頭的一個文件或者目錄,這時,能夠在感嘆號!前面加一個反斜槓轉義之,好比:\!important.txt會匹配文件!important.txt
  • 若是一個規則以斜槓結尾,在實際匹配的時候,最後的斜槓會被移除掉,可是這個規則只會匹配目錄,而不會匹配文件。換句話說,foo/會匹配到目錄foofoo下的子目錄,但不會匹配到文件foo或者軟連接foo
  • 若是規則中不包含斜槓/,Git就會就會把該規則當成通配符規則來進行處理,從該規則所在.gitignore文件所在路徑開始匹配。固然,若是這個規則不是放在.gitignore文件中的,就會從work tree的頂部開始匹配
  • 若是規則不符合以上的狀況,那麼Git就會把這個規則當成shell通配符規則來進行解析,是以帶FNM_PATHNAME標記的fnmatch(3)規則進行解析。可是,規則中的通配符不會匹配路徑名中的斜槓/。舉個栗子,Documentation/*.html匹配Documentation/git.html,但不會匹配Documentation/ppc/ppc.html或者tools/perf/Documentation/perf.html
  • 以斜槓開頭的通配符規則從路徑開頭開始匹配。好比,/*.c匹配cat-file.c,但不匹配mozilla-sha1/sha1.c

兩個連續的星號**在匹配全路徑名的時候可能有特殊含義:bash

  • 規則以兩個星號**開頭,後接一個斜槓,這樣的規則會在全部路徑或子路徑中嘗試進行匹配。好比,**/foo會匹配到文件foo或者目錄foo,不管它在哪一個目錄;foo這條規則一樣會嘗試匹配全部路徑中的文件foo或者目錄foo**/foo/bar規則會匹配任意文件或目錄foo下直接跟的文件bar或目錄bar
  • 若是規則中間有連續的兩個星號**,那這條規則會匹配下面的全部東西。好比abc/**會匹配目錄abc下的全部文件或目錄,固然,這裏的目錄abc是相對於.gitignore文件位置而言的,無限遞歸
  • 若是規則是斜槓/後跟兩個星號,而後再跟一個斜槓的形式,這裏的兩個星號就會匹配0+個目錄,這裏的0+是指能夠沒有,也能夠是多個。再舉個例子,好比a/**/b會匹配a/ba/x/ba/x/y/b這些
  • 其餘形式的連續星號都認爲是非法的

4. 筆記

gitignore文件的目的是確保某些不該該被Git追蹤的文件確實沒有被track。若是要中止track一個已經被Git追蹤的文件,請使用git rm --cached Xxx命令工具

5. 示例

$ git status
[...]
# 暫未被Git追蹤的文件:
[...]
# Documentation/foo.html
# Documentation/gitignore.html
# file.o
# lib.a
# src/internal.o
[...]
$ cat .git/info/exclude
# 忽略,即再也不追蹤倉庫中全部的objects和壓縮文件.
*.[oa]
$ cat Documentation/.gitignore
# 忽略自動生成的html文件,
*.html
# 排除手動維護的foo.html,即不忽略foo.html,即Git會追蹤foo.html
!foo.html
$ git status
[...]
# 暫未被Git追蹤的文件:
[...]
# Documentation/foo.html
[...]
複製代碼

一個例子不夠,再來一個:性能

$ cat .gitignore
vmlinux*
$ ls arch/foo/kernel/vm*
arch/foo/kernel/vmlinux.lds.S
$ echo '!/vmlinux*' > arch/foo/kernel/.gitignore
複製代碼

在這個例子中,第二個.gitignore文件arch/foo/kernel/.gitignore的優先級更高,它阻止了第一個.gitignore文件試圖忽略arch/foo/kernel/vmlinux.lds.S的行爲,從而,Git不會忽略arch/foo/kernel/vmlinux.lds.S,會嘗試追蹤它ui

最後再來一個例子收尾。舉個忽略目錄下全部文件或目錄,除了某個特定的目錄foo/bar的例子吧(注意下面的/*,就算沒有前面的斜槓,通配符也會匹配包括foo/bar在內的全部文件或目錄,因此斜槓/是無關緊要的):spa

$ cat .gitignore
# exclude everything except directory foo/bar
/*
!/foo
/foo/*
!/foo/bar
複製代碼

6. 補充示例

譯文到此完畢,我再補充幾個小例子吧命令行

6.1 示例一

6.2 示例二

6.3 示例三

相關文章
相關標籤/搜索