73

リモートリポジトリにメインの開発ブランチがあるこのプロジェクトがあり、実験ブランチを含むフォークがあります。rebaseフォークにプッシュする前に、開発ブランチから実験的ブランチに変更する必要があります。したがって、次のようになります。

git checkout experimentalbranch
git fetch remoterepo
git rebase remoterepo/developmentbranch

この時までに、私は衝突しました。しかし、私はこれらの変更に精通していません(私の変更がすぐにマージされなかったので、数週間分の変更をリベースしています)。また、やるのは初めてrebaseです。私はより慣れていmergeます。

meld では、たいていは<<LOCAL||REMOTE>>forのようなものでmerge、非常に直感的に聞こえます。しかしrebase、それは<<HEAD||COMMIT MESSAGE>>です。誰HEADですか?HEAD開発ブランチのですか?開発ブランチの最新コードですか、それとも他の場所ですか?

4

2 に答える 2

123

TL;DR (2018 年 5 月追加)

Git では内部の仕組みがすぐにわかるようになっているため、基本的に全体が少し混乱しています。

ここで関係するケースは、実行時に発生することに注意してください。

git checkout somebranch; git rebase origin/their-branch

または類似。マージの競合を強制的に解決するために、リベースが一時的に停止しました。その後、競合を解決してgit add実行することになっていますgit rebase --continue。(何らかのマージ ツールをgit mergetoolや洗練された GUI インターフェースと共に使用する場合、そのインターフェースは別の方法でこれの一部またはすべてを実行する場合がありますが、その下ではgit add、解決されたファイルを ing して実行していgit rebase --continueます。)

最初に、HEADコミットは彼らのブランチであるため、git checkout --oursorを使用するとgit checkout --theirs彼らの最後のコミットを--ours意味し、あなたがリベースする最初のコミットを意味します。これは通常の日常的な Git の混乱であり ( 「git における "ours" と "theirs" の正確な意味は何ですか? を参照)、元の質問につながったものではありません。origin/their-branch--theirs

ただし、後で、HEADコミットは実際には一種の混合物です。これは、いくつかのコミットを最新の commit の上にコピーした結果です。部分的に構築された新しい一連のコミットと、独自ののコミットとの間で競合が発生しています。この競合の原因は、通常、「彼ら」が行ったものです (途中で変更されたものorigin/their-branch)。この競合を解決する必要があります。そうすると、後のコミットでまったく同じ競合が再発することがあります。

繰り返しますが、HEADorlocalまたは--oursrebase が変更とその変更を組み合わせて構築したコミットであり、もう 1 つのコミット ( remoteor>>>>>>>または--theirs) は、rebase がコピーしようとしている独自のコミットHEADです。

より長いです

マージ (内部で繰り返される「マージ」の特殊なケースであるリベースを含む) には、2 つの「ヘッド」(2 つの特定のブランチ チップ) が関係します。your-branchこれらを呼び出しましょうorigin/their-branch:

              G - H --------      <-- HEAD=your-branch
            /               \
... - E - F                   M   <-- desired merge commit [requires manual merge]
            \               /
              I - J - K - L       <-- origin/their-branch

この点は、一般的に (そして当然のことながら) 混乱を招きますが、このようにラベル付けすると十分に明確になります。

さらに悪いことに、git は--ours--theirsを使用して、マージ中に 2 つのヘッド コミットを参照します。「ours」は、実行Hしたときのコミット (commit )git mergeであり、「theirs」は、まあ、彼らの (commit L) です。しかし、リベースを実行しているときは、2 つのヘッドが逆になるため、"ours" はリベース先のヘッド (つまり、更新されたコード) であり、"theirs" は現在リベースしているコミットです。つまり、独自のコードです。

これは、rebase が実際に一連のチェリー ピック操作を使用するためです。ほとんど同じ画像から始めます。

              G - H           <-- HEAD=your-branch
            /
... - E - F
            \
              I - J - K - L   <-- origin/their-branch

ここで git がしなければならないことは、commitとの効果をコピーすることです。しかし、それを行うには、git は最初に内部的にコミットするように切り替える必要があります(「切り離された HEAD」モードを使用):GHgit cherry-pickGHL

              G - H           <-- your-branch
            /
... - E - F
            \
              I - J - K - L   <-- HEAD, origin/their-branch

Fこれで、コミットのツリーを比較しG(変更内容を確認するため)、Fvsを比較しL(作業の一部が既に にあるかどうかを確認するためL)、まだ変更されていない変更を取得しLて追加することで、リベース操作を開始できます。これは、内部的には「マージ」操作です。

              G - H           <-- your-branch
            /
... - E - F                   G'   <-- HEAD
            \               /
              I - J - K - L   <-- origin/their-branch

マージがうまくいかない場合は、HEADまだ commit のままですL(commitG'がまだ存在しないため)。したがって、はい、HEAD開発部門の責任者です。少なくとも、現在はそうです。

ただし、のコピーがG存在すると、 にHEAD移動し、git は からの変更を同じ方法でG'コピーしようとします( diff vs 、次に diff vs 、結果をマージします)。HGHFG'

              G - H           <-- your-branch
            /
... - E - F                   G' - H'   <-- HEAD
            \               /
              I - J - K - L   <-- origin/their-branch

繰り返しますが、マージが失敗して助けが必要な場合は、 as がまだ存在しない代わりに を指すことにHEADなります。G'H'H'

マージがすべて成功し、コミットG'H' 存在するようになると、git はyour-branchcommit からラベルを削除し、代わりHに commit を指すようにします。H'

              G - H
            /
... - E - F                   G' - H'   <-- HEAD=your-branch
            \               /
              I - J - K - L   <-- origin/their-branch

あなたは今リベースされ、HEAD再びあなたが期待するものです. ただし、リベース中HEADは、ブランチ チップ ( commit L) か、ブランチ チップを越えてコピーおよび追加された新しいコミットの 1 つです。and--oursは、コミットがコピー元 (またはそれ以上)であることLを意味します。--theirsGH

(これは基本的に、git が行うことの生のメカニズムを公開する gitあり、git ではかなり頻繁に発生します。)

于 2014-04-22T00:00:05.330 に答える