2017-01-30 132 views
5

我需要克隆到現有的目錄($HOME,用於管理點文件)的git回購。我正在做一個裸克隆並重新配置它,因爲我需要克隆到現有的不乾淨的工作目錄。 它的工作原理,但是我發現git status試圖在第一次使用時運行過濾器。爲什麼要這樣做,我該如何預防它?爲什麼'git status'運行過濾器?

試試這個:

# create a test repo 
mkdir test && cd test 
git init 
echo hello > hello.txt 
git add . 
git commit -m 1 
echo 'hello.txt filter=foo diff=bar' > .gitattributes 
git add . 
git commit -m 2 

# clone it bare and configure it 
mkdir ../test2 && cd ../test2 
git clone --bare ../test .git 
git config core.bare false 
git config core.logallrefupdates true 
git reset 
git checkout . 
git config filter.foo.clean foo 
git config filter.foo.smudge foo 
git config diff.bar.textconv bar 

這borks

$ git status 
error: cannot run foo: No such file or directory 
error: cannot fork to run external filter 'foo' 
error: external filter 'foo' failed 
On branch master 
nothing to commit, working tree clean 

這不

$ git status 
On branch master 
nothing to commit, working tree clean 

而且,最初做git status多次快速連續(即git status; git status; git status)可以產生多個失敗,有時候,

據我所知,可以通過much reading進行確認,只有在檢查輸入和輸出文件時,過濾器纔會運行。

那麼爲什麼git status運行它們?

+0

你的'git --version'是什麼? –

+0

git版本2.11.0 – starfry

+0

順便說一句,我不會(也不要)以這種方式管理點文件。相反,我的主目錄中有一個名爲'Dotfiles'的Git目錄,它是一個普通的非裸樹,然後將'.whatever'符號鏈接到''Dotfiles/whatever'。 – torek

回答

2

僅在簽入/簽出期間運行過濾器的想法是white lie。這意味着要使過濾器更易於解釋。

事實上,雖然過濾索引和工作樹之間移動文件時運行(也,Git中充分現代版本,當與git show--path=選項和git cat-filegit hash-object以及要求:其中有些是直接從存儲庫轉換爲stdout,或者stdin轉換爲存儲庫)。這是主要是相當於簽入/結帳時間。但由於索引的緩存方面,git status也具有特殊功能。

出於性能原因,Git想知道工作樹中的任何文件是否可能與索引中的版本「髒」。 Git的假設stat價值st_mtime,通常具有一秒的分辨率,可以用於此目的:如果st_mtime時間文件的-the工作樹入門比保存st_mtime年長在索引條目中,那麼索引條目是最新的並且是「乾淨的」:索引中的內容與工作樹中的內容匹配,在應用乾淨的過濾器之後等。

如果工作樹的時間戳條目是,比保存的索引條目更新,那麼文件肯定已被修改:索引條目可能是過時了。這不是保證已過時,因爲工作樹文件可能已被修改,最終沒有改變。但顯然需要運行清潔過濾器(以及任何結束hackery的CR/LF行)。

如果兩個時間戳是相同的,工作樹條目是不確定的。 (Git稱之爲「racily clean」,雖然「racily dirty」同樣準確。)

在所有這些情況下,git status將在工作樹文件上運行clean filter(以及任何input-to-Git direction CR/LF修改)以計算新的散列值。如果新散列與索引散列匹配,Git可以並且將更新索引條目以將文件標記爲「實際上乾淨」。現在,當你下一次做某件事時,Git不必運行乾淨的過濾器。

除非,即在st_mtime stat字段的分辨率範圍內完成所有操作。在這種情況下,索引條目會變得「很乾淨」,Git必須再試一次。這是你在這裏觀察的內容。

(注意,順便說一句,那git status運行來進行比較:一個從HEAD索引,一個來自索引工作樹就這麼從索引緩存方面獲得巨大的好處第二差異的。指數現在還可以存儲關於未緩存文件和目錄,太!)


一些stat電話給亞秒級的精度,但由於種種原因,該指數/緩存項只存儲1無論如何,第二分辨率時間戳n ormally。

有關(更多)更多信息,請參見the racy-git.txt file in the technical documentation

+0

很好的解釋!它也解釋了爲什麼'touch hello.txt'使'git status'運行過濾器。它解釋了爲什麼如果文件時間戳更改和狀態檢查之間的時間太短(<1s),它們又會重新運行。給出這個解釋,我會假設沒有辦法阻止過濾器運行(在我的情況下,過濾器將失敗,直到提供加密密鑰)。在這種情況下,我的解決方案是'sleep 1 && git status&>/dev/null'是我希望的最好的...? – starfry

+0

該解決方法應該可行。不過,我不知道爲什麼要加密這些東西。 – torek

+0

私鑰,API密鑰等。我只在每個文件的基礎上隱藏敏感的東西。 – starfry