設定與配置
取得與建立專案
基本快照
分支與合併
分享與更新專案
檢查與比較
修補
除錯
電子郵件
外部系統
伺服器管理
指南
管理
底層命令
- 2.43.1 → 2.47.0 無變更
-
2.43.0
11/20/23
- 2.40.1 → 2.42.3 無變更
-
2.40.0
03/12/23
- 2.39.1 → 2.39.5 無變更
-
2.39.0
12/12/22
- 2.37.1 → 2.38.5 無變更
-
2.37.0
06/27/22
- 2.36.1 → 2.36.6 無變更
-
2.36.0
04/18/22
- 2.34.1 → 2.35.8 無變更
-
2.34.0
11/15/21
- 2.27.1 → 2.33.8 無變更
-
2.27.0
06/01/20
- 2.25.1 → 2.26.3 無變更
-
2.25.0
01/13/20
- 2.22.1 → 2.24.4 無變更
-
2.22.0
06/07/19
- 2.18.1 → 2.21.4 無變更
-
2.18.0
06/21/18
- 2.17.0 → 2.17.6 無變更
-
2.16.6
12/06/19
- 2.15.4 無變更
-
2.14.6
12/06/19
-
2.13.7
05/22/18
- 2.2.3 → 2.12.5 無變更
-
2.1.4
12/17/14
-
2.0.5
12/17/14
概要
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 commit 保持最新,才不會遺失本機變更。此旗標會停用與工作樹的檢查,目的是用於建立與目前工作樹狀態沒有直接關係的樹狀結構合併到暫時的索引檔案中。
- -n
- --dry-run
-
檢查命令是否會發生錯誤,而不會真正更新索引或工作樹中的檔案。
- -v
-
顯示檢查檔案時的進度。
- --trivial
-
將 *git read-tree* 的三向合併限制為只有在不需要檔案層級合併的情況下才會發生,而不是解決微不足道案例的合併,並在索引中留下未解決的衝突檔案。
- --aggressive
-
通常,*git read-tree* 的三向合併會解決非常微不足道案例的合併,並在索引中留下其他未解決的案例,以便瓷器可以實作不同的合併策略。此旗標會使命令在內部解決更多案例
-
當一側移除路徑而另一側保持路徑未修改時。解決方法是移除該路徑。
-
當兩側都移除路徑時。解決方法是移除該路徑。
-
當兩側都以相同方式新增路徑時。解決方法是新增該路徑。
-
- --prefix=<prefix>
-
保留目前的索引內容,並在
<prefix>
的目錄下讀取指定樹狀結構的內容。該命令將拒絕覆寫原始索引檔案中已存在的條目。 - --index-output=<file>
-
不是將結果寫出到
$GIT_INDEX_FILE
,而是將結果索引寫入指定的檔案中。當命令正在執行時,原始索引檔案會使用與平常相同的機制鎖定。該檔案必須允許從在一般索引檔案旁邊建立的暫存檔案重新命名(2)到該檔案中;通常這表示它需要與索引檔案本身位於相同的檔案系統上,而且您需要對索引檔案和索引輸出檔案所在的目錄具有寫入權限。 - --[no-]recurse-submodules
-
使用 --recurse-submodules 將根據超專案中記錄的 commit,透過遞迴呼叫 read-tree 來更新所有作用中子模組的內容,也會將子模組的 HEAD 設定為在該 commit 處分離。
- --no-sparse-checkout
-
即使
core.sparseCheckout
為 true,也會停用稀疏檢出支援。 - --empty
-
不是將樹狀結構物件讀入索引,而是清空索引。
- -q
- --quiet
-
靜默,抑制回饋訊息。
- <tree-ish#>
-
要讀取/合併的樹狀結構物件的 ID。
合併
如果指定 -m
,*git read-tree* 可以執行 3 種合併類型,如果只提供 1 個樹狀結構,則為單一樹狀結構合併,如果提供 2 個樹狀結構,則為快速前進合併,如果提供 3 個或更多樹狀結構,則為三向合併。
單一樹狀結構合併
如果只指定 1 個樹狀結構,*git read-tree* 的運作方式就像使用者未指定 -m
一樣,但如果原始索引中具有指定路徑名稱的條目,且路徑的內容與正在讀取的樹狀結構相符,則會使用索引中的 stat 資訊。(換句話說,索引的 stat() 優先於合併的樹狀結構)。
這表示如果您執行 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 commit,$M 是外部樹狀結構的 head,它只是在 $H 之前 (也就是說,我們處於快速前進的情況)。
當指定兩個樹狀結構時,使用者會告知 *git read-tree* 以下內容
-
目前的索引和工作樹衍生自 $H,但使用者在 $H 之後可能在本機對其進行了變更。
-
使用者想要快速前進到 $M。
在這種情況下,git read-tree -m $H $M
命令會確保不會因這種「合併」而遺失任何本機變更。以下是「向前攜帶」規則,其中「I」表示索引,「clean」表示索引和工作樹一致,「exists」/「nothing」是指指定 commit 中是否存在路徑
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
在所有「保留索引」的情況下,索引條目會保持在原始索引檔案中的樣子。如果條目不是最新版本,則當在 -u 旗標下執行時,*git read-tree* 會保持工作樹中的副本完整無缺。
當此形式的 *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> 的條目都在「階段 1」,所有 <tree2> 的條目都在「階段 2」,而所有 <tree3> 的條目都在「階段 3」。當將另一個分支合併到目前分支時,我們使用共同祖先樹作為 <tree1>,目前分支的頭部作為 <tree2>,以及另一個分支的頭部作為 <tree3>。
此外,git read-tree 具有特殊的邏輯,表示:如果你看到一個檔案在以下狀態下所有方面都匹配,它會「摺疊」回「階段 0」
-
階段 2 和 3 相同;取其中一個即可 (沒有區別 - 我們的分支在階段 2 和他們的分支在階段 3 完成了相同的工作)
-
階段 1 和階段 2 相同,而階段 3 不同;取階段 3 (我們的分支在階段 2 中沒有做任何事情,因為階段 1 中的祖先,而他們的分支在階段 3 中處理了它)
-
階段 1 和階段 3 相同,而階段 2 不同;取階段 2 (我們做了某事,而他們什麼都沒做)
git write-tree 命令拒絕寫入無意義的樹,如果看到單個條目不是階段 0,它會抱怨未合併的條目。
好的,這一切聽起來像是一堆完全無意義的規則,但它實際上正是你想要執行快速合併的方式。不同的階段代表「結果樹」(階段 0,又名「已合併」)、原始樹 (階段 1,又名「orig」) 以及你嘗試合併的兩個樹 (分別為階段 2 和 3)。
當你使用已填入的索引檔案開始三向合併時,階段 1、2 和 3 的順序 (因此三個 <樹狀結構> 命令列引數的順序) 很重要。以下是演算法運作方式的概述
-
如果檔案在三個樹中以相同的格式存在,它會被 git read-tree 自動摺疊為「已合併」狀態。
-
在三個樹中具有任何差異的檔案,將保留為索引中的單獨條目。如何移除非 0 階段,並插入合併的版本,取決於「瓷器策略」。
-
索引檔案會儲存並還原所有這些資訊,因此你可以逐步合併,但是只要它在階段 1/2/3 中有條目 (即「未合併的條目」),你就無法寫入結果。因此,現在合併演算法變得非常簡單
-
你依序走訪索引,並忽略所有階段 0 的條目,因為它們已經完成。
-
如果你找到「階段 1」,但沒有找到匹配的「階段 2」或「階段 3」,則表示它已從兩個樹中移除 (它僅存在於原始樹中),並且你移除該條目。
-
如果你找到匹配的「階段 2」和「階段 3」樹,則移除其中一個,並將另一個變成「階段 0」條目。如果存在,也移除任何匹配的「階段 1」條目。.. 所有正常的簡單規則 ..
-
你通常會使用提供的 git merge-one-file 的 git merge-index 來執行最後一步。腳本會在合併每個路徑時以及成功合併結束時更新工作目錄中的檔案。
當你使用已填入的索引檔案開始三向合併時,假設它代表工作樹中檔案的狀態,你甚至可以擁有索引檔案中未記錄的變更檔案。進一步假設此狀態是從階段 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
才能擁有稀疏簽出支援。
GIT
git[1] 套件的一部分