22

長いリベースで遭遇する問題の1つは、冗長な競合を解決する必要があることです。関数を変更し続ける一連のコミットを持つブランチがあり、最後のコミットで関数が完全に削除されたとします。

私がそうするときrebase master、Gitは各コミットを順番に素朴に適用します。つまり、最終的にはその作業が無駄になったとしても、マスターのヒントを使ってこれらの各コミットを解決する必要があります。

この状況に対処するための良い方法は何ですか?おそらく、ブランチ全体に対して単一のパッチを生成し、それをマスターに対して適用する必要がありますか?もしそうなら、いくつかの歴史を保存する方法はありますか?考え、提案など。

4

4 に答える 4

17

を使用して履歴コミットからデータベースgit rerereを教えることと組み合わせて使用​​したい(すでに持っている可能性があります)。これにより、gitは履歴から学習したマージ競合解決を自動的に使用できます。rererererere-train.sh/usr/share/doc/git/contrib/rerere-train.sh

警告:基本的に、競合するマージを修正するために履歴文字列置換を盲目的に使用して、gitにソースコードを書き直させています。リベース後に、競合するすべてのマージを確認する必要があります。これには問題なく機能することがわかりgitkました(マージのパッチとして競合解決のみが表示されます)。私は良い経験しかありませんでしたrerere、あなたはそれほど幸運ではないかもしれません。基本的に、履歴に壊れたマージが含まれている場合(つまり、技術的に誤って行われ、後でコミットで修正されるマージ)、rerere同様に壊れたマージを自動的に行う必要がない限り、履歴から使用することはできません。 。

簡単に言えば、あなたはただ走ります

git config --global rerere.enabled 1
bash /usr/share/doc/git/contrib/rerere-train.sh --all

本当にやりたいリベースが続き、魔法のように機能するはずです。

グローバルに有効rerereにすると、今後は履歴から学ぶ必要がなくなります。rerere学習機能は、有効にする前に競合解決がすでに行われた後に使用する場合にのみ必要ですrerere

PS。私は別の質問に対する同様の答えを見つけました:https ://stackoverflow.com/a/4155237/334451

于 2012-08-23T07:18:50.320 に答える
8

機能を使用できますgit rerere

を使用して有効にする必要がありますgit config --global rerere.enabled 1。その後、解決したすべての競合が後で使用できるように保存され、同じコンテキストで解決が再適用されます。

保存されている解像度は。で確認できますgit rerere diff

詳細については、このチュートリアルをご覧ください。

于 2012-05-15T13:37:04.333 に答える
5

squash冗長パッチを最初のインタラクティブリベースで一緒に(最初にそれらが一緒になるように並べ替えて)、シーケンスの「変更してから削除」の側面を一掃してみませんか。この段階では、コミット内のハンクを選択できます(たとえば、git guiを使用します)。これにより、最終的なクリーンリベースのシーケンスが改善されます。

于 2012-05-15T15:42:58.000 に答える
2

(これは私の質問に対する2番目の答えです。2回目の読書では、元の問題は私が最初に理解した問題とは少し異なっていた可能性があると思います。)

あなたが開発ブランチのパララーを持っているので、私は質問を理解していますmaster。通常、この種のブランチスタイルは機能ブランチと呼ばれ、これらを使用することを強くお勧めします。

機能ブランチを常にクリーンに保つように努める必要があります。実際には、間違いを犯したことがない場合に行ったであろうコミットを備えた機能ブランチが必要です。git rebase -i私にとって、それは私が後でそれらの間違いについて学ぶときに間違いを修正するために多くのことを後でコミットすることを意味します。

機能ブランチの準備が整うまでに、次のようになります。

  1. Xを実行するためのAPIを追加する
  2. コーナーケースZの既存のAPIYを修正
  3. XとYを使用して機能Bを追加します(Zの場合にも機能します!)
  4. 機能Bを改善する:魔法のようなことをするE

それ以外の

  1. WIP
  2. WIP2
  3. APIを追加
  4. APIを移動してXを実行する
  5. 機能Bを追加
  6. 考え直して、Xのパラメーターの名前を変更します
  7. 機能Bを修正
  8. XのAPiを修正
  9. コーナーケースZを修正
  10. APIYのコーナーケースZも修正
  11. 魔法のことをするE
  12. 欠落しているファイルをコミットする

その後、機能ブランチを最新のブランチにリベースするmasterと、変更が大きくなり、コミットのみFix existing API Y for corner case Zが競合を引き起こす可能性があります。そのコミットが既存のAPIを変更するための最小限の変更である場合、競合の修正は簡単です。さらに、その競合は、他のコミットが最小限の変更によって触れられた行を正確に変更した場合にのみ発生します。

マージする代わりに機能ブランチとリベース機能ブランチを実行する場合(私の好みのスタイルは、早送りが可能になるようにリベースしてからgit checkout master && git merge --no-ff feature-branch-x、マージコミットですべてを実行して文書化することです。これにより、ブランチの完全な履歴を保持し、GUIツールを使用できます。必要に応じて機能を簡単にナビゲートするために)これらのブランチをにリベースする前に、機能ブランチをクリーンに保つmaster必要があります。リベースが簡単になるだけでなく、長期的には履歴を読み取ることができます。

したがって、上記の例ではrebase -i <old-enough-sha1>、再注文は3 + 4 + 6 + 8、10、1 + 2 + 5 + 7 + 9、11 + 12としてコミットされます。ここで、+はスカッシュを意味します。Gitでは、既存のコミットを分割して編集することもできますが、通常は、コミットを非常に小さくして、後でそれらの一部を潰す方が簡単です。この例では、元のコミット番号10でさえ、元の最初のコミットの前に終了することに注意してください。これは正常であり、実装が完全ではなかったという現実を反映しています。ただし、バージョン履歴に保存する必要はありません。

あなたの場合、複数のコミットが同じものを追加および削除する機能ブランチがあるように思えます。それらのコミットを単一のコミットとして押しつぶします(変更がない場合は問題ありません)。機能ブランチがクリーンに見える場合にのみ、機能ブランチをマスターにリベースします。ファイルの代わりに変更されたを簡単にgit guiコミットできるようにするツールやその他のツールの使い方を確実に学びましょう。すべてのコミットは、適切なコレクションを変更する変更である必要があります。新しい機能Xを追加する場合、同じコミットで既存の関数Yを修正したり、Zに関する不足しているドキュメントを追加したりしてはなりません。同じファイルにこれらの変更が加えられた場合でも同様です。私にとって、これは、LinusTorvaldsが「ファイルは重要ではない」と言ったときに意味したようなものです。"。

于 2016-06-23T12:41:44.940 に答える