如果希望某個檔案不要被 git 追蹤,共有兩種方式,一種是讓協作的所有成員都知道這個檔案不要被追蹤,就放在 .gitignore
;另一種是只在自己的本機端不要被追蹤,可放在 .git/info/exclude
(我們終於要來看 .git/info/
裡面的東西啦!)
本文將進行以下實驗,探討兩者差別:
簡單說明如下:
code/
有被 git 追蹤的檔案推到 GitHub。another_code/
;在 another_code/
新建剛剛沒被推上 GitHub、但 code/
有的檔案。another_code/
有被 git 追蹤的檔案推到 GitHub。code/
把當前 GitHub 上的檔案拉下來。透過這些實驗,我們將能感受到 .gitignore
與 .git/info/exclude
的差別。
先透過以下指令,在經過 git init
的 code/
資料夾中,準備兩個想被忽略的檔案。
echo "Ignore in .gitignore" > ignore_gitignore.txt
再來是想被 .git/info/exclude
忽略的檔案:
echo "Ignore in exclude" > ignore_exclude.txt
ignore_gitignore.txt
要被加進 .gitignore
中:
echo "ignore_gitignore.txt" > .gitignore
而 ignore_exclude.txt
則是要被放在 .git/info/exclude
中:
echo "ignore_exclude.txt" > .git/info/exclude
另外做一個沒有要被忽略的檔案為對照組:
echo "Normal" > normal.txt
這時整體資料夾結構長這樣:
code/
├── .git/
│ ├── hooks/
│ ├── info/
│ │ └── exclude # 內文含"ignore_exclude.txt"
│ └── ...
│
├── .gitignore # 內文為"ignore_gitignore.txt"
├── ignore_exclude.txt # 內文為"Ignore in exclude"
├── ignore_gitignore.txt # 內文為"Ignore in .gitignore"
└── normal.txt # 內文為"Normal"
現在透過以下指令,把 code/
所有檔案都加到預存區:
git add .
使用 git status 檢查,會發現 .gitignore
跟 normal.txt
被放到預存區、被 git 追蹤:
相較之下,被寫在 .git/info/exclude
的 ignore_exclude.txt
與被寫在 .gitignore
的 ignore_gitignore.txt
則沒有被追蹤。
後續再形成一個 commit:
git commit -m "Initial commit"
再輸入推到 GitHub:
git push -u <GitHub repo URL>
可發現只有 .gitignore
與 normal.txt
兩個剛剛在預存區的檔案有被推上去:
現在在另外一臺電腦(或者同一臺電腦 code/
以外的地方)把這個 GitHub 倉儲拉下來:
git clone <GitHub repo URL>
註:使用 git clone 會讓新目錄名稱與 GitHub 上的倉儲相同,為 Day19,但我在本機端改名為 another_code/。
這時在新電腦或新目錄中,結構如下:
another_code/ # 從Day19改名為another_code
├── .git/
│ ├── hooks/
│ ├── info/
│ │ └── exclude # 內文「不」含"ignore_exclude.txt"
│ └── ...
│
├── .gitignore # 內文為"ignore_gitignore.txt"
└── normal.txt # 內文為"Normal"
跟原本的目錄相比,主要有兩個差別:
.git/info/exclude
:不再有原本目錄寫在裡面的 ignore_exclude.txt
。.gitignore
,沒有被 git 追蹤的 ignore_exclude.txt
不在裡面。如果我們在 another_code/
中,手動加上被放在 .gitignore
的檔案:
echo "Ignore in .gitignore again" > ignore_gitignore.txt
另加上原目錄中被放在 .git/info/exclude
的檔案:
echo "Ignore in exclude again" > ignore_exclude.txt
如果這時候再把所有檔案加進預存區:
git add .
會發生什麼狀況呢?
ignore_exclude.txt
居然被加進去了!
如果再下 commit:
git commit -m "Add ignore_exclude.txt"
接著推上 GitHub:
git push -u <repo URL>
這時候觀察 GitHub 倉儲:
ignore_exclude.txt
被推上去了!綜合實驗二、三可發現:在 another_code/
裡,沒寫在 .gitignore
的 ignore_exclude.txt
是不會被忽略的。
那如果原目錄去 git pull
呢?
ignore_exclude.txt
有被拉下來,而且還蓋過了原目錄中 ignore_exclude.txt
的內容!
但如果在原目錄 code/
又改了這份 ignore_exclude.txt
檔案:
echo "hello" > ignore_exclude.txt
然後再把全部檔案加到預存區:
git add .
這份被寫在 .git/info/exclude
的檔案會被加進去嗎?
咦?怎麼有?趕緊來看看 code/
裡的 .git/info/exclude
到底是不是還有這份檔案?
居然有,可是怎麼會沒效呢?
這是因為不管是 .gitignore
或 .git/info/exclude
都只對「尚未被 git 追蹤的檔案」有效,當我們在原目錄 git pull
時,拉到的 ignore_exclude.txt
已經是被 git 追蹤的狀態,所以就算被寫在 .git/info/exclude
,也還是有被持續追蹤的。
在下一篇文章中,我們將以這兩者中較為常用的 .gitginore
為例,探討到底什麼樣的情況會讓檔案被 git 追蹤,以及被追蹤後,要如何讓其被退追蹤。
由上述的實驗,我們可以比較出:
.gitignore
中的檔案,經 git push
與 git clone/pull
到其他目錄後,同名檔案依然可保持不被 git 追蹤。.git/info/exclude
中的檔案,只在本機不會被 git 追蹤,經 git push
與 git clone/pull
到其他目錄後,這些同名檔案就會被追蹤。這兩者都只對「尚未被 git 追蹤」的檔案有效,因此,如果某檔案於本機中有被放在 .git/info/exclude
、但後來拉下來的 GitHub 倉儲也有同名檔案,表示該檔案已被 git 追蹤,拉到本機之後,即便 .git/info/exclude
仍寫著這檔案名稱,此檔案還是會繼續被追蹤。
同樣的道理在 .gitignore
也適用,我們將在下篇文章詳細探討。