gitの「rebase --preserve-merges」は正確には何をするのですか(なぜですか?)


355

コマンドに関するrebase Gitのドキュメントは非常に簡潔です。

--preserve-merges
    Instead of ignoring merges, try to recreate them.

This uses the --interactive machinery internally, but combining it
with the --interactive option explicitly is generally not a good idea
unless you know what you are doing (see BUGS below).

では、実際に使用すると--preserve-mergesどうなりますか?デフォルトの動作(そのフラグなし)とどう違うのですか?マージなどを「再作成」するとはどういう意味ですか。


20
警告:Git 2.18(2018年第2四半期、5年後)以降、git --rebase-merges最終的に古いが置き換えられgit --preserve-mergesます。以下の私の回答を
VonC、2018年

回答:


464

通常のgit rebaseと同様に、git withは、--preserve-merges最初にコミットグラフの一部で行われたコミットのリストを識別し、次にそれらのコミットを別の部分の上に再生します。--preserve-mergesどのコミットが再生用に選択されるか、およびそのコミットがマージコミットでどのように機能するかを考慮した違い。

通常のリベースとマージ保持リベースの主な違いについてより明確にするために:

  • 通常のリベースはマージコミットを完全に無視するのに対し、マージ保持リベースは(一部の)マージコミットを再生する用意があります。
  • マージコミットを再生する用意があるため、マージ保持リベースは、マージコミットを再生することの意味を定義し、余分なしわに対処する必要があります。
    • 概念的に最も興味深い部分は、おそらく新しいコミットのマージの親がどうあるべきかを選択することです。
    • マージコミットを再生するには、特定のコミット(git checkout <desired first parent>)を明示的にチェックアウトする必要もありますが、通常のリベースではそれを心配する必要はありません。
  • マージ保持リベースは、再生のためにコミットのより浅いセットを考慮します。
    • 特に、最新のマージベース以降に行われたコミットの再生のみが考慮されます。つまり、2つのブランチが分岐した最新の時間ですが、通常のリベースは、2つのブランチが分岐した最初のコミットに戻ってコミットを再生する場合があります。
    • 暫定的で不明確になるために、これは最終的に、マージコミットにすでに「組み込まれている」「古いコミット」の再生を排除するための手段だと思います。

最初に--preserve-merges、リベースが行うことを「十分に正確に」説明しようと試み、次にいくつかの例を示します。もちろん、それがより有用であると思われる場合は、例から始めることができます。

「簡単」のアルゴリズム

本当に雑草に入りたい場合は、gitソースをダウンロードしてファイルを調べてくださいgit-rebase--interactive.sh。(RebaseはGitのCコアの一部ではなく、bashで記述されています。また、舞台裏では、「インタラクティブなrebase」とコードを共有しています。)

しかし、ここで私はそれの本質であると思うものをスケッチします。考えることの数を減らすために、私はいくつかの自由を取りました。(たとえば、計算が行われる正確な順序を100%の精度でキャプチャしようとせず、一部のそれほど中心的ではないトピック、たとえば、ブランチ間ですでに厳選されているコミットについてどうするかを無視します)。

最初に、マージを保持しないリベースはかなり単純であることに注意してください。それは多かれ少なかれです:

Find all commits on B but not on A ("git log A..B")
Reset B to A ("git reset --hard A") 
Replay all those commits onto B one at a time in order.

リベース--preserve-mergesは比較的複雑です。これは、非常に重要と思われるものを失うことなく作成できたのと同じくらい簡単です。

Find the commits to replay:
  First find the merge-base(s) of A and B (i.e. the most recent common ancestor(s))
    This (these) merge base(s) will serve as a root/boundary for the rebase.
    In particular, we'll take its (their) descendants and replay them on top of new parents
  Now we can define C, the set of commits to replay. In particular, it's those commits:
    1) reachable from B but not A (as in a normal rebase), and ALSO
    2) descendants of the merge base(s)
  If we ignore cherry-picks and other cleverness preserve-merges does, it's more or less:
    git log A..B --not $(git merge-base --all A B)
Replay the commits:
  Create a branch B_new, on which to replay our commits.
  Switch to B_new (i.e. "git checkout B_new")
  Proceeding parents-before-children (--topo-order), replay each commit c in C on top of B_new:
    If it's a non-merge commit, cherry-pick as usual (i.e. "git cherry-pick c")
    Otherwise it's a merge commit, and we'll construct an "equivalent" merge commit c':
      To create a merge commit, its parents must exist and we must know what they are.
      So first, figure out which parents to use for c', by reference to the parents of c:
        For each parent p_i in parents_of(c):
          If p_i is one of the merge bases mentioned above:
            # p_i is one of the "boundary commits" that we no longer want to use as parents
            For the new commit's ith parent (p_i'), use the HEAD of B_new.
          Else if p_i is one of the commits being rewritten (i.e. if p_i is in R):
            # Note: Because we're moving parents-before-children, a rewritten version
            # of p_i must already exist. So reuse it:
            For the new commit's ith parent (p_i'), use the rewritten version of p_i.
          Otherwise:
            # p_i is one of the commits that's *not* slated for rewrite. So don't rewrite it
            For the new commit's ith parent (p_i'), use p_i, i.e. the old commit's ith parent.
      Second, actually create the new commit c':
        Go to p_1'. (i.e. "git checkout p_1'", p_1' being the "first parent" we want for our new commit)
        Merge in the other parent(s):
          For a typical two-parent merge, it's just "git merge p_2'".
          For an octopus merge, it's "git merge p_2' p_3' p_4' ...".
        Switch (i.e. "git reset") B_new to the current commit (i.e. HEAD), if it's not already there
  Change the label B to apply to this new branch, rather than the old one. (i.e. "git reset --hard B")

--onto C引数を使用したリベースは非常によく似ています。Bのヘッドでコミット再生を開始するのではなく、代わりにCのヘッドでコミット再生を開始します。(そしてB_newの代わりにC_newを使用してください。)

例1

たとえば、コミットグラフを取る

  B---C <-- master
 /                     
A-------D------E----m----H <-- topic
         \         /
          F-------G

mは、親EおよびGとのマージコミットです。

通常のマージを維持しないリベースを使用して、マスター(C)の上にトピック(H)をリベースするとします。(たとえば、checkout topic; rebase master)。その場合、gitは次のコミットを選択して再生します。

  • Dを選ぶ
  • Eを選択
  • Fを選ぶ
  • Gを選択
  • Hを選択

そして、次のようにコミットグラフを更新します:

  B---C <-- master
 /     \                
A       D'---E'---F'---G'---H' <-- topic

(D 'はDの再生された同等物などです。)

マージコミットmは再生用に選択されていないことに注意してください。

代わりに--preserve-merges、Cの上にHのリベースを実行した場合(たとえば、checkout topic; rebase --preserve-merges master)。この新しいケースでは、gitは次のコミットを選択して再生します。

  • Dを選ぶ
  • Eを選択
  • Fを選択(「サブトピック」ブランチのDに)
  • Gを選択(「サブトピック」ブランチのFに)
  • マージブランチ「サブトピック」をトピックに選択
  • Hを選択

今度はm リプレイ選ばれました。また、マージの親EとGは、マージコミットmの前に含める対象として選択されたことにも注意してください。

結果のコミットグラフは次のとおりです。

 B---C <-- master
/     \                
A      D'-----E'----m'----H' <-- topic
        \          / 
         F'-------G'

繰り返しますが、D 'はDのチェリーピック(つまり、再作成)バージョンです。E'も同様です。マスター以外のすべてのコミットがリプレイされました。EとG(mのマージ親)の両方がE 'とG'として再作成され、m 'の親として機能します(リベース後も、ツリー履歴は同じままです)。

例2

通常のリベースとは異なり、マージ保持リベースは上流ヘッドの複数の子を作成できます。

たとえば、次のことを考慮してください。

  B---C <-- master
 /                     
A-------D------E---m----H <-- topic
 \                 |
  ------- F-----G--/ 

C(マスター)の上にH(トピック)をリベースする場合、リベースのために選択されるコミットは次のとおりです。

  • Dを選ぶ
  • Eを選択
  • Fを選ぶ
  • Gを選択
  • ピックm
  • Hを選択

結果は次のようになります:

  B---C  <-- master
 /    | \                
A     |  D'----E'---m'----H' <-- topic
       \            |
         F'----G'---/

例3

上記の例では、マージコミットとその2つの親の両方が、元のマージコミットにある元の親ではなく、再生されたコミットです。ただし、他のリベースでは、再生されたマージコミットは、マージ前にすでにコミットグラフにあった親で終了する可能性があります。

たとえば、次のことを考慮してください。

  B--C---D <-- master
 /    \                
A---E--m------F <-- topic

トピックをマスターにリベースする場合(マージを保持)、再生へのコミットは次のようになります

  • マージコミットmを選択
  • Fを選ぶ

書き換えられたコミットグラフは次のようになります。

                     B--C--D <-- master
                    /       \             
                   A-----E---m'--F'; <-- topic

ここで、再生されたマージコミットm 'は、コミットグラフに既存の親、つまりD(マスターのHEAD)とE(元のマージコミットmの親の1つ)を取得します。

実施例4

マージ保持リベースは、特定の「空のコミット」の場合に混乱する可能性があります。少なくともこれは、一部の古いバージョンのgit(たとえば、1.7.8)にのみ当てはまります。

このコミットグラフを見てください:

                   A--------B-----C-----m2---D <-- master
                    \        \         /
                      E--- F--\--G----/
                            \  \
                             ---m1--H <--topic

コミットm1とm2の両方にBとFからのすべての変更が組み込まれている必要があることに注意してください。

git rebase --preserve-mergesH(トピック)をD(マスター)に変換しようとすると、次のコミットが再生用に選択されます。

  • m1を選択
  • Hを選択

m1で統合された変更(B、F)はすでにDに組み込まれていることに注意してください(m2はBとFの子をマージするため、これらの変更はすでにm2に組み込まれているはずです)。 Dは、おそらく何もしないか、空のコミット(つまり、連続するリビジョン間の差分が空のコミット)を作成する必要があります。

ただし、代わりに、gitはDの上でm1を再生する試みを拒否する場合があります。次のようなエラーが発生する可能性があります。

error: Commit 90caf85 is a merge but no -m option was given.
fatal: cherry-pick failed

gitにフラグを渡すのを忘れたように見えますが、根本的な問題は、gitが空のコミットの作成を嫌うことです。


6
私は気づいたgit rebase --preserve-mergesある非常に遅くなるよりもrebaseなし--preserve-merges。それは正しいコミットを見つけることの副作用ですか?スピードアップするためにできることはありますか?(ちなみに…非常に詳細な回答に感謝します!)
David Alan Hjelle 2013

7
常に--preserve-mergesを使用する必要があるようです。そうしないと、履歴が失われる可能性があります。つまり、マージがコミットされます。
DarVar

19
@DarVarリベースの履歴は常に失われます。なぜなら、実際の場所とは異なるコードベースに加えられた変更を主張するからです。
クロニアル

5
これはまだ「暫定回答」ですか?
Andrew Grimm

5
@Chronialもちろん、そうです。リベースには常に失われた履歴が組み込まれますが、おそらくDarVarは履歴を失うだけでなく、コードベースを変更するという事実をほのめかしていました。競合の解決には、リベースを実行するすべての可能な方法で失われる情報が含まれています。あなたはいつもそれをやり直す必要があります。gitに競合解決をやり直させる方法は本当にありませんか?マージコミットをgitチェリーピックできないのはなぜですか?
Nils_M

94

Git 2.18(2018年第2四半期)では--preserve-merge、新しいオプションを追加することでオプションを大幅に改善します。

git rebase」学習「--rebase-mergesするために」コミットグラフの他の場所の全体のトポロジーを移植

(注:Git 2.22、2019年第2四半期は実際には非推奨 --preserve-mergeになり、Git 2.25、2020年第1四半期は " git rebase --help"出力でのアドバタイズを停止します

参照25cff9fをコミットし7543f6fをコミットし1131ec9をコミットし7ccdf65をコミットし537e7d6をコミットしa9be29cをコミットし8f6aed7をコミットし1644c73をコミットしd1e8b01をコミットし4c68e7dをコミットし9055e40をコミットしcb5206eをコミットしa01c2a5をコミットし2f6b1d1をコミットしbf5c057をコミット(2018年4月25日)ヨハネスSchindelin( )dscho
参照してくださいf431d73コミットすることにより(2018年4月25日)ステファンBellerを(stefanbeller
Phillip Wood(によるコミット2429335(2018年4月25日)を 参照してください。(による合併Junio C浜野- -2c18e6aコミット、2018年5月23日)をphillipwood
gitster

pull--rebase-mergesブランチトポロジの再作成を受け入れる

コマンドに オプションをpreserve渡すだけのモードと同様に、モードは--preserve-mergesオプションを渡すだけ です。rebasemerges--rebase-merges

これにより、ユーザーは、新しいコミットをフラット化せずにプルするときに、重要なコミットトポロジを簡単にリベースできます。


git rebaseマニュアルページに、マージによる履歴のリベースに特化し完全なセクションが追加されました。

エキス:

開発者がマージコミットの再作成を望む正当な理由があります。複数の相互に関連するブランチで作業するときにブランチ構造(または「コミットトポロジ」)を維持するためです。

次の例では、開発者はボタンの定義方法をリファクタリングするトピックブランチと、そのリファクタリングを使用して「バグの報告」ボタンを実装する別のトピックブランチで作業します。
の出力は次のgit log --graph --format=%s -5ようになります。

*   Merge branch 'report-a-bug'
|\
| * Add the feedback button
* | Merge branch 'refactor-button'
|\ \
| |/
| * Use the Button class for all buttons
| * Extract a generic Button class from the DownloadButton one

開発者はmaster 、たとえば、最初のトピックブランチが2番目のトピックブランチmasterよりもはるかに早く 統合されることが予想される場合など、ブランチトポロジを維持しながら、これらのコミットをより新しいものにリベースするDownloadButtonことができます。それに入りmasterます。

このリベースは、--rebase-mergesオプションを使用して実行できます。


小さな例については、コミット1644c73を参照してください。

rebase-helper --make-script:マージをリベースするフラグを導入

シーケンサーは、分岐構造を再作成するための新しいコマンドを学習しました(精神的に--preserve-mergesはに似ていますが、実質的に壊れていない設計です)。

rebase--helper新しい--rebase-mergesオプションによってトリガーされる、これらのコマンドを使用してToDoリストを生成できるようにします。
次のようなコミットトポロジの場合(HEADがCを指す):

- A - B - C (HEAD)
    \   /
      D

生成されたToDoリストは次のようになります。

# branch D
pick 0123 A
label branch-point
pick 1234 D
label D

reset branch-point
pick 2345 B
merge -C 3456 D # C

とはどう違い--preserve-mergeますか?
コミット8f6aed7は説明します:

むかしむかし、この開発者は、コアGit上のGit for Windowsのパッチをブランチの茂みとして表現でき、コアGitの上にリベースして、チェリーピック可能なパッチシリーズのセットを維持しますか?

これに答える最初の試みは:git rebase --preserve-mergesでした。

ただし、その実験はインタラクティブなオプションとして意図されたものではなくgit rebase --interactive、そのコマンドの実装はすでに非常によく知られているように見えるため、便乗されただけでした。それは、設計者と同じ人が設計した--preserve-mergesものです。

そして、「あなたの本当の意味で」、著者は自分自身について言及します: 主な理由であるヨハネスシンデリン(dschoです(他のいくつかのヒーロー-ハンネス、シュテフェン、セバスチャンなど...)当時、2009年は簡単ではありませんでした)。
彼は2015年9月から Microsoftで働いています。これは、Microsoftが現在Gitを頻繁に使用しており、サービスを必要としていることを考えると理にかなっています。
この傾向は実際にはTFSで2013年に始まりました。それ以来、マイクロソフトは地球上で最大のGitリポジトリを管理しています。そして、2018年10月以降、マイクロソフトはGitHubを買収しました

2018年4月のGit Merge 2018のこのビデオは、ヨハネスの講演をご覧いただけます。

しばらくして、他の開発者(私はあなたを探している、Andreas!;-))--preserve-merges--interactive(警告付き!)およびGitメンテナー(まあ、暫定Gitメンテナー)と組み合わせることができるようにするのは良い考えだと判断しましたジュニオの不在の間、それは同意されました、そしてそれは--preserve-mergesデザインの魅力がかなり速くそして魅力的ではなく崩壊し始めたときです。

ここでジョナサンはスーゼのアンドレアス・シュワブについて話している。
あなたは彼らの議論のいくつかを2012年に見ることができます。

理由?では--preserve-mergesモード、マージの親がコミット(またはそのことについては、のいずれかのコミット)は明示的に述べなかったが、された 暗示に渡さコミット名前でpickコマンド

これにより、たとえば、コミットの順序を変更することができなくなりました
ブランチ間でコミットを移動すること、またはトピックのブランチを2つに分割することは言うまでもありません。

悲しいかな、これらの欠点により、そのモード(本来の目的はGit for Windowsのニーズに対応することでしたが、他のユーザーにも役立つことを望んでいました)がGit for Windowsのニーズに対応できなくなりました。

5年後、時々コアGitのタグに基づいて再構築された、Git for Windowsの部分的に関連した、部分的に関連のないパッチの扱いにくい大きなホッジポッジパッチシリーズを1つ持つことが本当に耐えられなくなったとき(開発者の不当な怒りを獲得した)git-remote-hgGit for Windowsの競合するアプローチを最初に廃止した不運なシリーズの1 つであり、 後でメンテナなしで放棄される)は本当に耐えられず、「Gitガーデンハサミが生まれました。スクリプト、インタラクティブなリベースの上に便乗するスクリプト、最初に、リベースするパッチのブランチトポロジを決定し、さらに編集するための疑似ToDoリストを作成し、結果を実際のToDoリストに変換します(exec 不足しているtodoリストコマンドを「実装」するコマンド)、新しいベースコミットの上に一連のパッチを最後に再作成します。

(Gitガーデンシアースクリプトは、コミット9055e40のこのパッチで参照されています

それが2013年でした。
そして、デザインを思い付き、それをツリー外スクリプトとして実装するのに約3週間かかりました。言うまでもなく、実装自体が安定するまでにはかなりの年数が必要でしたが、その間、設計自体が健全であることが証明されました。

このパッチを使用すると、Gitガーデンハサミの良さがgit rebase -iそれ自体になります。オプションを
渡すと、--rebase-mergesすぐに理解できるToDoリストが生成され、コミットの並べ替え方法が明確になります。コマンドを
挿入labelしてを呼び出すことにより、新しいブランチを導入できますmerge <label>
このモードが安定し、広く受け入れられるようになると、以前の設計ミスを廃止でき--preserve-mergesます。


Git 2.19(2018年第3四半期)では、新しい--rebase-mergesオプションがで動作するように改善されています--exec

" --exec"のオプション " git rebase --rebase-mergesにより、execコマンドが間違った場所に配置されていましたが、これは修正されました。

コミット1ace63b(2018年8月9日)、およびJohannes Schindelin(によるコミットf0880f7(2018年8月6日)を参照してください。(合併によりJunio C浜野- -750eb11コミットし、2018年8月20日)をdscho
gitster

rebase --exec:で動作させる --rebase-merges

のアイデアは、それぞれの後に呼び出し--execを追加することです。execpick

導入以来fixup!/ sのquash!コミット、このアイデアは、Execが間に挿入されないであろう、すなわち、「おそらくフィックスアップ/スカッシュ鎖続いて、ピック」に適用するように拡張しpick、その対応の任意 fixupまたはsquash行。

現在の実装はそれを達成するためにダーティトリックを使用しています。それは、pick / fixup / squashコマンドのみがあると想定し 、最初の行以外の行を挿入し、最後の行を追加します。execpick

によって生成されたtodoリストによりgit rebase --rebase-merges、この単純な実装はその問題を示しています。それはlabelresetおよびmergeコマンドがあると、まったく間違ったものを生成します。

実装を変更して、望みどおりに実行します。行を探し、 pickフィックスアップ/スカッシュチェーンをスキップして、exec 行を挿入します。泡立て、すすぎ、繰り返します。

注:空のコミットはコメントアウトされた選択行で表されるため、コメント行のに挿入するのは骨が折れます(そして、そのような行のではなく、前の選択の実行行を挿入します)。

それと同時にexecmergeコマンドの後にも行pickを追加します。それらはコマンドと精神が似ているためです。新しいコミットを追加します。


Git 2.22(2019年第2四半期)では、refs / rewritten /階層の使用が修正され、リベースの中間状態が保存されます。これにより、本質的にワークツリーごとに階層が作成されます。

参照b9317d5をコミットし90d31ffをコミットし09e6564をコミットすることで(2019年3月7日)グエンタイ・ゴックDuyと(pclouds
(合併によりJunio C浜野- gitster-917f2cdコミット、2019年4月9日)

refs / rewritten /がワークツリーごとであることを確認してください

a9be29c(シーケンサー:labelコマンドworktree-local、2018-04-25、Git 2.19 によって生成された参照を作成)はrefs/rewritten/、ワークツリーごとの参照スペースとして追加されます。
残念なことに(私の悪いことですが)、実際にワークツリーごとであることを確認するために更新が必要な場所がいくつかあります。

- add_per_worktree_entries_to_dir()参照リストが、refs/rewritten/リポジトリごとではなくワークツリーごとに見えるように更新されました。

  • common_list[]git_path()正しい場所を返すように更新されます。これには「rev-parse --git-path」が含まれます。

この混乱は私が作成したものです。
私はrefs/worktree,、すべての参照がワークツリーごとに特別な処理なしでどこにあるかを紹介することでそれを修正しようとし始めました。
残念ながら、refs / worktreeの前にrefs / rewrittenが来たため、これが私たちにできることのすべてです。


Git 2.24(2019年第4四半期)では、「git rebase --rebase-merges」はさまざまなマージ戦略を推進し、戦略固有のオプションをそれらに渡す方法を学びました。

Elijah Newren(によるコミット476998d(2019年9月4日)を参照してください。 参照e1fac53をコミットしa63f990コミット5dcdd74をコミットしe145d99をコミットし4e6023bコミットf67336dをコミットしa9c7107コミットb8c6f24をコミットしd51b771をコミットしコミットc248d328c1e240をコミットしコミット5efed0e68b54f6をコミットし2e7bbacをコミットし6180b20をコミットしd5b581fコミット(31 2019年7月)newren
ヨハネスシンデリン(dscho
(合併によりJunio C浜野- gitster-917a319コミットし、2019年9月18日)を


Git 2.25(2020年第1四半期)では、ワークツリーのローカル参照とリポジトリグローバル参照を区別するために使用されるロジックが修正され、保存とマージが容易になりました。

参照f45f88bをコミットしc72fc40をコミットし8a64881をコミットし7cb8c92をコミットしe536b1fをコミットすることで(2019年10月21日)SZEDERガーボル(szeder
(合併によりJunio C浜野- gitster-db806d7コミット 2019年11月10日)

path.cmatch値なしで関数を呼び出さないでくださいtrie_find()

署名者:SZEDERGábor

'logs / refs'は作業ツリー固有のパスではありませんが、コミットb9317d55a3以降(refs / rewritten /がワークツリーごとにあることを確認してください、2019-03-07、v2.22.0-rc0) ' git rev-parse --git-path'は偽のパスを返しています末尾に「/」が存在する場合:

$ git -C WT/ rev-parse --git-path logs/refs --git-path logs/refs/
/home/szeder/src/git/.git/logs/refs
/home/szeder/src/git/.git/worktrees/WT/logs/refs/

trieデータ構造を使用して、パスが共通ディレクトリに属しているか、または作業ツリー固有であるかを効率的に判断します。

偶然にも、b9317d55a3trie4e09cf2acfに追加された実装自体と同じくらい古いバグをトリガーしました( " path:共通ディレクトリチェックの最適化"、2015-08-31、Git v2.7.0-rc0- バッチ#2にリストされたマージ)。

  • を説明するコメントによればtrie_find()、「トライに値が含まれるキーの/-または-\ 0で終了する接頭辞」に対して、特定の一致関数「fn」のみを呼び出す必要があります。
    これは真実ではありません。trie_find()がmatch関数を呼び出す場所は3つありますが、そのうちの1つには値の存在のチェックがありません。

  • b9317d55a3は、2つの新しいキーをに追加しましたtrie

    • logs/refs/rewritten」、および
    • ' logs/refs/worktree'、既存の ' logs/refs/bisect'の横。
      これによりtrie、パス ' logs/refs/'のノードが作成されました。これは、以前には存在せず、値が付加されていません。
      ' logs/refs/' のクエリはこのノードを見つけmatch、値の存在をチェックしない関数のその1つの呼び出しサイトにヒットするため、値としてmatch関数を呼び出しNULLます。
  • 場合match関数をcheck_common()用いて呼び出されるNULL値は、照会の経路は、最終的に上に示す偽のパスを得、共通のディレクトリに属していないことを示し、0を返します。

欠落している条件をに追加して、trie_find()存在しない値で一致関数を呼び出さないようにします。

check_common() これにより、NULL以外の値を取得したことを確認する必要がなくなるため、その条件を削除します。

同様の偽の出力を引き起こす可能性のある他のパスはないと思います。

一致関数がNULL値で呼び出される結果となる他の唯一のキーは ' co'です(キー ' common'および ' config'のため)。

ただし、それらは共通ディレクトリに属する​​ディレクトリにはないため、結果として生じる作業ツリー固有のパスが期待されます。


3
私はこれが一番の答えになるはずだと思いますが、--preserve-merges実際にマージを望みどおりに「保持」するのではなく、非常にナイーブです。これにより、インタラクティブなリベースの柔軟性を提供しながら、マージコミットとその親コミット関係を維持できます。この新しい機能は素晴らしいです。このよく書かれたSOの答えがなければ、私は知らなかったでしょう。
エグチカー

@egucciarありがとうございます。そして、Git 2.18(stackoverflow.com/search?q=user%3A6309+%22git+2.18%22)とGit 2.19(stackoverflow.com/search?q=user%3A6309+%22git+2.19%の唯一の機能ではありません22
VonC、

1
このQ / A、stackoverflow.com
questions

1
ああ、それは私がずっと探していたものです!私が持っていた手動の回避策 1は、架空のすべてのマージに参加コミット作成するべきで、そのようなケースのために。
カーニカー2018年

典型的なGit。あえて単純な質問をすると、おそらくGitの履歴、内部アルゴリズム、すべての厄介な実装の詳細に加えて、何が起こっているのかを理解するためにグラフ理論の専攻が必要になります。
Dimitris
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.