Git 內部結構:體系結構和索引文件

2021-02-23 微軟中國MSDN

我曾介紹過 Git 如何使用有向無環圖 (DAG) 來組織存儲庫的提交對象。此外,我還研究過提交對象可以指代的 blob、樹和標記對象。在這篇文章的最後,我還介紹了分支,包括 HEAD 和 head 的區別。閱讀本文前必須先閱讀這篇文章,因為本文將介紹 Git「三樹」體系結構及其索引文件的重要性。進一步了解這些 Git 內部結構將有助於積累基礎知識,提高 Git 用戶的工作效率,並有助於用戶在研究各種基於 Visual Studio IDE 圖形 Git 工具的 Git 操作時獲取新見解。

回顧一下,之前有介紹過,Visual Studio 使用 Git API 與 Git 進行通信,以及 Visual Studio IDE Git 工具簡化並取代了基礎 Git 引擎的功能。對於要實現版本控制工作流而不依賴 Git 命令行接口 (CLI) 的開發者來說,這是一大福音。哎,但 IDE 的實用 Git 抽象有時可能會引起混亂。以下面的基本工作流為例:將項目添加到 Git 源控制項,修改並暫存項目文件,再提交暫存文件。為此,需要打開「團隊資源管理器 - 更改」窗格來查看更改後文件列表,再選擇要暫存的文件。請注意圖 1 中的最左側圖像,其中顯示了我在工作目錄中更改的兩個文件(標記 1)。

圖 1:「團隊資源管理器 - 更改」窗格可以在「更改」和「暫存更改」部分中顯示相同的文件

在下一張靠右的圖像中,我暫存了其中一個更改後文件:Program.cs(標記 2)。當我這樣做時,Program.cs 似乎已從「更改」列表中「移動」到了「暫存更改」列表中。如果我進一步修改,並在工作目錄中保存 Program.cs 副本,那麼此文件會繼續出現在「暫存更改」部分中(標記 3),但同時也會出現在「更改」部分中(標記 4)! 如果不了解 Git 的幕後運行機制,可能會感到困惑,解疑釋惑的關鍵在於有兩個 Program.cs「副本」:一個位於工作文件夾中,另一個位於對象的 Git 內部資料庫中。即使發現這一點,可能也無法知道在取消暫存副本、嘗試暫存 Program.cs 的第二個更改副本、撤消對工作副本的更改或切換分支時會發生些什麼。

若要真正了解 Git 在暫存、取消暫存、撤消、提交和籤出文件時所做的工作,必須先了解 Git 的體系結構。


Git 實現的是三樹體系結構(在此上下文中,「樹」指的是目錄結構和文件)。在圖 2(Git 三樹體系結構利用非常重要的索引文件實現智能化和高效性能)中從左向右看,第一棵樹是工作目錄(包含隱藏 .git 文件夾的 OS 目錄)中的文件和文件夾集合;第二棵樹通常存儲在.git 文件夾根目錄中一個名為 index 的二進位文件中;第三棵樹由代表 DAG 的 Git 對象組成(回顧一下,名為 SHA-1 的 Git 對象位於 .git\objects 中用兩個十六進位數命名的文件夾內,也可以存儲在 .git\objects\pack 的「包」文件中,以及 .git\objects\info\alternates 文件定義的文件路徑中)。請注意,Git 存儲庫是由 .git 文件夾中的所有文件進行定義。人們通常將 DAG 稱為「Git 存儲庫」,但這並不太準確:因為索引和 DAG 都包含在 Git 存儲庫中。

圖 2:Git 三樹體系結構利用非常重要的索引文件實現智能化和高效性能

請注意,雖然每顆樹都存儲目錄結構和文件,但它們利用的數據結構不同,以便可以保留樹專屬元數據,並優化存儲和檢索。第一棵樹(工作目錄樹,也稱為「工作樹」)顯然是 OS 文件和文件夾(除了 OS 級數據結構外,沒有其他任何特殊數據結構),滿足軟體開發者和 Visual Studio 的需求;第二顆樹(Git 索引)跨越工作目錄和組成 DAG 的提交對象,從而幫助 Git 快速執行工作目錄文件內容比較和快速提交;第三棵樹 (DAG) 讓 Git 能夠跟蹤可靠歷史版本控制系統,同時 Git 還能向其存儲在索引和提交對象中的項添加有用的元數據。例如,在索引中存儲的元數據有助於檢測工作目錄中的文件更改,而在提交對象中存儲的元數據則有助於跟蹤提交籤發者和籤發原因。

本段內容是為了回顧三樹體系結構中的三棵樹,並引出本文剩餘部分重點介紹的主題:已了解工作目錄樹的運行方式,因為實際上就是已精通使用的 OS 文件系統。如果閱讀過我的上一篇文章,應該已非常了解 DAG 的運行方式。那麼,此時,缺少的環節就是跨工作目錄和 DAG 的索引樹(下稱「索引」)。實際上,索引的作用非常重要,將是本文剩餘部分的唯一主題。


可能已聽說過下面善意的意見:索引是「暫存區域」的代名詞。 雖然這樣的表述多少有些準確,但卻掩蓋了索引的真正作用:不僅支持暫存區域,還便於 Git 檢測工作目錄中的文件更改;協調分支合併過程,以便能夠逐個文件解決衝突,並能隨時安全地中止合併;將暫存文件和文件夾轉換為樹對象,這些對象的引用會被寫入下一個提交對象。Git 還使用索引來保留工作樹中文件的相關信息,以及從 DAG 中檢索到的對象的相關信息,從而進一步將索引用作一種緩存。我們將更為全面地研究一下索引。

索引實現自己的獨立式文件系統,從而能夠存儲對文件夾和文件的引用,以及關於文件夾和文件的元數據。Git 如何以及何時更新此索引取決於所發出的 Git 命令類型和指定的命令選項(若要試一試,可以使用 Git 更新索引底層命令來自行管理索引),因此這裡無法詳盡無遺地進行介紹。不過,使用 Visual Studio Git 工具時,不妨留意一下 Git 更新索引以及使用索引中存儲信息的主要方式。圖 3 展示了 Git 如何在用戶暫存文件時在索引中更新工作目錄數據,以及如何在用戶啟動合併(若有合併衝突)、執行克隆/拉取或切換分支時在索引中更新 DAG 數據。另一方面,Git 依賴索引中存儲的信息,在用戶籤發提交後更新 DAG,並在用戶執行克隆/拉取或切換分支後更新工作目錄。意識到 Git 依賴索引,並且索引跨越多個 Git 操作後,便會開始重視用於修改索引的高級 Git 命令,從而能夠有效地巧妙處理 Git 操作。

圖 3:更新索引的主要 Git 操作(綠色)和依賴索引所含信息的 Git 操作(紅色)

我們將在工作目錄中新建一個文件,看看此文件被寫入索引時會發生些什麼。在用戶暫存此文件後,Git 會立即使用以下字符串串聯公式創建標頭:

blob{space}{file-length in bytes}{null-termination character}

然後,Git 將標頭串聯到文件內容開頭。因此,對於包含字符串「Hello」的文本文件,將標頭與文件內容串聯後生成如下字符串(請注意,字母「H」前面有一個空字符):

blob 5Hello

為了更加明確化,下面展示了此字符串的十六進位版本:

62 6C 6F 62 20 35 00 48 65 6C 6C 6F

然後,Git 計算此字符串的 SHA-1:

5ab2f8a4323abafb10abb68657d9d39f1a775057

接下來,Git 檢查現有索引,以確定此文件夾\文件名的條目是否已存在且包含相同的 SHA-1。如果有,Git 會在 .git\objects 文件夾中找到此 blob 對象,並更新它的修改日期時間(Git 絕不會覆蓋存儲庫中的現有對象;而是更新上次修改日期,以便延遲這一新添加的對象被視為垃圾遭到回收的時間)。如果沒有,Git 會使用 SHA-1 字符串的前兩個字符作為 .git\objects 中的目錄名稱,並使用剩下的 38 個字符命名 blob 文件,再對此文件進行 zlib 壓縮並編寫其內容。在我的示例中,Git 會在 .git\objects 中創建名為 5a 的文件夾,再將 blob 對象作為文件 b2f8a4323abafb10abb68657d9d39f1a775057 寫入此文件夾。

當 Git 以這種方式創建 blob 對象時,大家可能會感到驚訝,因為 blob 對象中明顯缺少一個預期的文件屬性:文件名! 然而,這是有意而為之。回顧一下,Git 是內容可尋址文件系統,因此它管理的是名為 SHA-1 的 blob 對象,而不是文件。每個 blob 對象通常是由至少一個樹對象引用,反過來樹對象通常是由提交對象引用。最終,Git 樹對象表示暫存的文件的文件夾結構。不過,在用戶籤發提交之前,Git 不會創建這些樹對象。因此,可以得出下列結論:如果 Git 僅使用索引來準備提交對象,還必須為索引中的每個 blob 捕獲文件路徑引用,而它正是這樣做的。其實,即使兩個 blob 的 SHA-1 值相同,只要每個映射到不同的文件名或不同的路徑/文件值,都將顯示為索引中的單獨條目。

Git 還將文件元數據(如文件的創建日期和修改日期)與寫入索引的每個 blob 對象一起保存。Git 利用此類信息通過比較文件日期和使用啟發,有效地檢測工作目錄中的文件更改,而不是採用重新計算工作目錄中每個文件的 SHA-1 值這種蠻力做法。此類策略可以加快「團隊資源管理器 - 更改」窗格中顯示信息的速度,或發出高層 Git 狀態命令後顯示信息的速度。

有了工作目錄文件對應的索引條目及其相關元數據後,Git 據說就可以「跟蹤」文件了,因為它可以很容易地將文件副本與工作目錄中保留的副本進行比較。從技術角度來講,被跟蹤的文件也存在於工作目錄中,並包含在下一次提交中。這與未受跟蹤的文件相反,未受跟蹤的文件分為以下兩種類型:位於工作目錄中但不位於索引中的文件,以及顯式指定為不受跟蹤的文件(見「索引擴展」部分)。總而言之,藉助索引,Git 可以確定跟蹤、不跟蹤以及不得跟蹤哪些文件。

為了更好地理解索引的具體內容,讓我們來看看一個具體示例,從新的 Visual Studio 項目入手。此項目是否複雜並不太重要,只需幾個文件就可以充分說明正在發生什麼。新建名為 MSDNConsoleApp 的控制臺應用程式,並選中「創建解決方案的目錄」和「新建 Git 存儲庫」複選框。單擊「確定」,創建解決方案。

稍後我將發出一些 Git 命令。因此,若要在系統上運行這些命令,請在工作目錄中打開命令提示符窗口,並確保可以在繼續操作時使用此窗口。一種為特定 Git 存儲庫快速打開 Git 命令窗口的方法是,訪問「Visual Studio Team」菜單,並選擇「管理連接」。此時,將看到本地 Git 存儲庫列表,以及相應存儲庫的工作目錄路徑。右鍵單擊存儲庫名稱,並選擇「打開命令提示符」,以啟動可用於輸入 Git CLI 命令的窗口。

創建解決方案後,立即打開「團隊資源管理器 - 分支」窗格(圖 4 中的標記 1),以確定 Git 是否創建了名為「主分支」的默認分支(標記 2)。右鍵單擊「主分支」(標記 2),並選擇「查看歷史記錄」(標記 3),以查看 Visual Studio 代表用戶創建的兩個提交對象(標記 4)。第一個對象包含提交消息「添加 .gitignore 和 .gitattributes」;第二個對象包含提交消息「添加項目文件」。

圖 4:查看歷史記錄以確定 Visual Studio 在用戶新建項目時所做的工作

打開「團隊資源管理器 - 更改」窗格。Visual Studio 依賴 Git API 在此窗口中填充項,因為它是 Visual Studio 版 Git 狀態命令。當前,此窗口指明工作目錄中沒有取消暫存的更改。為了做出此決定,Git 將每個索引條目與各個工作目錄文件進行比較。有了索引的文件條目和相關的文件元數據後,Git 就有了所需的全部信息,可以確定用戶是否進行了任何更改、添加、刪除,或是否重命名了工作目錄中的任何文件(不包括 .gitignore 文件中提到的任何文件)。

因此,在方便 Git 智能化確定工作目錄樹與 HEAD 指向的提交對象的差異方面,索引起到了關鍵作用。若要詳細了解索引提供給 Git 引擎的信息種類,請轉到前面打開的命令行窗口,並發出以下底層命令:

git ls-files --stage

可以隨時發出此命令,從而生成索引中當前包含的文件的完整列表。在我的系統上,此命令的輸出如下:

100644 1ff0c423042b46cb1d617b81efb715defbe8054d 0       .gitattributes100644 3c4efe206bd0e7230ad0ae8396a3c883c8207906 0       .gitignore100644 f18cc2fac0bc0e4aa9c5e8655ed63fa33563ab1d 0       MSDNConsoleApp.sln100644 88fa4027bda397de6bf19f0940e5dd6026c877f9 0       MSDNConsoleApp/App.config100644 d837dc8996b727d6f6d2c4e788dc9857b840148a 0       MSDNConsoleApp/MSDNConsoleApp.csproj100644 27e0d58c613432852eab6b9e693d67e5c6d7aba7 0       MSDNConsoleApp/Program.cs100644 785cfad3244d5e16842f4cf8313c8a75e64adc38 0       MSDNConsoleApp/Properties/AssemblyInfo.cs

輸出的第一列是八進位的 Unix OS 文件模式。不過,Git 並不支持全部文件模式值。可能只會看到 100644(對於非 EXE 文件)和 100755(對於基於 Unix 的 EXE 文件,適用於 Windows 的 Git 也對可執行文件類型使用 100644)。第二列是文件的 SHA-1 值。第三列是文件的合併暫存值,0 表示沒有衝突,1、2 或 3 表示有合併衝突。最後,請注意,七個 blob 對象的路徑和文件名全都存儲在索引中。Git 使用路徑值在下一次提交之前生成樹對象(稍後將詳細介紹)。

現在,讓我們來研究一下索引文件本身。由於它是二進位文件,因此我將使用 HexEdit 4(hexedit.com 提供的免費軟體十六進位編輯器)查看文件內容(圖 5 摘錄了部分內容)。

圖 5:項目的 Git 索引文件的十六進位轉儲

圖 6:Git 索引標頭數據格式

索引文件 - 標頭條目00 - 03
(4 字節)DIRC用於目錄緩存條目的固定標頭。
所有索引文件的開頭都是此條目。04 - 07
(4 字節)Version索引版本號(適用於 Windows 的 Git 
當前使用版本 2)。08 - 11
(4 字節)條目數作為 4 字節的值,索引最多支持 
4,294,967,296 個條目!


索引的前 12 個字節包含標頭(見圖 6)。前 4 個字節始終包含字符 DIRC(「目錄緩存」的縮寫),這是 Git 索引通常被稱為「緩存」的原因之一。接下來的 4 個字節包含索引版本號,默認為版本 2,除非要使用 Git 的特定功能(如稀疏籤出)。在這種情況下,可以設置為版本 3 或 4。最後 4 個字節包含索引進一步包含的文件條目數。

12 字節標頭後面是 n 個索引項的列表,其中 n 與索引標頭描述的條目數一致。圖 7 展示了每個索引條目的格式。Git 根據路徑/文件名欄位按升序排列索引條目。

圖 7:Git 索引文件 - 索引條目數據格式

索引文件 - 索引條目4 字節32 位創建時間(以秒為單位)與 1970 年 1 月 1 日 00:00:00 之間相隔的秒數。4 字節32 位創建時間 - 納秒組成部分創建時間的納秒組成部分(以秒為單位)。4 字節32 位修改時間(以秒為單位)與 1970 年 1 月 1 日 00:00:00 之間相隔的秒數。4 字節32 位修改時間 - 納秒組成部分修改時間的納秒組成部分(以秒為單位)。4 字節設備與文件相關的元數據,源自 Unix OS 上使用的文件屬性。4 字節Inode4 字節mode4 字節用戶 ID4 字節組 ID4 字節文件內容長度文件內容字節數。20 字節SHA-1相應 blob 對象的 SHA-1 值。2 個字節標記(從高到低位)1 位:假設有效/假設未更改標誌;1 位:擴展標誌(如果版本低於 3,必須為 0;如果為 1,在路徑\文件名前面附加 2 個字節);2 位:合併暫存;12 位:路徑\文件名長度(如果小於 0xFFF)2 個字節 
(版本 3 
或更高版本)
標記(從高到低位)
1 位:日後使用
1 位:跳過工作樹標誌(稀疏籤出)
1 位:有意添加標誌 (git add -N)
13 位:未使用,必須為零長度不固定路徑/文件名以空字符結尾


第一個 8 字節表示文件創建時間(與 1970 年 1 月 1 日 00:00:00 之間相隔的秒數)。第二個 8 字節表示文件修改時間(與 1970 年 1 月 1 日 00:00:00 之間相隔的秒數)。接下來是五個與主機 OS 相關的文件屬性元數據的 4 字節值(設備、inode、模式、用戶 ID 和組 ID)。唯一僅限 Windows 的值是模式,值通常是八進位的 100644,我在前面介紹 ls-files 命令輸出時提到過(這會轉換為 4 字節 814AH 值,如圖 5 中的 26H 位置所示)。

元數據後面是 4 字節的文件內容長度。在圖 5 中,此值從 030 行的 00 00 0A 15(十進位為 2,581)開始,我的系統上的 .gitattributes 文件長度為:

05/08/2017  09:24 PM    <DIR>          .05/08/2017  09:24 PM    <DIR>          ..05/08/2017  09:24 PM             2,581 .gitattributes05/08/2017  09:24 PM             4,565 .gitignore05/08/2017  09:24 PM    <DIR>          MSDNConsoleApp05/08/2017  09:24 PM             1,009 MSDNConsoleApp.sln               3 File(s)          8,155 bytes               3 Dir(s)  92,069,982,208 bytes free

偏移 034H 是 blob 對象的 20 字節 SHA-1 值:

1ff0c423042b46cb1d617b81efb715defbe8054d.

請注意,此 SHA-1 指向 blob 對象,其中包含相關文件 (.gitattributes) 的文件內容。

048H 是 2 字節值,包含兩個 1 位標誌、2 位合併暫存值,以及當前索引條目的路徑/文件名的 12 位長度。在這兩個 1 位標誌中,高位指定索引條目是否設置了假設未更改標誌(通常使用 Git 更新索引底層命令完成);低位指定是否在路徑\文件名條目之前附加兩字節的數據(只有當索引版本不小於 3 時,此位才會是 1)。接下來的 2 位保留介於 0 到 3 之間的合併暫存值,如前所述。12 位值包含路徑\文件名字符串的長度。

如果設置了擴展標誌,那麼 2 字節值包含跳過工作樹標誌和有意添加位標誌,以及填充佔位符。

最後,長度不固定的字節序列包含路徑\文件名。此值以一個或多個空字符結尾。空字符結尾後面是索引中的下一個 blob 對象,或一個或多個索引擴展條目(我很快將會介紹)。

我在前面提到過,在用戶提交暫存內容前,Git 不會生成樹對象。也就是說,索引最初只包含路徑/文件名,以及對 blob 對象的引用。不過,只要用戶籤發提交,Git 就會將索引更新為包含對在上次提交期間創建的樹對象的引用。如果在下一次提交期間這些目錄引用仍位於工作目錄中,那麼可以使用緩存的樹對象引用,以減少 Git 需要在下一次提交期間完成的工作量。可以看到,索引的作用涉及許多方面,正因為此,它被描述為索引、暫存區域和緩存。

圖 7 展示的索引條目只支持 blob 對象引用。Git 使用擴展,以便可以存儲樹對象。


索引可以包含擴展條目,這些條目存儲特殊化數據流,為 Git 引擎提供其他信息,以供它在監視工作目錄中的文件和準備下一次提交時參考。為了緩存在上次提交期間創建的樹對象,Git 將樹擴展對象添加到工作目錄的根目錄的索引,以及每個子目錄的索引。

圖 5 中的標記 2 展示了索引的最終字節,並捕獲索引中存儲的樹對象。圖 8 展示了樹擴展數據的格式。

圖 8:Git 索引文件樹擴展對象數據格式

索引文件 - 緩存的樹擴展標頭4 字節TREE用於緩存的樹擴展條目的固定籤名。4 字節表示 TREE 擴展數據長度的 32 位數字

 

緩存的樹擴展條目變量Path以空字符結尾的路徑字符串(只有是根樹,才為 NULL)。ASCII 數字條目數ASCII 數字,表示此樹條目覆蓋的索引中的條目數。1 個字節20H(空格字符)
ASCII 數字子樹數量表示此樹的子樹數量的 ASCII 數字。1 個字節0AH(換行符)
20 字節樹對象的 SHA-1此條目生成的樹對象的 
SHA-1 值。


在偏移 284H 處出現的樹擴展數據標頭包含字符串「TREE」(標記了緩存的樹擴展數據的開頭),後跟 32 位值(表示後面的擴展數據的長度)。接下來是各個樹條目:第一個條目是樹路徑的以 NULL 結尾的長度不固定字符串值(或直接為 NUL,如果是根樹的話)。後跟 ASCII 值,因此十六進位編輯器中顯示「7」,即當前樹覆蓋的 blob 條目數(因為這是根樹,條目數與先前在籤發 Git ls-files 暫存命令時看到的條目數相同)。下一個字符是空格,後又跟一個 ASCII 數字,表示當前樹的子樹數量。

我們項目的根樹只有 1 個子樹:MSDNConsoleApp。此值後面是換行符和樹的 SHA-1 值。SHA-1 從偏移 291 處的 0d21e2 開始。

我們將確認 0d21e2 是否就是根樹的 SHA-1。為此,請轉到命令窗口並輸入:

git log

這將顯示與最近提交相關的詳細信息:

commit 5192391e9f907eeb47aa38d1c6a3a4ea78e33564Author: Jonathan Waldman <jonathan.waldman@live.com>Date:   Mon May 8 21:24:15 2017 -0500  Add project files.commit dc0d3343fa24e912f08bc18aaa6f664a4a020079Author: Jonathan Waldman <jonathan.waldman@live.com>Date:   Mon May 8 21:24:07 2017 -0500  Add .gitignore and .gitattributes.

最近一次提交的時間戳為 21:24:15,所以就是上次更新索引的提交。我可以使用此提交的 SHA-1 查找根樹的 SHA-1 值:

git cat-file -p 51923

輸出如下:

tree 0d21e2f7f760f77ead2cb85cc128efb13f56401dparent dc0d3343fa24e912f08bc18aaa6f664a4a020079author Jonathan Waldman <jonathan.waldman@live.com> 1494296655 -0500committer Jonathan Waldman <jonathan.waldman@live.com> 1494296655 -0500

以上樹條目就是根樹對象。據此可以確認,索引轉儲中偏移 291H 處的 0d21e2 值實際上就是根樹對象的 SHA-1 值。

SHA-1 值後面為其他樹條目(從偏移 2A5H 開始)。若要確認根樹下緩存的樹對象的 SHA-1 值,請運行以下命令:

git ls-tree -r -d master

這僅以遞歸方式顯示當前分支上的樹對象:

040000 tree c7c367f2d5688dddc25e59525cc6b8efd0df914d    MSDNConsoleApp040000 tree 2723ceb04eda3051abf913782fadeebc97e0123c    MSDNConsoleApp/Properties

第一列中的模式值 040000 表明此對象是目錄,而不是文件。

最後,索引的最後 20 個字節包含表示索引本身的 SHA-1 哈希值:就跟預期一樣,Git 使用此 SHA-1 值來驗證索引的數據完整性。

雖然我介紹了本文中示例索引文件的所有條目,但更大、更複雜的索引文件成為一種規範。索引文件格式支持附加的擴展數據流,例如:

支持合併操作和合併衝突解決方法的數據流。它的籤名為「REUC」(用於解決撤消衝突)。

用於維護未受跟蹤的文件(這些是未包含在跟蹤範圍內的文件,在 .gitignore 和 .git\info\exclude 中指定,並由 core.excludesfile 指向的文件指定)的緩存的數據流。它的籤名為「UNTR」。

支持拆分索引模式的數據流,以便加快非常大的索引文件的索引更新速度。它的籤名為「link」。

藉助索引的擴展功能,可以繼續添加索引功能。


本文回顧了 Git 三樹體系結構,並深入詳細地探討了索引文件的幕後運行機制。我介紹了 Git 為響應特定操作而更新索引,並依賴索引包含的信息,以便執行其他操作。

可以在不太考慮索引的情況下使用 Git。然而,了解索引可以獲取對 Git 核心功能的寶貴見解,同時了解 Git 如何檢測工作目錄中的文件更改、什麼是暫存區域及其非常有用的原因、Git 如何管理合併以及 Git 執行特定操作如此快速的原因。此外,還可以輕鬆了解籤出命令和變基命令的命令行變體,以及軟重置、混合重置與硬重置的區別。通過此類功能,可以指定應在發出特定命令時更新索引、工作目錄還是兩者都更新。了解 Git 工作流、策略和高級操作時,將會看到此類選項。本文旨在讓讀者認識到索引起到的重要作用,從而可以更好地了解具體利用方式。

Jonathan Waldman 是一名 Microsoft 認證專家,專攻軟體工效學,從 Microsoft 技術誕生之際便一直研究這些技術。Waldman 是 Pluralsight 技術團隊的成員,目前負責機構和私營部分的軟體開發項目。可以通過 jonathan.waldman@live.com 與他聯繫。

衷心感謝以下 Microsoft 技術專家對本文的審閱:Kraig Brockschmidt、Saeed Noursalehi、Ralph Squillace 和 Edward Thomson

相關焦點

  • 20 分鐘教你搞懂 Git!
    git ls-files命令可以顯示索引中當前的內容。$ git ls-files --stage100644 3b18e512dba79e4c8300dd08aeb37f8e728b8dad 0   test.txt上述代碼顯示索引中只有一個test.txt文件,還顯示了該文件的二進位對象名和訪問該文件的權限。
  • Oracle DB存儲體系結構
    • 跟蹤文件:每個伺服器和後臺進程都可以寫入關聯的跟蹤文件。當進程檢測到內部錯誤時,進程會將有關該錯誤的信息轉儲到相應的跟蹤文件中。寫入跟蹤文件的一些信息是為資料庫管理員提供的,而其它信息是為Oracle SupportServices 提供的。
  • 一文讀懂JAVA類文件結構
    有些人說了類文件結構我們知道或者不知道沒有什麼作用,如果你持有這種觀點,我覺得需要矯正一下,類文件結構是沒有多大的作用,但是它是我們代碼和java虛擬機之間的橋梁,如果研究透了類文件結構,那麼會對我們研究虛擬機的運行起到至關重要的作用,同樣對於我們研究jvm內存調優能夠帶來很大的幫助。
  • 索引很難麼?帶你從頭到尾捋一遍 MySQL 索引結構!
    而我們不難看出,頁內部存放數據的模塊,實質上就是一個鍊表的結構,鍊表的特點也就是增刪快,查詢慢,所以優化查詢的效率是必須的。但是,我們也可以看到,現在的頁模式內部,實際上是採用了鍊表的結構,前一條數據指向後一條數據,本質上還是通過數據的逐條比較來取出特定的數據。那麼假設,我們這一頁中有一百萬條數據,我們要查的數據正好在最後一個,那麼我們是不是一定要從前往後找到這一條數據呢?
  • MySQL索引及優化存儲引擎和底層數據結構
    在昨天的面試中問到了MySQL索引怎麼優化(查詢很慢怎麼辦),回答的很不理想,所以今天來總結幾篇關於MySQL索引的知識。1.什麼是索引?首先我們一定要明確什麼是索引?我自己的總結就是索引是一種數據結構,可以幫助我們快速訪問資料庫的指定信息,就像一本書的目錄一樣,可以加快查詢速度2.MySQl存儲引擎MySQL中最常見的存儲引擎有InnoDB和MyISAM,它們的主要區別如下:MyISAM不支持事務;InnoDB是事務類型的存儲引擎。MyISAM只支持表級鎖;InnoDB支持行級鎖和表級鎖,默認為行級鎖。
  • 文件結構概述:PNG格式
    概述在CTF比賽中,常見各種文件的隱寫題目。而圖片格式,常見的題目類型有LSB隱寫、圖片尺寸篡改、jphide隱寫等。本文將介紹PNG的文件結構內容,輔助解決CTF中遇到的圖片隱寫問題。什麼是 PNGPNG 是20世紀90年代中期開始開發的圖像文件存儲格式,其目的是替代 GIF 和 TIFF 文件格式,同時增加一些 GIF 文件格式所不具備的特性。
  • git環境配置和.gitconfig配置文件詳解
    上面提到的git remote add 和git config設置的參數是加上都是配置在git的配置文件中的。其中git remote添加的倉庫Url連結信息是保存在項目目錄.git/config文件中,這是項目級的配置文件。而git config設置的global信息保存在用戶級的配置文件中,該文件的位置為用戶目錄~/.gitconfig。
  • Git-操作文件
    add -i 相似,沒什麼鳥用update:詳見下方 git add -urevert:把已經添加到暫存區的文件從暫存區剔除,其操作方式和 update 類似add untracked:可以把新增的文件添加到暫存區,其操作方式和 update 類似patch:詳見下方 git add -pdiff:比較暫存區文件和本地版本庫的差異
  • 如何存儲 Git 大文件?
    你只需按常規進行 git checkout、編輯文件、git add 和 git commit。git clone 和 git pull 將明顯更快,因為你只下載實際檢出的提交所引用的大文件版本,而不是曾經存在過的文件的每一個版本。
  • MySQL中創建及優化索引組織結構的思路
    【IT168 專稿】通過一個實際生產環境中的數據存取需求,分析如何設計此存儲結構,如何操縱存儲的數據,以及如何使操作的成本或代價更低,系統開銷最小。同時,讓更多初學者明白數據存儲的表上索引是如何一個思路組織起來的,希望起到一個參考模板的價值作用。
  • MySQL的索引結構為什麼使用B+樹?
    前言在MySQL中,無論是Innodb還是MyIsam,都使用了B+樹作索引結構(這裡不考慮hash等其他索引
  • 索引很難麼?帶你從頭到尾捋一遍MySQL索引結構,不信你學不會!
    而我們不難看出,頁內部存放數據的模塊,實質上就是一個鍊表的結構,鍊表的特點也就是增刪快,查詢慢,所以優化查詢的效率是必須的。但是,我們也可以看到,現在的頁模式內部,實際上是採用了鍊表的結構,前一條數據指向後一條數據,本質上還是通過數據的逐條比較來取出特定的數據。那麼假設,我們這一頁中有一百萬條數據,我們要查的數據正好在最後一個,那麼我們是不是一定要從前往後找到這一條數據呢?如果是這樣,我們需要查找的次數就達到了一百萬次,即使是在內存中查找,這個效率也是不高的。
  • 【面試索引】B-Tree、B+Tree、紅黑樹、B*Tree數據結構
    面試官:你知道文件索引、資料庫索引一般用什麼數據結構來存儲嗎?小秋:知道啊,一般都是用樹形結構來存儲的。
  • Git鮮為人知的四個命令:bisect,blame,reflog和提交範圍
    關於git blame 還有以下兩點我們要牢記:(1):如果一個提交哈希前面有^號,那麼自該文件創建以來,相關聯的行就沒有被修改過。(2):Git還可以跟蹤跨文件的行內容變化。如果你要對一個大文件代碼重構或者你的配置文件重新發布到多個小文件中時,git會,那麼git會顯示大文件中的原始提交和大文件的名稱。你可通過-C選項來實現。3、Git reflog可能老司機警告過你要避免使用git reset。因為他是一種破壞性的操作。
  • 圖文詳解 Git 工作原理
    基本用法上面的四條命令在工作目錄、暫存目錄(也叫做索引)和倉庫之間複製文件。ResetReset命令把當前分支指向另一個位置,並且有選擇的變動工作目錄和索引。也用來在從歷史倉庫中複製文件到索引,而不動工作目錄。
  • C語言結構體描述BMP的文件格式
    本文轉載自【微信公眾號:strongerHuang,ID:strongerHuang】經微信公眾號授權轉載,如需轉載與原文作者聯繫BMP文件的結構其實非常簡單,就是兩個結構體+一個可選的調色板+位圖數據。第一個結構體是BITMAPFILEHEADER,第二個結構體是BITMAPINFOHEADER。然後就是可選的調色板(RGBQUAD數組)。
  • 你真的理解索引嗎?從數據結構層面解析mysql索引原理 - 計算機java...
    實際上,上面的結構就是一顆B+樹。實際的用戶記錄其實都存放在B+樹的葉子節點上,而非葉子節點存放的是目錄項。MyISAM中的索引方案簡單介紹我們知道InnoDB中索引即數據,也就是聚簇索引的那棵B+樹的葉子節點中已經把所有完整的用戶記錄都包含了,而MyISAM的索引方案雖然也使用樹形結構,但是卻將索引和數據分開存儲:
  • git底層原理,從常見操作解釋git的底層原理,再也不怯
    我們再次查看objects目錄$ find .git/objects/ -type f.git/objects/6a/0b867bdc470c582c15906f264b9fec371cdbfc這就是開始時 Git 存儲內容的方式——一個文件對應一條內容, 以該內容加上特定頭部信息一起的 SHA-1 校驗和為文件命名。
  • 概述Java中的數據結構是什麼及其內部實現原理
    那麼我該如何向數組中刪除一個元素呢這是我剛剛學習java時寫的一小段代碼,它用於刪除數組指定下標的元素,邏輯就是將要刪除的下標置換到數組尾部然後縮減數組長度,添加也是同樣的方法,總之是非常的麻煩,那麼對數組這種結構可以歸納為數組是一種被創建時長度固定,難增刪的數據結構,但是它由於有下標作為索引所以能夠快速定位到指定下標的元素,同時java.util.Arrays
  • 真核細胞的基本結構體系
    真核細胞是遺傳信息量大、結構複雜的細胞,原始的真核細胞在早在12億~16億年前的地球上就已經出現了。現存的真核生物種類繁多,既包括大量的單細胞原生生物,又包括全部多細胞生物(一切動植物、大部分真菌)。真核細胞在內部構建成許多精細的具有專門功能的結構單位。