チェリーピック
私が自分自身を誤解していない限り、「git cherry-pick <commit C>」を実行すると、次のようになります。
- LOCAL: マージするコミット (つまり、ブランチの HEAD)
- REMOTE: 選択したコミット (例: <commit C>)
- BASE: 選択したコミットの親 (つまり、C^、つまり C の親)
BASE が C^ であるべき理由がすぐにわからない場合は、以下の「理由」セクションを参照してください。
一方、例を挙げてみましょう。チェリー ピックでは、BASE が共通の祖先になる可能性がありますが、多くの場合そうではないことがわかります。コミット グラフが次のようになっているとします。
E <-- master
|
D
| C <-- foo_feature(*)
|/
B
|
A
あなたはブランチ foo_feature にいます(したがって、アスタリスク)。「git cherry-pick <commit D>」を実行すると、cherry-pick の BASE は C と D の共通の祖先であるコミット B になります (C は LOCAL になり、D は REMOTE になります)。代わりに「git cherry-pick <commit E>」を実行すると、BASE はコミット D になります (C は LOCAL になり、E は REMOTE になります)。
リベース
バックグラウンド コンテキストの場合、rebase はほぼ反復されたチェリー ピッキングです。特に、マスターの上にトピックをリベースする (つまり、「git checkout topic; git rebase master」) とは、おおよそ次のことを意味します。
git checkout master # switch to master's HEAD commit
git checkout -b topic_rebased # create new branch rooted there
for each commit C in master..topic # for each topic commit not already in master...
git cherry-pick C # bring it over to the new branch
finally, forget what "topic" used to mean and now defined "topic" as the HEAD of topic_rebased.
このプロセス中に適用されるラベルは、通常のチェリー ピック ルールの拡張です。
- LOCAL: チェリーピックしているコミット
- これは新しい topic_rebased ブランチの HEAD です
- 最初のコミットのみ、これは master の HEAD と同じになります
- REMOTE: 選択したコミット (例: <commit C>)
- BASE: 選択したコミットの親 (C^、つまり C の親)
これは、混乱を避けるために、LOCAL と REMOTE について留意すべきことを意味します。
リベースを開始したときにブランチ トピックにいたとしても、リベースの進行中にLOCAL がトピック ブランチのコミットを参照することはありません。 代わりに、LOCAL は常に、作成される新しいブランチ (topic_rebased) のコミットを参照します。
(これを心に留めておかないと、厄介なマージの最中に、「待って、なぜこれらはローカルの変更だと言っているのですか? 私は、それらが私のブランチではなくマスターで行われた変更であることを誓います. 」と自問し始めるかもしれません。)
より具体的に言うと、以下に例を示します。
コミットグラフがあるとしましょう
D <-- foo_feature(*)
|
| C <-- master
B |
|/
|
A
現在、ブランチ foo_feature (「*」で示されています) にいます。「git rebase master」を実行すると、リベースは 2 つのステップで進みます。
最初に、B からの変更が C の上で再生されます。この間、C は LOCAL、B は REMOTE、A は BASE です。A は B と C の実際の共通の祖先であることに注意してください。この最初のステップの後、おおよそ次のようなグラフが得られます。
B' <-- foo_feature
D |
| |
| C <-- master
B /
|/
|
A
(実生活では、この時点で B と D は既にツリーから剪定されている可能性がありますが、潜在的な共通の祖先を見つけやすくするために、ここに残しています。)
次に、D からの変更が B' の上で再生されます。この間、B' は LOCAL、D は REMOTE、B は BASE です。B は何の関連する共通の祖先でもないことに注意してください。(たとえば、現在の LOCAL と REMOTE、B' と D の共通の祖先ではありません。また、元のブランチ ヘッドの C と D の共通の祖先でもありません)。このステップの後、おおよそ次のようなブランチがあります。
D' <-- foo_feature
|
B'
D |
| |
| C <-- master
B /
|/
|
A
完全を期すために、リベースの最後までに B と D がグラフから削除され、次のようになることに注意してください。
D' <-- foo_feature
|
B'
|
C <-- master
|
A
BASEがそのまま定義されているのはなぜですか?
上記のように、cherry-pick と rebase の両方で、BASE はプルされるコミット C の親 (C^) です。一般に、C^ は共通の祖先ではないため、なぜ BASE と呼ぶのですか? ? (通常のマージでは、BASEは共通の祖先です。そして、マージにおける git の成功の一部は、適切な共通の祖先を見つける能力によるものです。)
基本的に、通常の3 方向マージアルゴリズムを介して「パッチ」機能を実装する方法としてこれを行います。特に、これらの「斑点のある」プロパティを取得します。
- <commit C> がファイルの特定のリージョンを変更しない場合、ブランチのそのリージョンのバージョンが優先されます。(つまり、「パッチ」が変更を要求しない領域にはパッチが適用されません。)
- <commit C> がファイルの特定の領域を変更し、ブランチがその領域をそのままにしておく場合、<commit x> からのその領域のバージョンが優先されます。(つまり、「パッチ」が変更を要求する領域にパッチが適用されます。)
- <commit C> がファイルの特定の領域を変更したが、ブランチがその領域も変更した場合、マージの競合が発生します。