6

s やs と同じように、インデックスに何がgit含まれているかについてはあいまいな考えがありますが、. 私は特に、マージが失敗した場合 (たとえば、何らかの競合が原因で) にインデックスが保持するものを知りたいと思っています。git-addgit-commitgit-merge

4

1 に答える 1

11

任意のパスに対して、インデックスには最大 4 つの「バージョン番号」があり、0 (ゼロ) から 3 までの番号が付けられています。すべてのエントリに実際に存在するかのようにそれらを「スロット」と呼び、簡単にインデックスを付けます (この実際には追加のバージョンは必要な場合にのみ動的に導入されますが。これらの「仮想スロット」は「空」である可能性があり、ファイルが存在しないことを意味します。

(実際には、エントリがインデックスに作成されると、CE_REMOVED必要に応じてフラグ ビットでマークされます。これは、ファイルでいっぱいのディレクトリ全体が「削除済み」とマークされ、次の名前でファイルが作成される可能性があるため、毛むくじゃらになります。以前のディレクトリと「追加済み」とマークされた. 代わりに、固定スロットがあると仮定しましょう. :-) )

スロット #0 は、「通常の」、競合のない、万事順調なエントリです。これには、リポジトリに格納されているファイルの一連のキャッシュ データ、パス名、および blob-ID (SHA-1) が含まれています。

マージが成功すると、すべて「通常どおり」になるため、唯一の特殊なケースはマージの競合です。スロット 1、2、および/または 3 が空でない場合、マージは「競合」します。メカニズムのほとんどをスキップすると、何が起こるかというと、これです。マージでは、すべてのスロットに「最新」の名前が使用されます。

  • スロット 0 は空のままです (競合を解決するまで「コミット」することはできません。競合を解決するまでは、ファイルを本当に削除したい場合を除き、このスロットはもう空ではありません)。
  • スロット 1 (「ベース」) には、共通の祖先バージョンが入ります。ファイルが (両方のリビジョンで) 新しい場合、このスロットは空です。
  • スロット 2 (「私たち」) は、ターゲット (HEAD基になるマージ機構の一部を手動で呼び出していない限り) バージョンで埋められます。/ target-of-merge でファイルが削除された場合、HEAD代わりにこのスロットは空になります。
  • スロット 3 ("theirs") には、マージされるバージョンが入ります。マージ中のリビジョンでファイルが削除された場合、このスロットは空です。

競合を解決して「git add」すると、#0 スロットは「追加」したもので埋められ、#1 から #3 のエントリが消去されます。または、競合しているファイルを「git rm」した場合は、他のステージ エントリは引き続き削除されますが、#0 スロットは空のままになり、競合も解決されます。

より具体的には、次の 2 つのファイルを持つ共通の祖先があるとします。

gronk
flibby

あなたはブランチcleanupにいて、名前を に変更gronkbreem、その と の両方を編集しましたflibby。あなたは、彼らが変更したが名前を変更しなかったgit merge work場所で、 を削除することにしました。他のいくつかのファイルはきれいにマージされました。gronkflibby

インデックスには、 の 3 つのバージョンbleemと の 2 つのバージョンが含まれflibbyます。

$ git checkout cleanup
Switched to branch 'cleanup'
$ git merge work
CONFLICT (modify/delete): flibby deleted in work and modified
in HEAD. Version HEAD of flibby left in tree.
Auto-merging bleem
CONFLICT (content): Merge conflict in bleem
Automatic merge failed; fix conflicts and then commit the result.
$ git ls-files --stage
100644 4362aba7f3b7abf2da0d0ed558cbf5bc0d12e4b0 1   bleem
100644 49db92a61392e9fd691c4af6e1221f408452a128 2   bleem
100644 04b399c8fe321902ce97a1538248878756678ca2 3   bleem
100644 366b52546711401122b791457793a38c033838dd 1   flibby
100644 6fecb1480f45faaabc31b18c91262d03d3767cde 2   flibby
100644 7129c6edb96d08bb44ca1025eb5ae41d41be8903 0   x.txt

bleemwithのオリジナル (ベース) バージョンを見ることができますgit show :1:bleem。これはgronk基本バージョン (workこの場合は同様に) で呼び出されましたが、現在はbleemgit が in に名前が変更されたgronkと認識しているため、呼び出されています。(この場合のように、Git はマージ ベース間の名前変更を検出し、必要に応じて同じ名前変更を適用します。)bleemcleanupHEADwork

同様に、 または を含むバージョンと、 、 、または のいずれかを含むバージョンを確認できます(スロット2にはworkakaバージョンが含まれ、の名前に従って名前が付けられます)。git show :3:bleemgit show work:gronkHEADgit show HEAD:bleemgit show cleanup:bleemgit show :2:bleemHEADcleanupHEAD

flibbyただし、については、 で削除されたworkため、「彼らの」(スロット 3) バージョンはありません。

競合を解決するには、スロット 0 のエントリを更新して 1 ~ 3 のエントリを削除するだけgit addですgit rm。もちろん、 ではgit add、スロット 0 に入れるのは現在の作業ディレクトリにあるものなので、通常は最初にファイルを編集する必要があります。

ちなみに、スロット 2 と 3 には、上記で「私たちのもの」と「彼らのもの」というラベルを付けました。これはgit checkout、それらを同様に処理する方法です (git checkout --oursそしてgit checkout --theirs、バージョン 2 または 3 をスロット 0 に書き込むことができます。このようなチェックアウトは、ほとんどのチェックアウトと同様に、他のスロットも「消去」し、競合を解決します)。ただし、リベースでは、HEADブランチは実際にはリベース先のブランチであり、「彼らの」バージョンはリベース先のブランチです。したがって、私の意見では、私たちの/彼らの用語はそれほど素晴らしいものではありません.リベース中に元に戻すのは簡単すぎます.

また、競合するマージの最中にある場合は、必要に応じてスロット 0 を消去し、スロット 1 ~ 3 のバージョンを「復活」させることによって、マージの競合を「再作成」することに注意してくださいgit checkout -m(競合するマージを作成します)。ファイルを作業ディレクトリにコピーし、merge.conflictstyle設定の変更にも従います)。

于 2014-01-23T14:40:38.387 に答える