git忽略文件追蹤

  • 2020 年 1 月 23 日
  • 筆記

git忽略追蹤文件包括兩種,一種是未提交到git倉庫的文件,一種是已經提交到git倉庫中的文件。

一、忽略追蹤未提交到git倉庫的文件

    將忽略追蹤的文件路徑寫到倉庫根目錄下的.gitignore文件中即可

二、忽略追蹤已經提交到git倉庫中的文件

方案一、在每個clone下來的倉庫中手動設置不要檢查特定文件的更改情況

    git update-index –assume-unchanged filename

方案二、直接刪除對應文件的跟蹤(實際操作測試有些問題,不建議使用,詳見誤區說明)

    操作步驟如下:

    1、git rm –cached path/to/xxx.file

    2、更新 .gitignore 忽略掉目標文件

    3、git commit -m "We really don't want Git to track this anymore!"

    誤區說明:這種操作下,clone最新版的程式碼,將無法得到被rm –cached忽略的文件。

    解決方案如下:

1、複製出一份被忽略前的程式碼

cp -rv source.git tmp/

2、進入複製的程式碼庫中,恢復到忽略前的版本

cd tmp/source.git

git reset –hard e496b8b6d3851

3、將忽略的文件拷貝到當前倉庫中,不要覆蓋.git文件夾

cp -rv tmp/source.git/src/* source.git/src/  

4、保留忽略的文件,將其他文件更新至最新

附錄


方案一說明:

.gitignore只能忽略那些原來沒有被track的文件,如果某些文件已經被納入了版本管理中,則修改.gitignore是無效的。 正確的做法是在每個clone下來的倉庫中手動設置不要檢查特定文件的更改情況。

git update-index --assume-unchanged PATH    # 在PATH處輸入要忽略的文件。

另外 git 還提供了另一種 exclude 的方式來做同樣的事情,不同的是 .gitignore 這個文件本身會提交到版本庫中去。用來保存的是公共的需要排除的文件。而 .git/info/exclude 這裡設置的則是你自己本地需要排除的文件。 他不會影響到其他人。也不會提交到版本庫中去。

.gitignore 還有個有意思的小功能, 一個空的 .gitignore 文件 可以當作是一個 placeholder 。當你需要為項目創建一個空的 log 目錄時, 這就變的很有用。 你可以創建一個 log 目錄 在裡面放置一個空的 .gitignore 文件。這樣當你 clone 這個 repo 的時候 git 會自動的創建好一個空的 log 目錄了。


方案二說明:

具體的原因如下:

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

  1. 所有的團隊成員都必須對目標文件執行:git update-index --assume-unchanged <PATH>。這是因為即使你讓 Git 假裝看不見目標文件的改變,但文件本身還是在 Git 的歷史記錄里的,所以團隊的每個人在 fetch 的時候都會拉到目標文件的變更。(但實際上目標文件是根本不想被 Git 記錄的,而不是假裝看不見它發生了改變)
  2. 一旦有人改變目標文件之後沒有 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 暫時不會理睬你對文件做的修改;
  2. 當你的工作告一段落決定可以提交的時候,重置改標識:git update-index --no-assume-unchanged,於是 Git 只需要做一次更新,這是完全可以接受的了;
  3. 提交+推送。

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

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);
  2. 同樣的事情更應該用 .gitignore 文件來實現(針對未追蹤的文件)。

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

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

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

  1. 從 Git 的資料庫中刪除對於該文件的追蹤;
  2. 把對應的規則寫入 .gitignore,讓忽略真正生效;
  3. 提交+推送。

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

最後有一點需要注意的,git rm --cached 刪除的是追蹤狀態,而不是物理文件;如果你真的是徹底不想要了,你也可以直接 rm+忽略+提交。

參考地址:http://segmentfault.com/q/1010000000430426