簡體中文 ▾ 主題 ▾ 最新版本 ▾ git-merge-tree 最後更新於 2.50.0

名稱

git-merge-tree - 執行合併而不觸及索引或工作區

概要

git merge-tree [--write-tree] [<options>] <branch1> <branch2>
git merge-tree [--trivial-merge] <base-tree> <branch1> <branch2> (deprecated)

描述

此命令有一個現代的 --write-tree 模式和一個已廢棄的 --trivial-merge 模式。除了末尾的已廢棄描述部分外,本文件的其餘部分描述的是現代的 --write-tree 模式。

執行合併,但不建立任何新的提交,也不讀取或寫入工作區或索引。

執行的合併將使用與“真正的”git-merge[1] 相同的功能,包括

  • 單個檔案的三方內容合併

  • 重新命名檢測

  • 正確的目錄/檔案衝突處理

  • 遞迴祖先整合(即,當存在多個合併基礎時,透過合併這些合併基礎來建立虛擬合併基礎)

  • 等等。

合併完成後,將建立一個新的頂層樹物件。詳見下面的 OUTPUT

選項

--stdin

從標準輸入而非命令列讀取要合併的提交。更多資訊請參見下面的輸入格式。此選項隱含 -z

-z

在“<衝突檔案資訊>”部分不引用檔名,並且每個檔名以 NUL 字元而不是換行符結束。訊息部分也以 NUL 字元而不是換行符開始。更多資訊請參見下面的輸出

--name-only

在“衝突檔案資訊”部分中,對於衝突檔案,不輸出 (模式、OID、階段、路徑) 元組列表,只提供衝突檔名列表(如果檔名有多個衝突階段,則不重複列出)。

--[no-]messages

將所有資訊性訊息(如“自動合併 <路徑>”或衝突通知)寫入標準輸出的末尾。如果未指定,預設情況下,如果存在合併衝突則包含這些訊息,否則省略。

--quiet

停用程式的所有輸出。當您只對退出狀態感興趣時很有用。允許 merge-tree 在發現衝突時提前退出,並允許它避免寫入大多數由合併建立的物件。

--allow-unrelated-histories

merge-tree 預設情況下,如果指定了兩個分支沒有共同的歷史,則會報錯。可以給定此標誌以覆蓋該檢查並仍進行合併。

--merge-base=<tree-ish>

不查詢 <branch1> 和 <branch2> 的合併基礎,而是為合併指定一個合併基礎,目前不支援指定多個基礎。此選項與 --stdin 不相容。

由於直接提供了合併基礎,<branch1> 和 <branch2> 不需要指定提交;樹物件就足夠了。

-X<option>
--strategy-option=<option>

將合併策略特定的選項傳遞給合併策略。有關詳細資訊,請參閱 git-merge[1]

輸出

對於成功的合併,git-merge-tree 的輸出只有一行

<OID of toplevel tree>

而對於衝突的合併,輸出預設形式為

<OID of toplevel tree>
<Conflicted file info>
<Informational messages>

下面將分別討論這些。

但是,有一個例外。如果傳遞了 --stdin,則開頭會有一個額外的部分,末尾會有一個 NUL 字元,然後所有部分都會為輸入的每一行重複。因此,如果第一次合併發生衝突而第二次合併乾淨,則輸出的形式為

<Merge status>
<OID of toplevel tree>
<Conflicted file info>
<Informational messages>
NUL
<Merge status>
<OID of toplevel tree>
NUL

合併狀態

這是一個整數狀態,後跟一個 NUL 字元。整數狀態是

0: merge had conflicts
1: merge was clean

頂層樹的 OID

這是一個樹物件,表示 git merge 結束時將在工作區中檢出的內容。如果存在衝突,則此樹中的檔案可能包含嵌入的衝突標記。此部分後始終跟著一個換行符(如果傳遞了 -z 則為 NUL)。

衝突檔案資訊

這是一系列行,格式為

<mode> <object> <stage> <filename>

檔名將按照配置變數 core.quotePath 的解釋進行引用(參見git-config[1])。但是,如果傳遞了 --name-only 選項,則將省略模式、物件和階段。如果傳遞了 -z,則“行”由 NUL 字元而不是換行符終止。

資訊性訊息

此部分提供資訊性訊息,通常與衝突有關。此部分的格式根據是否傳遞了 -z 而顯著不同。

如果傳遞了 -z

輸出格式是零個或多個衝突資訊記錄,每個記錄的形式為

<list-of-paths><conflict-type>NUL<conflict-message>NUL

其中 <路徑列表> 的形式為

<number-of-paths>NUL<path1>NUL<path2>NUL...<pathN>NUL

幷包含受 <衝突訊息> 中衝突或資訊性訊息影響的路徑(或分支名稱)。此外,<衝突型別> 是一個穩定的字串,解釋衝突型別,例如

  • "Auto-merging"(自動合併)

  • "CONFLICT (rename/delete)"(衝突(重新命名/刪除))

  • "CONFLICT (submodule lacks merge base)"(衝突(子模組缺少合併基礎))

  • "CONFLICT (binary)"(衝突(二進位制))

而 <衝突訊息> 是關於衝突的更詳細的訊息,通常(但不總是)在其中嵌入了 <stable-short-type-description>。這些字串在未來的 Git 版本中可能會改變。一些例子:

  • "Auto-merging <檔案>"(自動合併 <檔案>)

  • "CONFLICT (rename/delete): <舊檔案> 重新命名…​但在…​中刪除"(衝突(重新命名/刪除):<舊檔案> 重新命名…​但在…​中刪除)

  • "Failed to merge submodule <子模組> (no merge base)"(合併子模組 <子模組> 失敗(無合併基礎))

  • "Warning: cannot merge binary files: <檔名>"(警告:無法合併二進位制檔案:<檔名>)

如果未傳遞 -z

此部分以一個空行開始,將其與前幾個部分分隔開,然後只包含前一節中的 <衝突訊息> 資訊(由換行符分隔)。這些是非穩定字串,不應被指令碼解析,僅供人類閱讀。此外,請注意,雖然 <衝突訊息> 字串通常不包含嵌入的換行符,但有時會包含。(然而,自由形式的訊息永遠不會有嵌入的 NUL 字元)。因此,整個資訊塊旨在供人類讀者閱讀,作為所有衝突訊息的彙總。

退出狀態

對於成功的、無衝突的合併,退出狀態為 0。當合並存在衝突時,退出狀態為 1。如果合併因某種錯誤而無法完成(或開始),則退出狀態不是 0 或 1(並且輸出未指定)。當傳遞 --stdin 時,成功合併和衝突合併的返回狀態均為 0,如果無法完成所有請求的合併,則返回狀態不是 0 或 1。

使用注意事項

此命令旨在作為低階工具,類似於 git-hash-object[1]git-mktree[1]git-commit-tree[1]git-write-tree[1]git-update-ref[1]git-mktag[1]。因此,它可以作為一系列步驟的一部分使用,例如

vi message.txt
BRANCH1=refs/heads/test
BRANCH2=main
NEWTREE=$(git merge-tree --write-tree $BRANCH1 $BRANCH2) || {
    echo "There were conflicts..." 1>&2
    exit 1
}
NEWCOMMIT=$(git commit-tree $NEWTREE -F message.txt \
    -p $BRANCH1 -p $BRANCH2)
git update-ref $BRANCH1 $NEWCOMMIT

請注意,當退出狀態不為零時,此序列中的 NEWTREE 將包含比單純一個樹物件多得多的輸出。

對於衝突,輸出包含與 git-merge[1] 相同的資訊:

輸入格式

git merge-tree --stdin 的輸入格式是純文字。每行都有此格式

[<base-commit> -- ]<branch1> <branch2>

如果一行由 -- 分隔,則分隔符之前的字串用於指定合併的合併基礎,分隔符之後的字串描述要合併的分支。

避免的錯誤

請勿透過遍歷生成的頂層樹來嘗試查詢哪些檔案存在衝突;請改為解析衝突檔案資訊部分。在大型倉庫中解析整個樹物件不僅會非常慢,而且有許多型別的衝突無法用衝突標記表示(修改/刪除、模式衝突、兩側都更改了二進位制檔案、檔案/目錄衝突、各種重新命名衝突排列等)。

請勿將空的衝突檔案資訊列表解釋為乾淨合併;請檢查退出狀態。合併可能存在衝突,但沒有單個檔案衝突(有幾種型別的目錄重新命名衝突屬於此類別,未來也可能新增其他型別)。

請勿嘗試從衝突檔案資訊列表中猜測或讓使用者猜測衝突型別。那裡的資訊不足以做到這一點。例如:重新命名/重新命名(1to2)衝突(雙方以不同方式重新命名了相同的檔案)將導致三個不同的檔案具有更高階階段(但每個檔案只有一個更高階階段),無法確定哪三個檔案是相關的(除非檢視資訊性訊息部分)。檔案/目錄衝突也會導致一個檔案只有一個更高階階段。可能涉及目錄重新命名衝突(當“merge.directoryRenames”未設定或設定為“conflicts”時)也會導致一個檔案只有一個更高階階段。在所有情況下,資訊性訊息部分都包含必要的資訊,儘管它並非設計為機器可解析的。

請勿假設衝突檔案資訊中的每個路徑與資訊性訊息中的邏輯衝突之間存在一對一對映,也不存在一對多對映,也不存在多對一對映。多對多對映是存在的,這意味著每個路徑在單次合併中可以有多種邏輯衝突型別,並且每種邏輯衝突型別可以影響多個路徑。

請勿假設資訊性訊息部分中列出的所有檔名都有衝突。訊息可以包含沒有衝突的檔案,例如“Auto-merging <檔案>”。

避免從衝突檔案資訊中獲取 OID 並重新合併它們以向用戶呈現衝突。這將丟失資訊。相反,請查詢頂層樹的 OID中找到的檔案版本並顯示該版本。特別是,後者將帶有原始分支/提交(正在合併)的衝突標記註釋,如果涉及重新命名,還將帶有原始檔名。雖然您可以在重新合併時在衝突標記註釋中包含原始分支/提交,但原始檔名無法從衝突檔案資訊中獲取,因此您將丟失可能有助於使用者解決衝突的資訊。

已廢棄描述

根據描述,與本文件的其餘部分不同,本節描述的是已廢棄的 --trivial-merge 模式。

除了可選的 --trivial-merge 之外,此模式不接受其他選項。

此模式讀取三個樹形物件,並將簡單的合併結果和衝突階段以半差分格式輸出到標準輸出。由於這是為更高級別的指令碼消費並將結果合併回索引而設計的,因此它省略了與 <branch1> 匹配的條目。第二種形式的結果類似於三方 git read-tree -m 的操作,但它不是將結果儲存在索引中,而是將條目輸出到標準輸出。

這種形式不僅適用範圍有限(簡單合併無法處理單個檔案的內容合併、重新命名檢測、正確的目錄/檔案衝突處理等),而且輸出格式也難以處理,並且即使在成功合併的情況下,其效能通常也會低於第一種形式(特別是在大型倉庫中工作時)。

Git

Git[1] 套件的一部分

scroll-to-top