個別のファイルの名前変更をチェックする diffcore-rename の名前変更検出ロジックもディレクトリ名前変更検出ロジックに集約され、そして、 merge-ort または merge-recursive で名前変更の組み合わせがディレクトリ全体の名前変更を示しているケースについて分析されます。

Scope of abilities

例から始めるのがおそらく最も簡単です:

  • x/a 、x/b 、x/c のすべてが z/a 、 z/b 、z/c に移動した場合、ディレクトリ x 全体が z に移動したことをヒントにして、 z/d に移動したくなる可能性があります。

ただし、以下のようなさらに興味深い可能性があります:

  • 履歴の一方では x→z に名前変更され、もう一方のファイルの名前は x/e に変更されるため、名前の変更が z/e になるように、マージで他動的(transitive)な名前変更を行う必要があります。

  • 履歴の片側は x → z と名前変更しますが、x内のすべてのファイルの名前も変更します。 たとえば、 x/a → z/alpha 、x/b → z/bravo などです。

  • xy の両方が単一のディレクトリ z にマージされ、ディレクトリの名前変更が x→z と y→z の両方で検出されます。

  • ディレクトリ内のすべてのファイルが同じ場所に名前変更されているわけではありません。 つまり、おそらく x 内のほとんどのファイルは z の下にありますが、いくつかは w の下にあります。

  • 名前が変更されているディレクトリ。これには、まったく別の場所に名前が変更されたサブディレクトリも含まれています。 (そして、おそらく内部ディレクトリ自体には、さらに他の場所に名前が変更された内部ディレクトリが含まれていました)。

  • 上記の組み合わせ。さまざまな興味深いケースについては、 t/t6423-merge-rename-directories.sh を参照してください。

Limitations — applicability of directory renames

インデックスで表すことができない、またはユーザーが理解して解決しようとするのに複雑すぎる可能性のある競合が発生する境界ギリギリのケース(edge case)とめったに発生しない厄介なケース(corner case)を防ぐために、ディレクトリ名変更の検出が適用される場合の基本的なルール制限は、以下のとおりです:

  1. 特定のディレクトリがマージの両側にまだ存在する場合、名前が変更されたとは見なされません。

  2. 名前を変更するファイルのサブセットにファイルまたはディレクトリが邪魔になっている(または互いに邪魔になる)場合は、それらの特定のサブパスのディレクトリ名を「オフ」(turn off)にして、競合をユーザーに報告します。

  3. 履歴の反対側がディレクトリの名前を履歴のあなた側で別の名前に変更したパスに変更した場合、暗黙的なディレクトリの名前変更については、履歴の反対側からの特定の名前変更を無視します(ただし、ユーザーに警告します)。

Limitations — detailed rules and testcases

t/t6423-merge-rename-directories.sh には、上記ルールを生成および調査する広範なテストと解説が含まれています。 また、いくつかの追加ルールもリストされています。

  1. 名前の変更によってディレクトリが2つ以上に分割された場合、名前の変更が最も多いディレクトリが「勝ち」(wins)です。

  2. 履歴の反対側が名前変更を行っている場合にのみ、暗黙的なディレクトリ名変更をディレクトリに適用します。

  3. 新しいパスが追加されていないディレクトリに対して、ディレクトリ名変更の検出を実行しないでください。

Limitations — support in different commands

ディレクトリの名前変更の検出は、「merge」および「cherry-pick」でサポートされています。 他のgitコマンドでは、ディレクトリ名の変更の検出が制限されているか、まったくサポートされていないことにユーザーは驚くかもしれません:

diff

人々は過去に git diff がディレクトリの名前変更を検出し、どういうわけかその出力を単純化することを要求しました。 これが望ましいかどうか、または出力をどのように簡略化する必要があるかは明確ではないため、これは単に実装されませんでした。 また、diffcore-rename には、ディレクトリの名前変更を検出するためのロジックのほとんどがありますが、一部のロジックは、 merge-ort や merge-recursive 内にあります。 diffでディレクトリ名変更の検出を完全にサポートするには、ロジックの残りの少しをdiff機構にコピーまたは移動する必要があります。

am

git-amは、git-applyを呼び出す代わりに、完全な3方向マージを回避しようとします。 これにより、名前の変更をまったく検出できなくなり、ディレクトリの名前変更の検出が無効になる可能性があります。 ただし、フォールバックがあります。 最初のgit-applyが失敗し、ユーザーが-3オプションを指定した場合、git-amは3方向マージにフォールバックします。 ただし、git-amには、「実際に」3方向マージを実行するために必要な情報がありません。 代わりに、 build_fake_ancestor() を使用して、ディレクトリ名の変更を検出するために重要である可能性のあるファイルが存在しないマージベースを取得しなければなりません。

rebase

amベースのリベースは、最初に一連のパッチを生成し(元のコミットが何であったかを記録しなくなったため、実際のマージベースを見つけるために必要な情報がない)、次にgit-amを呼び出すことで機能するためです。 これは、amベースのリベースがディレクトリの名前変更を常に正常に検出するとは限らないことを意味します(上記の「am」セクションを参照)。 マージベースのリベース(rebase -m)およびチェリーピックベースのリベース(rebase -i)は、この欠点の影響を受けず、ディレクトリ名変更の検出を完全にサポートします。