382

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

--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でしょうか。デフォルトの動作 (そのフラグなし) とどう違うのですか? マージなどを「再作成する」とはどういう意味ですか?

4

3 に答える 3

491

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

通常のリベースとマージ保存リベースの主な違いをより明確にするには:

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

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

「ブリーフ」のアルゴリズム

本格的に雑草を掘り下げたい場合は、git ソースをダウンロードしてファイルを調べてgit-rebase--interactive.shください。(リベースは Git の C コアの一部ではなく、bash で記述されています。また、舞台裏では、「対話型リベース」とコードを共有しています。)

しかし、ここではその本質であると私が考えるものをスケッチします。考えなければならないことの数を減らすために、私はいくつかの自由を取りました。(たとえば、計算が行われる正確な順序を 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 の HEAD でコミット再生を開始する代わりに、代わりに C の HEAD でコミット再生を開始します。(そして、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 トピック; リベース --preserve-merges master )。この新しいケースでは、git はリプレイ用に次のコミットを選択します。

  • Dを選ぶ
  • Eを選ぶ
  • F を選択します (「サブトピック」ブランチの D に)
  • G を選択します (「サブトピック」ブランチの F に)
  • pick ブランチ「サブトピック」をトピックにマージ
  • 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を選ぶ
  • 私を選ぶ
  • 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 からのすべての変更が組み込まれている必要があることに注意してください。

H (トピック) を D (マスター)にしようとするとgit rebase --preserve-merges、次のコミットがリプレイ用に選択されます。

  • 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 が空のコミットの作成を嫌うということです。

于 2013-04-10T01:29:50.193 に答える
123

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 、コミット25555555555555555555555555555 555555555555555555555555555555550年のコミットを参照してくださいヨハネス・シンデリン ( )著。Stefan Beller ( )によるcommit f431d73 (2018 年 4 月 25 日) を参照してください。dscho
stefanbeller
Phillip Wood ( )によるcommit 2429335 (2018 年 4 月 25 日) を参照してください。( 2018 年 5 月 23 日コミット 2c18e6aJunio C Hamanoによってマージされました)phillipwood
gitster

pull--rebase-merges:分岐トポロジの再作成を受け入れます

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

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


git rebaseman ページに、マージによる履歴のリベース専用の完全なセクションが追加されました。

エキス:

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

次の例では、開発者は、ボタンの定義方法をリファクタリングするトピック ブランチと、そのリファクタリングを使用して「バグを報告する」ボタンを実装する別のトピック ブランチで作業します。
の出力は次の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によってトリガーされる、これらのコマンドを使用して todo リストを生成できるようにしましょう。 このようなコミット トポロジの場合 (HEAD は C を指します):--rebase-merges

- 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 for Windows のコア Git 上のパッチをブランチの茂みとして表現し、コア Git の上にリベースして、チェリーピック可能な一連のパッチシリーズを維持していますか?

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

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

そして、「本当にあなたの」という言葉で、著者は自分自身を指します: Johannes Schindelin ( dscho)は、(Hannes、Steffen、Sebastian などの数人のヒーローと共に) Git For Windows を持っている主な理由です (たとえ当時 - 2009 - それは簡単ではありませんでした)。彼は2015 年 9 月から
Microsoft に勤務しています。これは、Microsoft が現在 Git を多用しており、彼のサービスを必要としていることを考えると理にかなっています。 その傾向は、実際には 2013 年に TFS で始まりました。それ以来、Microsoftは地球上で最大の Git リポジトリを管理しています。そして、2018 年 10 月以降、Microsoft は GitHub を買収しました。

Johannes が2018 年 4 月に開催された Git Merge 2018 のこのビデオで話すのを見ることができます。

しばらくして、他の開発者 (Andreas さん、私はあなたのことを見ています! ;-)) は、(注意が必要です!) および Git メンテナ (つまり、Git の暫定メンテナ) と--preserve-merges組み合わせることを許可することをお勧めします。--interactiveジュニオの不在の間、つまり) 同意しました. それは、--preserve-mergesデザインの魅力がかなり急速にそして魅力的に崩壊し始めたときです.

ここで、Jonathan はSuse のAndreas Schwabについて話しています。2012 年の議論
の一部を見ることができます。

理由?モードでは、マージ コミット (またはさらに言えば、任意のコミット) の親は明示的に述べられていませんでしたが 、 commandに渡されたコミット名によって暗示--preserve-mergespickされていました。

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

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

5 年後、時々コア Git のタグに基づいてリベースされた、部分的に関連し、部分的に無関係なパッチの扱いにくい、大きな寄せ集めのパッチシリーズを Windows 用の Git に置くことが本当に受け入れられなくなったとき (開発者の不当な怒りを得た) Git for Windows の競合するアプローチを最初に廃止し、後にメンテナーなしで放棄された不運な git-remote-hgシリーズの 1 つが本当に支持できなかったため、「Git ガーデン シャーが誕生しました。最初に、リベースするパッチのブランチ トポロジを決定し、さらに編集するために疑似 todo リストを作成し、結果を実際の todo リストに変換します (execコマンドを使用して不足している todo リスト コマンドを「実装」し、最後に新しいベース コミットの上に一連のパッチを再作成します。

(Git 庭ばさみスクリプトは、コミット 9055e40のこのパッチで参照されています)

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

このパッチにより、Git ガーデン ハサミの良さが際立ちgit rebase -iます
オプションを渡す--rebase-mergesと、すぐに理解できる todo リストが生成され、コミットの順序を変更する方法が明確になります。コマンドを挿入して を呼び出すと
、新しいブランチを導入できます。そして、このモードが安定し、普遍的に受け入れられるようになると、設計上の誤りを非難することができます.labelmerge <label>
--preserve-merges


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

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

commit 1ace63b (2018 年 8 月 9 日) およびcommit f0880f7 (2018 年 8 月 6 日) によるJohannes Schindelin ( dscho)を参照してください。
( 2018 年 8 月 20 日、コミット 750eb11Junio C Hamanoによってマージされました)gitster

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

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

fixup!/sコミットが導入されて以来、この考えは拡張され、"pick、おそらくその後に fixup / quash!squash チェーン" が適用されるようになりpickまし た。fixupsquash

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

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

実装を変更して、必要なことを正確に実行します。行を探し、 pickフィックスアップ/スカッシュ チェーンをスキップしてから、execを挿入します。泡立てて、すすぎ、繰り返します。

注:空のコミットはコメントアウトされた pick 行で表されるため、可能な限りコメント行の前に挿入するように苦労します (そして、前の pick の exec 行をそのような行の後ではなくに挿入したいと考えています)。

その際、コマンドのexec後に行を追加します。これは、コマンドmergeと精神が似ているためpickです。新しいコミットを追加します。


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

Nguyễn Thái Ngọc Duy ( )によるcommit b9317d5commit 90d31ffcommit 09e6564 (2019 年 3 月 7 日)を参照してください。( 2019 年 4 月 9 日コミット 917f2cdJunio C Hamanoによってマージされました)pclouds
gitster

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

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

  • add_per_worktree_entries_to_dir()ref リストがリポジトリごとではなくワークツリーごとに表示されるように更新されましたrefs/rewritten/

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

この混乱は私によって作成されます。すべての参照が特別な処理なしでワークツリーごとに配置される場所
を導入して、それを修正しようとし始めました。 残念なことに、refs/rewrite は refs/worktree の前に来たので、これが私たちにできるすべてです。refs/worktree,


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

Elijah Newren ( )によるcommit 476998d (2019 年 9 月 4 日)を参照してください。 E1FAC53のコミット、 A63F990のコミット、 5DCDD74のコミットコミットE145D99コミット4E6023Bコミット4E6023BF67336Dコミット、A9C7107のコミット、コミットB8C6F24コミットD51B771コミットメントC248D32参照してください。2019 年 7 月)newren
ヨハネス・シンデリン ( dscho) .
( 2019 年 9 月 18 日、コミット 917a319Junio C Hamanoによってマージされました)gitster


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

commit f45f88b、commit c72fc40commit 8a64881commit 7cb8c92commit e536b1f (2019 年 10 月 21 日) by SZEDER Gábor ( szeder)を参照してください。
( 2019 年 11 月 10 日、コミット db806d7Junio C Hamanoによってマージされました)gitster

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

署名者: SZEDER Gá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、パスが共通ディレクトリに属しているか、作業ツリー固有であるかを効率的に判断します。

たまたま、 b9317d55a3trieは実装自体と同じくらい古いバグを引き起こし、4e09cf2acfに追加されました(" path: 共通ディレクトリ チェックの最適化"、2015-08-31、Git v2.7.0-rc0 --マージはバッチ #2にリストされています)。

  • を説明するコメントによると、trie_find()「トライに値が含まれるキーの /-or-\0 で終わるプレフィックス」に対して、指定された一致関数 'fn' のみを呼び出す必要があります。
    これは正しくありません: trie_find() が match 関数を呼び出す場所が 3 つありますが、そのうちの 1 つは値の存在のチェックが行われていません。

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

  • ' logs/refs/rewritten'、および

  • ' logs/refs/worktree'、既存の ' logs/refs/bisect' の隣。
    これによりtrie、パス ' logs/refs/' を持つノードが作成されました。このノードは以前には存在せず、値が添付されていません。
    ' ' のクエリは、このノードを見つけ、値の存在をチェックしない関数logs/refs/の 1 つの呼び出しサイトにヒットし、値として関数を呼び出します。matchmatchNULL

  • match関数check_common()が値を指定して呼び出されると、0NULLが返されます。これは、照会されたパスが共通ディレクトリに属していないことを示し、最終的に上記の偽のパスになります。

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

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

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

AFAICTNULL値を指定して match 関数が呼び出される唯一の他のキーは ' co' です (キー ' common' と ' config' のため)。

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


メモリ リークを避けるために、必ず Git 2.34 (2021 年第 4 四半期) を使用してください。

Ævar Arnfjörð Bjarmason ( )によるcommit 6e65854commit 0c52cf8 (2021 年 10 月 13 日)、およびcommit e5a917f (2021 年 10 月 7 日) を参照してください。Junio C Hamano ( )によるコミット 9d05b45 (2021 年 10 月 7 日) を参照してください。( 2021 年 10 月 25 日コミット bfa646cJunio C Hamanoによってマージされました)avar
gitster
gitster

sequencer: でのメモリ リークを修正します。do_reset()

署名者: Ævar Arnfjörð Bjarmason

対応する. _ sequencer_ _ _ _ _ setup_unpack_trees_porcelain()_clear_unpack_trees_porcelain()

于 2018-05-27T19:26:37.743 に答える