2010-12-12 25 views
18

只是爲了好玩,我試圖將85GB的大部分-6MB左右的二進制文件放入git中。雖然Git在一段時間內一直處於困境,但總是在「緊急:令人不安的對象源數據迷惑」,然後是SHA1的消息的中途發生了一半的故障。你知道爲什麼嗎?有什麼方法可以解決它嗎?git說:「致命的:被不穩定的對象源數據困惑」

回答

19

要麼

  • 一個或多個文件被修改或
  • 東西導致不一致的讀取(例如硬件故障)。

簡短版本:Git的開發人員並不打算將它用於易失性文件。

由於佈局*該GIT中使用用於「鬆動物體」,並且它假定**有限文件系統語義,GIT中必須知道對象名稱的第一個字節(2個十六進制字符)(SHA- 1)一個新對象,然後才能開始存儲該對象。

* objects/[0-9a-f][0-9a-f]/目錄。見gitrepository-layout
** 具體來說,它需要能夠做「原子」文件重命名。某些文件系統(通常是網絡文件系統;我相信AFS)只有在重命名的源和目標位於同一目錄內時才能保證重命名原子性。

目前,Git在每個新的文件上執行兩次SHA-1傳遞。第一遍用於檢查Git是否已知道文件的內容(其對象存儲中是否已存在其SHA-1對象名稱)。如果對象已經存在,則不進行第二次傳遞。

對於新內容(對象不在對象存儲區中),在壓縮和計算正在壓縮的數據的SHA-1時再次讀取該文件。如果初始SHA-1(「已存儲?」檢查)與較晚的SHA-1(被壓縮和寫入的數據的散列)相匹配,則壓縮的數據被寫入臨時文件,該臨時文件僅被重命名爲其最終鬆散對象名稱。 。如果這些SHA-1哈希值不匹配,那麼Git會顯示您正在查看並中止的錯誤消息。這個錯誤檢查在748af44c63中添加,它首次在Git 1.7.0.2中發佈。

+0

很確定它不是不穩定的,但對於閱讀更多關於git內部的知識仍然非常有啓發性。我想我現在必須去確保我的磁盤沒有失效。 – jbfink 2010-12-12 22:43:49

+10

如果git表示「致命的:被不穩定的對象源數據困惑」,後面緊跟着一個SHA1,然後跟隨該文件,肯定會很好。很煩人,它不告訴你什麼文件是易失性的...如果它可以合理地將它或目錄添加到我的.gitignore – 2012-01-15 20:44:26

+4

那麼這是什麼解決方案? – 2013-01-24 06:51:34

3

兩種理論:當你正試圖把他們變成混帳

  • 東西被寫入這些文件。

  • 您有某種磁盤/內存故障導致數據損壞。

4

source,斑點的SHA1計算兩次:

  • write_sha1_file_prepare
  • write_loose_object

無論從write_sha1_file稱爲(有也是從force_object_loose的路徑,但它是用於重新包裝)。

第一個散列用於檢查對象是否已經知道(儘管git盡力讓文件系統保證文件未被修改,touch或者這樣會使它失去蹤跡);第二個是實際提供給zlib進行壓縮的數據的散列,然後寫入。

由於zlib的原因,第二個散列可能會更昂貴一些,這可能解釋了爲什麼要計算兩個散列(儘管這似乎是歷史事件,而且我猜測添加新對象時的性能成本有當檢測到虛假更改時,比CPU獲勝更具影響力)。有人可以添加一個回退,以便write_changed_sha1存在檢查邏輯重新與新的sha1一起使用,以便那些不穩定的文件也可以被添加。這對備份很有用,當添加的一些文件打開時。您的操作過程中

15

還有另一種可能性,即使是遙遠的。這將是一個非常大的文件(例如3GB或更多),git無法處理它。我們發現嘗試創建一個具有巨大文件的結構中的存儲庫的錯誤

+0

剛剛發生這種情況時,一些多GB的日誌文件,偷偷進入一個GIT工作樹。 – fche 2014-08-04 12:37:00

+0

大(但穩定)的文件肯定會導致此錯誤。錯誤信息具有誤導性,而且Git並沒有告訴你關於這個大小的事實,至少在目前Git是一個缺點。 我試過git-annex,一種看起來很有前途的處理大文件的方式,但到目前爲止還沒有能夠讓它在OS/X上運行。 – 2015-02-11 02:47:31

0

如果您嘗試git svn clone或git svn在btrfs文件系統上獲取存儲庫可能會發生這種情況,可能與內部競爭條件或原子性有關btrfs牛功能。

例子:

git svn --authors-file=authors.map clone http://svn.example.com/svn/repo repo 

cd repo; git svn --authors-file=../authors.map fetch 

我找到了一個解決方法通過設置你基地沒有工作目錄寫入時複製:

chattr +C . 

然後,你需要複製所有數據(例如):

cp -fr repo repo.new; rm -fr repo; mv -f repo.new repo 

cp authors.map authors.map.new; mv -f authors.map.new authors.map 

然後它不應該失敗(並且運行速度更快)。