設定和配置
獲取和建立專案
基本快照
分支與合併
共享和更新專案
檢查和比較
打補丁
除錯
電子郵件
外部系統
伺服器管理
指南
管理
底層命令
- 2.43.1 → 2.50.1 無更改
-
2.43.0
2023-11-20
- 2.40.1 → 2.42.4 無更改
-
2.40.0
2023-03-12
- 2.39.1 → 2.39.5 無變化
-
2.39.0
2022-12-12
- 2.37.1 → 2.38.5 無變更
-
2.37.0
2022-06-27
- 2.36.1 → 2.36.6 無更改
-
2.36.0
2022-04-18
- 2.34.1 → 2.35.8 無更改
-
2.34.0
2021-11-15
- 2.27.1 → 2.33.8 無變化
-
2.27.0
2020-06-01
- 2.25.1 → 2.26.3 無更改
-
2.25.0
2020-01-13
- 2.22.1 → 2.24.4 無更改
-
2.22.0
2019-06-07
- 2.18.1 → 2.21.4 無變更
-
2.18.0
2018-06-21
- 2.17.0 → 2.17.6 無更改
-
2.16.6
2019-12-06
- 2.15.4 無更改
-
2.14.6
2019-12-06
-
2.13.7
2018-05-22
- 2.2.3 → 2.12.5 無變化
-
2.1.4
2014-12-17
-
2.0.5
2014-12-17
概要
git read-tree [(-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>) [-u | -i]] [--index-output=<file>] [--no-sparse-checkout] (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])
描述
將 <tree-ish>
指定的樹資訊讀入索引,但不會實際 更新 它“快取”的任何檔案。(請參閱:git-checkout-index[1])
可選地,它可以使用 -m
標誌將一個樹合併到索引中,執行快進(即雙向)合併,或三向合併。與 -m
結合使用時,-u
標誌還會用合併結果更新工作樹中的檔案。
只有簡單的合併是由 git read-tree 本身完成的。只有衝突的路徑在 git read-tree 返回時會處於未合併狀態。
選項
- -m
-
執行合併,而不僅僅是讀取。如果您的索引檔案有未合併的條目,該命令將拒絕執行,表明您尚未完成之前開始的合併。
- --reset
-
與 -m 相同,但未合併的條目將被丟棄而不是導致失敗。與
-u
結合使用時,導致工作樹更改或未跟蹤檔案或目錄丟失的更新不會中止操作。 - -u
-
成功合併後,用合併結果更新工作樹中的檔案。
- -i
-
通常,合併要求索引檔案以及工作樹中的檔案與當前 HEAD 提交保持最新,以免丟失本地更改。此標誌停用對工作樹的檢查,旨在用於將與當前工作樹狀態沒有直接關係的樹合併到臨時索引檔案時使用。
- -n
- --dry-run
-
檢查命令是否會出錯,而不實際更新索引或工作樹中的檔案。
- -v
-
顯示檢查檔案的進度。
- --trivial
-
限制 git read-tree 的三向合併僅在無需檔案級合併時發生,而不是為簡單情況解決合併並讓衝突檔案在索引中保持未解決狀態。
- --aggressive
-
通常,git read-tree 的三向合併會為非常簡單的情況解決合併,而將其他情況留在索引中未解決,以便上層命令可以實現不同的合併策略。此標誌使命令在以下情況下在內部解決更多情況:
-
當一方刪除路徑而另一方保持路徑不變時。解決方案是刪除該路徑。
-
當雙方都刪除路徑時。解決方案是刪除該路徑。
-
當雙方以相同方式新增路徑時。解決方案是新增該路徑。
-
- --prefix=<prefix>
-
保留當前索引內容,並將指定樹物件的目錄內容讀入 <prefix> 目錄。該命令將拒絕覆蓋原始索引檔案中已存在的條目。
- --index-output=<file>
-
將結果寫入指定的
<file>
中,而不是寫入$GIT_INDEX_FILE
。在命令操作期間,原始索引檔案會像往常一樣被鎖定。該檔案必須允許從在常用索引檔案旁邊建立的臨時檔案透過 rename(2) 重新命名;通常這意味著它需要與索引檔案本身位於同一檔案系統上,並且您需要對索引檔案和索引輸出檔案所在的目錄具有寫入許可權。 - --[no-]recurse-submodules
-
使用 --recurse-submodules 將根據超級專案中記錄的提交,透過遞迴呼叫 read-tree 來更新所有活動子模組的內容,同時也將子模組的 HEAD 分離到該提交。
- --no-sparse-checkout
-
即使
core.sparseCheckout
為 true,也停用稀疏檢出支援。 - --empty
-
清空索引,而不是將樹物件讀入索引。
- -q
- --quiet
-
安靜模式,抑制反饋訊息。
- <tree-ish#>
-
要讀取/合併的樹物件的 ID。
合併
如果指定了 -m
,git read-tree 可以執行 3 種合併:如果只給出一個樹,則進行單個樹合併;使用兩個樹進行快進合併;或如果提供三個或更多樹,則進行三向合併。
單樹合併
如果只指定一個樹,git read-tree 的操作就像使用者沒有指定 -m
一樣,但如果原始索引中存在給定路徑名的條目,並且路徑內容與正在讀取的樹匹配,則使用索引中的 stat 資訊。(換句話說,索引的 stat()s 優先於合併樹的 stat()s)。
這意味著如果您執行 git
read-tree
-m
<newtree>,然後執行 git
checkout-index
-f
-u
-a
,則 git checkout-index 只會檢出實際更改的內容。
這用於避免在 git read-tree 執行後執行 git diff-files 時出現不必要的錯誤命中。
雙樹合併
通常,這透過 git
read-tree
-m
$H
$M
呼叫,其中 $H 是當前倉庫的 HEAD 提交,而 $M 是外部樹的 HEAD,該外部樹只是超前於 $H(即我們處於快進情況)。
當指定兩個樹時,使用者正在告訴 git read-tree 以下內容:
-
當前索引和工作樹源自 $H,但使用者可能自 $H 以來在其中進行了本地更改。
-
使用者希望快進到 $M。
在這種情況下,git
read-tree
-m
$H
$M
命令確保此“合併”不會丟失任何本地更改。以下是“沿用”規則,其中“I”表示索引,“clean”表示索引和工作樹一致,“exists”/“nothing”表示路徑在指定提交中的存在:
I H M Result ------------------------------------------------------- 0 nothing nothing nothing (does not happen) 1 nothing nothing exists use M 2 nothing exists nothing remove path from index 3 nothing exists exists, use M if "initial checkout", H == M keep index otherwise exists, fail H != M clean I==H I==M ------------------ 4 yes N/A N/A nothing nothing keep index 5 no N/A N/A nothing nothing keep index 6 yes N/A yes nothing exists keep index 7 no N/A yes nothing exists keep index 8 yes N/A no nothing exists fail 9 no N/A no nothing exists fail 10 yes yes N/A exists nothing remove path from index 11 no yes N/A exists nothing fail 12 yes no N/A exists nothing fail 13 no no N/A exists nothing fail clean (H==M) ------ 14 yes exists exists keep index 15 no exists exists keep index clean I==H I==M (H!=M) ------------------ 16 yes no no exists exists fail 17 no no no exists exists fail 18 yes no yes exists exists keep index 19 no no yes exists exists keep index 20 yes yes no exists exists use M 21 no yes no exists exists fail
在所有“保留索引”的情況下,索引條目保持與原始索引檔案中的相同。如果條目不是最新的,git read-tree 在使用 -u 標誌操作時會保持工作樹中的副本不變。
當這種形式的 git read-tree 成功返回時,您可以透過執行 git
diff-index
--cached
$M
來檢視您所做的哪些“本地更改”被沿用了。請注意,這不一定與在進行這種雙樹合併之前 git
diff-index
--cached
$H
所產生的結果匹配。這是因為情況 18 和 19 —— 如果您已經在 $M 中擁有這些更改(例如,您可能透過電子郵件以補丁形式獲取了它),在本次合併之前 git
diff-index
--cached
$H
會告訴您有關這些更改的資訊,但它不會在雙樹合併後在 git
diff-index
--cached
$M
的輸出中顯示。
情況 3 略顯棘手,需要解釋。此規則的結果邏輯上應該是如果使用者暫存了路徑的刪除然後切換到一個新分支,則刪除該路徑。但這會阻止初始檢出發生,因此規則被修改為僅當索引內容為空時才使用 M(新樹)。否則,只要 $H 和 $M 相同,路徑的刪除就會被保留。
三向合併
每個“索引”條目都有兩個位的“階段”狀態。階段 0 是正常狀態,也是您在任何正常使用中唯一會看到的狀態。
然而,當您使用三個樹執行 git read-tree 時,“階段”從 1 開始。
這意味著您可以執行
$ git read-tree -m <tree1> <tree2> <tree3>
最終您將得到一個索引,其中所有 <tree1>
條目位於“stage1”中,所有 <tree2>
條目位於“stage2”中,所有 <tree3>
條目位於“stage3”中。將另一個分支合併到當前分支時,我們使用共同祖先樹作為 <tree1>
,當前分支頭作為 <tree2>
,另一個分支頭作為 <tree3>
。
此外,git read-tree 具有特殊邏輯,規定:如果您看到一個在以下所有方面都匹配的檔案,它將“摺疊”回“stage0”:
-
階段 2 和 3 相同;取其中之一(沒有區別——我們分支的階段 2 和他們分支的階段 3 做了相同的工作)
-
階段 1 和階段 2 相同,而階段 3 不同;取階段 3(我們分支的階段 2 自階段 1 的祖先以來沒有做任何事情,而他們分支的階段 3 對其進行了操作)
-
階段 1 和階段 3 相同,而階段 2 不同;取階段 2(我們做了些什麼,而他們沒有做任何事情)
git write-tree 命令拒絕寫入無意義的樹,如果它看到任何非階段 0 的單個條目,它將抱怨未合併的條目。
好的,這一切聽起來像是一堆完全沒有意義的規則,但實際上它正是您進行快速合併所需要的。不同的階段代表“結果樹”(階段 0,即“已合併”)、原始樹(階段 1,即“原始”),以及您試圖合併的兩個樹(分別為階段 2 和 3)。
當您開始對已填充的索引檔案進行三向合併時,階段 1、2 和 3 的順序(因此也是三個 <tree-ish>
命令列引數的順序)非常重要。演算法的工作原理概述如下:
-
如果檔案在所有三個樹中都以相同的格式存在,它將由 git read-tree 自動摺疊為“已合併”狀態。
-
如果檔案在三個樹中有 任何 不同之處,它將作為單獨的條目保留在索引中。如何刪除非 0 階段並插入合併版本,由“上層策略”決定。
-
索引檔案儲存並恢復所有這些資訊,因此您可以增量合併,但只要它有階段 1/2/3 的條目(即“未合併的條目”),您就不能寫入結果。所以現在合併演算法變得非常簡單:
-
您按順序遍歷索引,並忽略所有階段 0 的條目,因為它們已經完成。
-
如果您找到一個“stage1”,但沒有匹配的“stage2”或“stage3”,您就知道它已從兩個樹中刪除(它只存在於原始樹中),並且您刪除該條目。
-
如果您找到匹配的“stage2”和“stage3”樹,您刪除其中一個,並將另一個轉換為“stage0”條目。如果存在匹配的“stage1”條目,也將其刪除。..所有正常的簡單規則..
-
您通常會使用 git merge-index 並提供 git merge-one-file 來完成最後一步。該指令碼在合併每個路徑時更新工作樹中的檔案,並在成功合併結束時更新。
當您使用已填充的索引檔案啟動三向合併時,假定它代表您工作樹中檔案的狀態,並且您甚至可以擁有索引檔案中未記錄更改的檔案。進一步假定此狀態“派生”自階段 2 樹。如果它在原始索引檔案中找到與階段 2 不匹配的條目,則三向合併將拒絕執行。
這樣做是為了防止您丟失正在進行的更改,以及將您的隨意更改混入不相關的合併提交中。為了說明,假設您從上次提交到倉庫的內容開始:
$ JC=`git rev-parse --verify "HEAD^0"` $ git checkout-index -f -u -a $JC
您進行隨意編輯,但不執行 git update-index。然後您注意到您的“上游”樹的尖端自從您從他那裡拉取以來已經前進:
$ git fetch git://.... linus $ LT=`git rev-parse FETCH_HEAD`
您的工作樹仍然基於您的 HEAD ($JC),但您自那以後進行了一些編輯。三向合併確保您自 $JC 以來沒有新增或修改索引條目,如果沒有,則會做正確的事情。因此,按照以下順序:
$ git read-tree -m -u `git merge-base $JC $LT` $JC $LT $ git merge-index git-merge-one-file -a $ echo "Merge with Linus" | \ git commit-tree `git write-tree` -p $JC -p $LT
您將提交的是 $JC 和 $LT 之間的純合併,不包含您正在進行的更改,並且您的工作樹將更新為合併的結果。
但是,如果工作樹中有本地更改將被此合併覆蓋,git read-tree 將拒絕執行以防止您的更改丟失。
換句話說,無需擔心工作樹中僅存在的內容。當您在專案中未參與合併的部分有本地更改時,您的更改不會干擾合併,並保持不變。當它們 確實 干擾時,合併甚至不會開始(git read-tree 會大聲抱怨並失敗,不修改任何內容)。在這種情況下,您可以簡單地繼續您正在做的事情,當您的工作樹準備好時(即您已完成正在進行的工作),再次嘗試合併。
稀疏檢出
注意:git-update-index[1] 和 read-tree
中的 skip-worktree 功能早於 git-sparse-checkout[1] 的引入。鼓勵使用者優先使用 sparse-checkout
命令來滿足稀疏檢出/skip-worktree 相關需求,而不是這些底層命令。但是,以下資訊可能對試圖理解 sparse-checkout
命令非錐形模式中使用的模式樣式很有用。
“稀疏檢出”允許稀疏填充工作目錄。它使用 skip-worktree 位(請參閱 git-update-index[1])來告訴 Git 工作目錄中的檔案是否值得檢視。
git read-tree 和其他基於合併的命令(git merge、git checkout...)可以幫助維護 skip-worktree 點陣圖和工作目錄更新。$GIT_DIR/info/sparse-checkout
用於定義 skip-worktree 引用點陣圖。當 git read-tree 需要更新工作目錄時,它會根據此檔案重置索引中的 skip-worktree 位,該檔案使用與 .gitignore 檔案相同的語法。如果條目與此檔案中的模式匹配,或者條目對應於工作樹中存在的檔案,則該條目將不會設定 skip-worktree。否則,將設定 skip-worktree。
然後它將新的 skip-worktree 值與舊值進行比較。如果 skip-worktree 從已設定變為未設定,它將新增相應的迴文件。如果它從未設定變為已設定,則該檔案將被刪除。
雖然 $GIT_DIR/info/sparse-checkout
通常用於指定包含哪些檔案,但您也可以使用否定模式指定 不 包含哪些檔案。例如,要刪除檔案 unwanted
:
/* !unwanted
另一個棘手的問題是當您不再需要稀疏檢出時完全重新填充工作目錄。您不能僅僅停用“稀疏檢出”,因為 skip-worktree 位仍在索引中,並且您的工作目錄仍處於稀疏填充狀態。您應該按如下方式使用 $GIT_DIR/info/sparse-checkout
檔案內容重新填充工作目錄:
/*
然後您可以停用稀疏檢出。git read-tree 和類似命令中的稀疏檢出支援預設是停用的。您需要將 core.sparseCheckout
設定為 on 才能獲得稀疏檢出支援。