天天看點

解決.gitignore不起作用的辦法

作者:有AI野心的電工和碼農
本文是15年時網上搜集來的2篇的合集,加上了一點自己的了解。
第一篇segmentfault回答中,對git update-index --assume-unchanged的詳解,看似有點跑題但很有價值!

第一篇

Original address:http://segmentfault.com/q/1010000000430426

Q:

現在項目的根目錄放了.gitignore檔案,并且git遠端倉庫的項目根目錄已經有了logs檔案夾。

由于每次本地運作項目,都會生成新的log檔案,但是我并不想送出logs檔案夾裡面的内容,是以要在.gitignore寫logs的規則。

我嘗試過添加以下規則

logs/*.log

logs/

/logs/

但是運作git status的時候,始終能看到modified:logs/xx.log 。

請問是我的規則編寫錯誤,還是我某個地方有了解錯誤?

A:

正确的做法應該是:

  1. git rm --cached logs/xx.log,
  1. 然後更新.gitignore忽略掉目标檔案,
  1. 最後git commit -m "We really don't want Git to track this anymore!"

具體的原因如下:

被采納的答案雖然能達到(暫時的)目的,但并非最正确的做法,這樣做是誤解了git update-index的含義,而且這樣做帶來的最直接(不良)後果是這樣的:

  1. 所有的團隊成員都必須對目标檔案執行:git update-index --assume-unchanged <PATH>。這是因為即使你讓 Git 假裝看不見目标檔案的改變,但檔案本身還是在 Git 的曆史記錄裡的,是以團隊的每個人在 fetch 的時候都會拉到目标檔案的變更。(但實際上目标檔案是根本不想被 Git 記錄的,而不是假裝看不見它發生了改變)
  1. 一旦有人改變目标檔案之後沒有git update-index --assume-unchanged <PATH>就直接push了,那麼接下來所有拉取了最新代碼的成員必須重新執行update-index,否則 Git 又會開始記錄目标檔案的變化。這一點實際上很常見的,比如說某成員換了機器或者硬碟,重新clone了一份代碼庫,由于目标檔案還在 Git 的曆史記錄裡,是以他/她很可能會忘記update-index。

為什麼會這樣?答案就在 Git 的man pages裡:

首先,git update-index的定義是:

Register file contents in the working tree to the index(把工作區下的檔案内容注冊到索引區)

這句話暗含的意思是:update-index針對的是 Git 資料庫裡被記錄的檔案,而不是那些需要忽略的檔案。

接着看關于--assume-unchanged的幾句相關的描述:

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).

大緻意思是:

應用了該辨別之後,Git 停止檢視工作區檔案可能發生的改變,是以你必須手動重置該辨別以便 Git 知道你想要恢複對檔案改變的追蹤。當你工作在一個大型項目中,這在檔案系統的lstat系統調用非常遲鈍的時候會很有用。

我們知道 Git 不僅僅是用來做代碼版本管理的,很多其他領域的項目也會使用 Git。比如說我公司曾經一個客戶的項目涉及到精密零件圖紙文檔的版本管理,他們也用 Git。有一種使用場景是對一些體積龐大的檔案進行修改,但是每一次儲存 Git 都要計算檔案的變化并更新工作區,這在硬碟慢的時候延遲卡頓非常明顯。

git update-index --assume-unchanged的真正用法是這樣的:

  1. 你正在修改一個巨大的檔案,你先對其 git update-index --assume-unchanged,這樣 Git 暫時不會理睬你對檔案做的修改;
  1. 當你的工作告一段落決定可以送出的時候,重置改辨別:git update-index --no-assume-unchanged,于是 Git 隻需要做一次更新,這是完全可以接受的了;
  1. 送出+推送。

另外,根據文檔的進一步描述:

This option can be also used as a coarse file-level mechanism to ignore uncommitted changes in tracked files (akin to what .gitignore does for untracked files).

這段描述告訴我們兩個事實:

  1. 雖然可以用其來達成樓主想要的結果,但這是不講究的做法(coarse);
  1. 同樣的事情更應該用.gitignore檔案來實作(針對未追蹤的檔案)。

随之而來的問題是:為什麼我增加了.gitignore裡的規則卻沒有效果?

這是因為我們誤解了.gitignore檔案的用途,該檔案隻能作用于Untracked Files,也就是那些從來沒有被 Git 記錄過的檔案(自添加以後,從未 add 及 commit 過的檔案)。

之是以你的規則不生效,是因為那些 .log 檔案曾經被 Git 記錄過,是以.gitignore對它們完全無效。這也正是開頭那段簡短答案所做的事情:

  1. 從 Git 的資料庫中删除對于該檔案的追蹤;
  1. 把對應的規則寫入.gitignore,讓忽略真正生效;
  1. 送出+推送。

隻有這樣做,所有的團隊成員才會保持一緻而不會有後遺症,也隻有這樣做,其他的團隊成員根本不需要做額外的工作來維持對一個檔案的改變忽略。

最後有一點需要注意的,git rm --cached删除的是追蹤狀态,而不是實體檔案;如果你真的是徹底不想要了,你也可以直接rm+忽略+送出

My的了解:在添加 .gitignore 檔案之前,已經track的檔案,是不可能再被ignore的了,隻有從git的資料庫中删除掉 欲被忽略的檔案 的追蹤,才可讓.gitignore檔案中的配置生效。

第二篇 關于使用Github,gitignore不起作用的解決方法

Original address: http://niltor.net/index.php/Home/Blog/showblog?id=5
點評: 這是一種比較簡單直接粗暴的作法,從git庫中删除目錄下所有檔案的記錄,再重新add。

NilTor @ 2014-08-08 16:50:55 | 最後編輯:2014-08-08 16:50:55

摘要: 前段時間gitignore檔案不起作用的問題讓我很頭疼,我需要在不同的電腦上,不同的作業系統中同步代碼.必須會忽略一些檔案的.經過搜尋,終于找到了解決的辦法.

直接上解決方法:

git rm -r --cached .
git add .
git commit -m 'update .gitignore'           

解釋:

.gitignore檔案,具體的規則一搜就有.

我在使用GIT的過程中,明明寫好了規則,但問題不起作用,每次還是重複送出,無法忍受.

其實這個檔案裡的規則對已經追蹤的檔案是沒有效果的.

是以我們需要使用rm指令清除一下相關的緩存内容. 這樣檔案将以未追蹤的形式出現.

然後再重新添加送出一下, .gitignore檔案裡的規則就可以起作用了.

繼續閱讀