SYNOPSIS

git read-tree [(-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>)
                [-u | -i]] [--index-output=<file>] [--no-sparse-checkout]
                (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])

DESCRIPTION

<tree-ish> によって指定されたツリー情報をインデックスに読み込みますが、「キャッシュする」ファイルは実際には「更新」されません。 (git-checkout-index(1) 参照)

オプションで、ツリーをインデックスにマージしたり、早送り(fast-forward)(つまり、2方向)マージを実行したり、 -m フラグを使用して3方向マージを実行したりできます。 -u フラグを -m と一緒に使用すると、マージの結果で作業ツリー内のファイルも更新されます。

Only trivial merges are done by git read-tree itself. Only conflicting paths will be in an unmerged state when git read-tree returns.

OPTIONS

-m

Perform a merge, not just a read. The command will refuse to run if your index file has unmerged entries, indicating that you have not finished a previous merge you started.

--reset

Same as -m, except that unmerged entries are discarded instead of failing. When used with -u, updates leading to loss of working tree changes or untracked files or directories will not abort the operation.

-u

After a successful merge, update the files in the work tree with the result of the merge.

-i

Usually a merge requires the index file as well as the files in the working tree to be up to date with the current head commit, in order not to lose local changes. This flag disables the check with the working tree and is meant to be used when creating a merge of trees that are not directly related to the current working tree status into a temporary index file.

-n
--dry-run

Check if the command would error out, without updating the index or the files in the working tree for real.

-v

Show the progress of checking files out.

--trivial

Restrict three-way merge by git read-tree to happen only if there is no file-level merging required, instead of resolving merge for trivial cases and leaving conflicting files unresolved in the index.

--aggressive

Usually a three-way merge by git read-tree resolves the merge for really trivial cases and leaves other cases unresolved in the index, so that porcelains can implement different merge policies. This flag makes the command resolve a few more cases internally:

  • 一方の側がパスを削除し、もう一方の側がパスを変更しないままにする場合。 解決策は、そのパスを削除することです。

  • 両側でパスを削除したとき。 解決策は、そのパスを削除することです。

  • 両側で同じようにパスを追加する場合。 解決策は、そのパスを追加することです。

--prefix=<prefix>

Keep the current index contents, and read the contents of the named tree-ish under the directory at <prefix>. The command will refuse to overwrite entries that already existed in the original index file.

--index-output=<file>

Instead of writing the results out to $GIT_INDEX_FILE, write the resulting index in the named file. While the command is operating, the original index file is locked with the same mechanism as usual. The file must allow to be rename(2)ed into from a temporary file that is created next to the usual index file; typically this means it needs to be on the same filesystem as the index file itself, and you need write permission to the directories the index file and index output file are located in.

--[no-]recurse-submodules

Using --recurse-submodules will update the content of all active submodules according to the commit recorded in the superproject by calling read-tree recursively, also setting the submodules' HEAD to be detached at that commit.

--no-sparse-checkout

Disable sparse checkout support even if core.sparseCheckout is true.

--empty

Instead of reading tree object(s) into the index, just empty it.

-q
--quiet

Quiet, suppress feedback messages.

<tree-ish#>

読み取られる/マージされる ツリーオブジェクトのID。

MERGING

-m が指定されている場合、 git read-tree は3種類のマージを提供します。1つのツリーのみが指定されている場合は単一のツリーマージ(single tree merge)、2つのツリーとの早送り(fast-forward)マージ(two tree merge)、3つ以上のツリーが指定されている3方向マージです(3-way merge)。

Single Tree Merge

ツリーが 1 つだけ指定されている場合、 git read-tree はユーザーが -m を指定しなかったかのように動作しますが、 元のインデックスに特定のパス名のエントリがあり、パスの内容が読み取られるツリーと一致する場合、インデックスの統計情報が使用されます。(言い換えれば、インデックスの stat() はマージされたツリーのものよりも優先されます)。

つまり、 git read-tree -m <newtree> の後に git checkout-index -f -u -a を実行すると、 git checkout-index は本当に変更されたものだけをチェックアウトします。

これは、 git read-tree の後に git diff-files を実行したときに不要な誤検出を避けるために使用します。

Two Tree Merge

通常、これは git read-tree -m $H $M として呼び出されます。ここで、$H は現在のリポジトリのヘッドコミットであり、$M は $H の前にある外部ツリーのヘッドです(つまり、早送り(fast-forward)の状況にあります)。

2つのツリーが指定されている場合、ユーザーは git read-tree に以下のように指示している事になります:

  1. 現在のインデックスと作業ツリーは$Hから派生していますが、 ユーザーは$H以降にローカルで変更を加えている可能性があります。

  2. ユーザーは$Mに早送り(fast-forward)したいと考えています。

この場合、 git read-tree -m $H $M コマンドは、この「マージ」の結果としてローカルの変更が失われないことを確認します。 「繰越」(carry forward)ルールは次のとおりです。「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 を実行することで、行った「ローカル変更」のどれが繰り越されたかを確認できます。 これは、このような2つのツリーがマージされる前に git diff-index --cached $H が生成したものと必ずしも一致しないことに注意してください。 これは、上記ケース18と19が原因です — すでに$Mに変更があった場合(たとえば、パッチ形式で電子メールで取得した場合)、 git diff-index --cached $H は、このマージの前に変更について通知しますが、 2ツリーのマージ後の git diff-index --cached $M 出力には表示されません。

上記ケース3は少しトリッキーで、説明が必要です。 このルールの結果は、論理的には、ユーザーがパスの削除をステージングしてから新しいブランチに切り替えた場合に、パスを削除することです。 ただし、これにより最初のチェックアウトが行われないため、インデックスの内容が空の場合にのみM(新しいツリー)を使用するようにルールが変更されます。 それ以外の場合、パスの削除は、$Hと$Mが同じである限り保持されます。

3-Way Merge

各「インデックス」エントリには、2ビット相当の「ステージ」状態があります。ステージ0は通常のステージであり、通常の使用で見られる唯一のステージです。

しかしながら、あなたが3つのツリーで git read-tree を実行すると、「ステージ」は1から始まります。

これはあなたが以下のようにできることを意味します

$ git read-tree -m <tree1> <tree2> <tree3>

そうすると、「stage1」にすべての<tree1>エントリ、「stage2」にすべての<tree2>エントリ、「stage3」にすべての<tree3>エントリを持つインデックスが作成されます。 別のブランチを現在のブランチにマージする場合、共通の祖先ツリーを<tree1>として、現在のブランチヘッドを<tree2>として、他のブランチヘッドを<tree3>として使用します。

さらに、 git read-tree には、以下のような特殊なケースのロジックがあります。以下の状態ですべての点で一致するファイルを見つけると、「折りたたみ」(collapse)して stage0 に戻します:

  • ステージ2と3は同一です。 どちらか一方を取ります(違いはありません。ステージ2のブランチとステージ3のブランチで同じ作業が行われました)

  • ステージ1とステージ2は同じで、ステージ3は異なります。ステージ3を取得します(ステージ2のブランチは、ステージ3のブランチが作業している間、ステージ1の祖先以降何もしませんでした)

  • ステージ1とステージ3は同じで、ステージ2は異なります。ステージ2を使用します(私達は何もしなかったのに何かをしました)

git write-tree コマンドは、無意味なツリーの書き込みを拒否し、ステージ0ではない単一のエントリを検出すると、マージされていないエントリについて文句を言います。

ええ、これはすべてまったく無意味なルールのコレクションのように聞こえますが、実際には、高速マージを実行するために必要なものです。 異なるステージは、「結果ツリー」(result tree)(ステージ0、別名「merged」)、元のツリー(original tree)(ステージ1、別名「orig」)、およびマージしようとしている2つのツリー(それぞれステージ2と3)を表します。

すでに入力されているインデックスファイルを使用して3方向マージを開始する場合、ステージ1、2、および3の順序(つまり、3つの<tree-ish>コマンドライン引数の順序)は重要です。アルゴリズムの仕組みの概要は以下のとおりです:

  • ファイルが3つのツリーすべてに同じ形式で存在する場合、ファイルは git read-tree によって自動的に「マージされた」状態(merged state)に折りたたまれ(collapse)ます。

  • 3つのツリーに違いがあるファイルは、インデックス内の別々のエントリとして残ります。0以外のステージを削除し、マージされたバージョンを挿入する方法を決定するのは、「磁器ポリシー」(porcelain policy)次第です。

  • インデックスファイルはこれらすべての情報を保存および復元するため、段階的にマージできますが、ステージ 1/2/3 のエントリ(つまり、「マージされていないエントリ」)がある限り、結果を書き込むことはできません。したがって、マージアルゴリズムは非常に単純になります:

    • あなたはインデックスを順番に歩きます。ステージ0のすべてのエントリはすでに完了しているため、無視します。

    • 「stage1」が見つかったが、一致する「stage2」または「stage3」がない場合は、両方のツリーから削除されたことがわかり(元のツリーにのみ存在した)、そのエントリを削除します。

    • 一致する「stage2」および「stage3」ツリーが見つかった場合は、それらの1つを削除し、もう1つを「stage0」エントリに変換します。 一致する「stage1」エントリも存在する場合は削除します。 .. すべての通常のtrivial(些細な)ルール ..

この最後のステップを実行するには、通常、提供された git merge-one-file とともに git merge-index を使用します。 スクリプトは、各パスをマージし、マージが正常に終了すると、作業ツリー内のファイルを更新します。

すでに入力されているインデックスファイルを使用して3方向マージを開始すると、それが作業ツリー内のファイルの状態を表していると見なされ、変更がインデックスファイルに記録されていないファイルを作成することもできます。 さらに、この状態はステージ2ツリーから「派生」していると想定されます。 元のインデックスファイルでステージ2と一致しないエントリが見つかった場合、3方向マージは実行を拒否します。

これは、進行中の変更が失われたり、無関係なマージコミットでランダムな変更が混在したりするのを防ぐために行われます。ここでは説明のために、あなたのリポジトリに最後にコミットされたものから開始するとします:

$ JC=`git rev-parse --verify "HEAD^0"`
$ git checkout-index -f -u -a $JC

あなたは git update-index を実行せずに、ランダムに編集します。 そして、あなたは彼(him)からpullしてからあなたの「上流」のツリーの先端が進んだことに気づきます:

$ git fetch git://.... linus
$ LT=`git rev-parse FETCH_HEAD`

作業ツリーはまだHEAD($JC)に基づいていますが、あなたはそれ以降、いくつか編集しています。3方向マージは、 $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 は大声で文句を言い、何も変更せずに失敗します)。 このような場合は、実行中の作業を続行し、作業ツリーの準備ができたら(つまり、進行中の作業が終了したら)、マージを再試行します。

SPARSE CHECKOUT

注意: git-update-index(1)read-tree の skip-worktree 機能は、git-sparse-checkout(1) の導入以前の機能です。 ユーザーは、 sparse-checkout/skip-worktree 関連の需要に対して、 これらの配管コマンドよりも優先して sparse-checkout コマンドを使用することをお勧めします。 ただし、以下の情報は、sparse-checkout コマンドの非円錐(non-cone)モードで使用されるパターン・スタイルを理解しようとしているユーザーにとって役立つ場合があります。

「スパースチェックアウト」(Sparse checkout)を使用すると、作業ディレクトリにまばらに(sparsely)データを入力できます。 skip-worktreeビット(git-update-index(1) 参照)を使用して、作業ディレクトリ内のファイルを確認する価値があるかどうかをGitに通知します。

git read-tree およびその他のマージベースコマンド(git mergegit checkout …)は、skip-worktreeビットマップと作業ディレクトリの更新を維持するのに役立ちます。$GIT_DIR/info/sparse-checkout は、skip-worktree参照ビットマップを定義するために使用されます。 git read-tree が作業ディレクトリを更新する必要がある場合、このファイルに基づいてインデックスのskip-worktreeビットをリセットします。これは、 .gitignore ファイルと同じ構文を使用します。 エントリがこのファイルのパターンとマッチする場合、または、エントリが作業ツリーに存在するファイルに対応する場合、 skip-worktree はそのエントリに設定されません。 それ以外の場合は、skip-worktree が設定されます。

次に、新しいskip-worktree値を前の値と比較します。 skip-worktreeがsetからunsetに変わると、対応するファイルが追加されます。 unsetからsetに変わると、そのファイルは削除されます。

通常、 $GIT_DIR/info/sparse-checkout はどのファイルが含まれているかを指定するために使用されますが、否定パターンを使用して、どのファイルが含まれていないかを指定することもできます。 たとえば、ファイル unwanted を削除するには以下のようにします:

/*
!unwanted

もう1つの注意が必要なのは、スパースチェックアウトが不要になったときに作業ディレクトリを完全に再設定することです。 skip-worktreeビットはまだインデックスにあり、作業ディレクトリはまだまばらに(sparsely)配置されているため、「スパースチェックアウト」を無効にすることはできません。 以下のように、作業ディレクトリに $GIT_DIR/info/sparse-checkout ファイルの内容を再入力する必要があります:

/*

その後、スパースチェックアウトを無効にできます。 git read-tree および同様のコマンドでのスパースチェックアウトのサポートはデフォルトで無効になっています。 スパースチェックアウトをサポートするには、 core.sparseCheckout をオンにする必要があります。

SEE ALSO

GIT

Part of the git(1) suite