正確的做法應(yīng)該是:git rm --cached logs/xx.log,然后更新.gitignore忽略掉目標(biāo)文件,最后git commit -m "We really don't want Git to track this anymore!"
具體的原因如下:
被采納的答案雖然能達(dá)到(暫時的)目的,但并非最正確的做法,這樣做是誤解了git update-index的含義,而且這樣做帶來的最直接(不良)后果是這樣的:
所有的團(tuán)隊(duì)成員都必須對目標(biāo)文件執(zhí)行:git update-index --assume-unchanged 。這是因?yàn)榧词鼓阕?Git 假裝看不見目標(biāo)文件的改變,但文件本身還是在 Git 的歷史記錄里的,所以團(tuán)隊(duì)的每個人在fetch的時候都會拉到目標(biāo)文件的變更。(但實(shí)際上目標(biāo)文件是根本不想被 Git 記錄的,而不是假裝看不見它發(fā)生了改變)
一旦有人改變目標(biāo)文件之后沒有g(shù)it update-index --assume-unchanged 就直接push了,那么接下來所有拉取了最新代碼的成員必須重新執(zhí)行update-index,否則 Git 又會開始記錄目標(biāo)文件的變化。這一點(diǎn)實(shí)際上很常見的,比如說某成員換了機(jī)器或者硬盤,重新clone了一份代碼庫,由于目標(biāo)文件還在 Git 的歷史記錄里,所以他/她很可能會忘記update-index。
為什么會這樣?答案就在 Git 的man pages里:
首先,git update-index的定義是:
Register file contents in the working tree to the index(把工作區(qū)下的文件內(nèi)容注冊到索引區(qū))
這句話暗含的意思是:update-index針對的是 Git 數(shù)據(jù)庫里被記錄的文件,而不是那些需要忽略的文件。
接著看關(guān)于--assume-unchanged的幾句相關(guān)的描述:
When the "assume unchanged" bit is on, Git stops checking the working tree files for possible modifications, so you need to manually unset the bit to tell Git when you change the working tree file. This is sometimes helpful when working with a big project on a filesystem that has very slow lstat(2) system call (e.g. cifs).
大致意思是:
應(yīng)用了該標(biāo)識之后,Git 停止查看工作區(qū)文件可能發(fā)生的改變,所以你必須手動重置該標(biāo)識以便 Git 知道你想要恢復(fù)對文件改變的追蹤。當(dāng)你工作在一個大型項(xiàng)目中,這在文件系統(tǒng)的lstat系統(tǒng)調(diào)用非常遲鈍的時候會很有用。
我們知道 Git 不僅僅是用來做代碼版本管理的,很多其他領(lǐng)域的項(xiàng)目也會使用 Git。比如說我公司曾經(jīng)一個客戶的項(xiàng)目涉及到精密零件圖紙文檔的版本管理,他們也用 Git。有一種使用場景是對一些體積龐大的文件進(jìn)行修改,但是每一次保存 Git 都要計(jì)算文件的變化并更新工作區(qū),這在硬盤慢的時候延遲卡頓非常明顯。
git update-index --assume-unchanged的真正用法是這樣的:
你正在修改一個巨大的文件,你先對其git update-index --assume-unchanged,這樣 Git 暫時不會理睬你對文件做的修改;
當(dāng)你的工作告一段落決定可以提交的時候,重置改標(biāo)識:git update-index --no-assume-unchanged,于是 Git 只需要做一次更新,這是完全可以接受的了;
提交+推送。
另外,根據(jù)文檔的進(jìn)一步描述:
This option can be also used as acoarsefile-level mechanism to ignore uncommitted changes in tracked files (akin to what .gitignore does foruntracked files).
這段描述告訴我們兩個事實(shí):
雖然可以用其來達(dá)成樓主想要的結(jié)果,但這是不講究的做法(coarse);
同樣的事情更應(yīng)該用.gitignore文件來實(shí)現(xiàn)(針對未追蹤的文件)。
隨之而來的問題是:為什么我增加了.gitignore里的規(guī)則卻沒有效果?
這是因?yàn)槲覀冋`解了.gitignore文件的用途,該文件只能作用于Untracked Files,也就是那些從來沒有被 Git 記錄過的文件(自添加以后,從未 add 及 commit 過的文件)。
之所以你的規(guī)則不生效,是因?yàn)槟切?log文件曾經(jīng)被 Git 記錄過,因此.gitignore對它們完全無效。這也正是開頭那段簡短答案所做的事情:
從 Git 的數(shù)據(jù)庫中刪除對于該文件的追蹤;
把對應(yīng)的規(guī)則寫入.gitignore,讓忽略真正生效;
提交+推送。
只有這樣做,所有的團(tuán)隊(duì)成員才會保持一致而不會有后遺癥,也只有這樣做,其他的團(tuán)隊(duì)成員根本不需要做額外的工作來維持對一個文件的改變忽略。
最后有一點(diǎn)需要注意的,git rm --cached刪除的是追蹤狀態(tài),而不是物理文件;如果你真的是徹底不想要了,你也可以直接rm+忽略+提交。