日本語 ▾ トピック ▾ 最新バージョン ▾ 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] と同じ機能を使用します。

  • 個々のファイルの3方向コンテンツマージ

  • 名前変更検出

  • 適切なディレクトリ/ファイル競合処理

  • 再帰的な祖先統合 (つまり、マージベースが複数ある場合、マージベースをマージして仮想マージベースを作成する)

  • など。

マージが完了すると、新しいトップレベルのツリーオブジェクトが作成されます。詳細については、以下の OUTPUT を参照してください。

オプション

--stdin

コマンドラインではなく標準入力からマージするコミットを読み込みます。詳細については、以下の 入力形式 を参照してください。-z を含みます。

-z

<競合ファイル情報> セクションのファイル名を引用せず、各ファイル名を改行ではなくNUL文字で終了します。また、メッセージセクションを改行ではなくNUL文字で開始します。詳細については、以下の 出力 を参照してください。

--name-only

競合ファイル情報セクションで、競合ファイルに対して (モード、OID、ステージ、パス) のタプルリストを出力する代わりに、競合するファイル名のリストのみを提供します (複数の競合ステージがある場合でも、ファイル名を複数回リストしません)。

--[no-]messages

"Auto-merging <path>" や CONFLICT 通知などの情報メッセージを標準出力の末尾に書き込みます。指定しない場合、デフォルトではマージの競合がある場合はこれらのメッセージを含め、それ以外の場合は省略します。

--quiet

プログラムからのすべての出力を無効にします。終了ステータスのみに関心がある場合に役立ちます。これにより、merge-tree は競合が見つかったときに早期に終了でき、マージによって作成されたほとんどのオブジェクトの書き込みを回避できます。

--allow-unrelated-histories

merge-tree はデフォルトで、指定された2つのブランチに共通の履歴がない場合にエラーになります。このフラグを指定すると、そのチェックを上書きしてマージを続行できます。

--merge-base=<tree-ish>

<branch1> と <branch2> のマージベースを見つける代わりに、マージのマージベースを指定します。複数のベースの指定は現在サポートされていません。このオプションは --stdin と互換性がありません。

マージベースが直接提供されるため、<branch1> と <branch2> はコミットを指定する必要がなく、ツリーで十分です。

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

マージ戦略固有のオプションをマージ戦略に渡します。詳細については、git-merge[1] を参照してください。

出力

マージが成功した場合、git-merge-tree からの出力は単純に1行です。

<OID of toplevel tree>

競合するマージの場合、出力はデフォルトで次の形式になります。

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

これらについては以下で個別に説明します。

ただし、例外があります。--stdin が渡された場合、先頭に余分なセクションがあり、末尾にNUL文字があり、その後、入力の各行に対してすべてのセクションが繰り返されます。したがって、最初のマージが競合し、2番目のマージがクリーンである場合、出力は次の形式になります。

<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 が渡された場合

出力形式は、0個以上の競合情報レコードであり、それぞれが次の形式です。

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

ここで、<list-of-paths> は次の形式です。

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

そして、競合または情報メッセージ <conflict-message> の影響を受けるパス (またはブランチ名) を含みます。また、<conflict-type> は、次のような競合のタイプを説明する安定した文字列です。

  • "Auto-merging"

  • "CONFLICT (rename/delete)"

  • "CONFLICT (submodule lacks merge base)"

  • "CONFLICT (binary)"

そして <conflict-message> は、競合に関するより詳細なメッセージであり、多くの場合 (常にではありませんが) その中に <stable-short-type-description> が埋め込まれています。これらの文字列は将来のGitバージョンで変更される可能性があります。いくつかの例:

  • "Auto-merging <file>"

  • "CONFLICT (rename/delete): <oldfile> renamed…​but deleted in…​"

  • "Failed to merge submodule <submodule> (no merge base)"

  • "Warning: cannot merge binary files: <filename>"

-z が渡されない場合

このセクションは、前のセクションから区切るために空白行で始まり、その後、前のセクションからの <conflict-message> 情報のみを含みます (改行で区切られます)。これらはスクリプトで解析すべきではない不安定な文字列であり、人間が読むことを目的としています。また、<conflict-message> 文字列には通常改行が埋め込まれていませんが、時々埋め込まれている場合があることに注意してください。(ただし、自由形式のメッセージには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] で得られるのと同じ情報が含まれます。

  • 作業ツリーに書き込まれるもの (トップレベルツリーの OID)

  • インデックスに書き込まれる高次ステージ (競合ファイル 情報)

  • 標準出力に表示されるメッセージ (情報 メッセージ)

入力形式

git merge-tree --stdin の入力形式は完全にテキストベースです。各行は次の形式です。

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

1行が -- で区切られている場合、区切り文字の前の文字列はマージのマージベースを指定するために使用され、区切り文字の後の文字列はマージされるブランチを記述します。

避けるべき間違い

どのファイルが競合しているかを特定するために結果のトップレベルツリーを調べては**いけません**。代わりに、競合ファイル情報 セクションを解析してください。ツリー全体を解析するのは大規模なリポジトリでは恐ろしく遅いだけでなく、競合マーカーで表現できない競合タイプ (変更/削除、モード競合、両側でバイナリファイルが変更された、ファイル/ディレクトリの競合、さまざまな名前変更競合の組み合わせなど) が多数存在します。

競合ファイル情報 リストが空であるからといって、クリーンなマージと解釈しては**いけません**。終了ステータスを確認してください。個々のファイルに競合がなくてもマージに競合がある場合があります (このカテゴリに分類されるいくつかのディレクトリの名前変更競合タイプがあり、将来的には他の競合も追加される可能性があります)。

競合ファイル情報 リストから競合タイプを推測したり、ユーザーに推測させたりしては**いけません**。そこにある情報では十分ではありません。例: 名前変更/名前変更 (1対2) の競合 (両側で同じファイルが異なる名前に変更された場合) は、3つの異なるファイルに高次ステージ (ただし、それぞれに1つの高次ステージのみ) が存在することになり、どの3つのファイルが関連しているかを判断する方法 (情報 メッセージ セクションを除いて) はありません。ファイル/ディレクトリの競合も、ちょうど1つの高次ステージを持つファイルになります。ディレクトリの名前変更に関与している可能性のある競合 ("merge.directoryRenames" が設定されていないか "conflicts" に設定されている場合) も、ちょうど1つの高次ステージを持つファイルになります。すべての場合において、情報 メッセージ セクションには必要な情報がありますが、機械で解析できるように設計されていません。

競合ファイル情報 の各パスと、情報 メッセージ の論理的な競合が1対1マッピングであると仮定しては**いけません**。また、1対多マッピングでも、多対1マッピングでもありません。多対多マッピングが存在し、これは各パスが1つのマージで多くの論理競合タイプを持つことができ、各論理競合タイプが多くのパスに影響を与える可能性があることを意味します。

情報 メッセージ セクションにリストされているすべてのファイル名に競合があったと仮定しては**いけません**。"Auto-merging <file>" のように、競合のないファイルにもメッセージが含まれる場合があります。

ユーザーに競合を提示するために、競合ファイル情報 からOIDを取得して再マージすることは**避けてください**。これにより情報が失われます。代わりに、トップレベルツリーの OID 内で見つかったファイルのバージョンを検索して表示してください。特に、後者には元のブランチ/コミットがマージされたこと、および名前変更が関与している場合は元のファイル名が注釈として付けられた競合マーカーが含まれます。再マージするときに競合マーカーの注釈に元のブランチ/コミットを含めることはできますが、元のファイル名は 競合ファイル情報 からは利用できないため、ユーザーが競合を解決するのに役立つ情報が失われます。

非推奨の概要

概要 に従い、このドキュメントの残りの部分とは異なり、このセクションでは非推奨の --trivial-merge モードについて説明します。

オプションの --trivial-merge 以外に、このモードはオプションを受け入れません。

このモードは3つのtree-ishを読み込み、些細なマージ結果と競合するステージを半差分形式で標準出力に出力します。これは高レベルのスクリプトが消費して結果をインデックスにマージし直すために設計されたため、<branch1> と一致するエントリは省略されます。この2番目の形式の結果は、3方向の git read-tree -m が行うことと似ていますが、結果をインデックスに保存する代わりに、コマンドはエントリを標準出力に出力します。

この形式は適用範囲が限られているだけでなく (些細なマージでは個々のファイルのコンテンツマージ、名前変更検出、適切なディレクトリ/ファイル競合処理などを行うことができません)、出力形式も扱いにくく、成功したマージであっても (特に大規模なリポジトリで作業している場合) 最初の形式よりも一般的にパフォーマンスが低くなります。

GIT

git[1]スイートの一部

scroll-to-top