git rebase を実行するとき、競合を解決するときに「ローカル」と「リモート」で何が起こっているのかを理解するのが難しいことがよくあります。あるコミットから次のコミットへと側面が入れ替わっているような印象を受けることがあります。
これはおそらく(間違いなく)私がまだきちんと理解していないためです。
リベースするとき、誰が「ローカル」で誰が「リモート」ですか?
(競合を解決するために P4Merge を使用します)
要約すると ( Benubird の コメントとして)、次の場合:
git checkout A
git rebase B # rebase A on top of B
local
は(にB
リベース)、remote
はA
と:
git checkout A
git merge B # merge B into A
local
は(にA
マージ)、remote
はB
ours
リベースは (リベース開始前の現在のブランチ) とtheirs
(リベースしたいブランチ ) を切り替えます。
kutschkemは、GUI の mergetool コンテキストで次のように指摘しています。
ours
" (上流のブランチ)theirs
" - リベース前の現在のブランチ。この回答の最後の部分にある図を参照してください。
混乱は、 rebase の反転ours
とtheirs
rebase 中の関係に関連している可能性があります。
(関連抜粋)
リベースのマージは、作業中のブランチから各コミットをブランチの上で再生することによって機能することに注意してください
<upstream>
。
このため、マージの競合が発生した場合:
ours
は、これまでにリベースされたシリーズで、 で始まります<upstream>
。theirs
' は作業ブランチです。つまり、側面が交換されます。x--x--x--x--x(*) <- current branch B ('*'=HEAD)
\
\
\--y--y--y <- other branch to merge
、現在のブランチ 'B' は変更しないので、作業していたものがまだ残っています (別のブランチからマージします)。
x--x--x--x--x---------o(*) MERGE, still on branch B
\ ^ /
\ ours /
\ /
--y--y--y--/
^
their
しかし、 rebaseでは、 rebase が最初に行うことは上流のブランチをチェックアウトすることなので、サイドを切り替えます! (その上で現在のコミットを再生するため)
x--x--x--x--x(*) <- current branch B
\
\
\--y--y--y <- upstream branch
Agit rebase upstream
は最初HEAD
に B を上流ブランチに変更しますHEAD
(したがって、以前の「現在の」作業ブランチと比較して「私たち」と「彼ら」の切り替えです)。
x--x--x--x--x <- former "current" branch, new "theirs"
\
\
\--y--y--y(*) <- upstream branch with B reset on it,
new "ours", to replay x's on it
、そしてリベースは新しい「私たちの」Bブランチで「彼らの」コミットをリプレイします:
x--x..x..x..x <- old "theirs" commits, now "ghosts", available through reflogs
\
\
\--y--y--y--x'--x'--x'(*) <- branch B with HEAD updated ("ours")
^
|
upstream branch
注:「上流」の概念は、データの読み取り元または新しいデータの追加/作成先となるデータの参照セット(すべてのリポジトリ、またはここではローカルブランチにすることができるブランチ)です。
local
' と ' remote
' 対 ' mine
' と ' theirs
'Pandawoodはコメントに次のように追加します。
私にとっては、「ローカル」で誰が「リモート」であるかという問題がまだ残っています(gitでリベースするときは「私たちの」と「彼らの」という用語は使用されないため、それらを参照すると答えがより混乱するようです) .
kutschkemは次のように付け加えています。
競合を解決するとき、git は次のように言います。
local: modified file and remote: modified file.
この時点で、質問はローカルとリモートの定義を目指していると確信しています。その時点で、私の経験から次のように思えます。
ours
" (上流のブランチ)theirs
" - リベース前の現在のブランチ。git mergetool
確かに「ローカル」と「リモート」について言及しています:
Merging:
f.txt
Normal merge conflict for 'f.txt':
{local}: modified file
{remote}: modified file
Hit return to start merge resolution tool (kdiff3):
たとえば、KDiff3はマージ解像度を次のように表示します。
git mergetool -t gvimdiff を使用して、Vimdiff をマージツールとして呼び出します。最近のバージョンの Git は、次のウィンドウ レイアウトで Vimdiff を呼び出します。
+--------------------------------+
| LOCAL | BASE | REMOTE |
+--------------------------------+
| MERGED |
+--------------------------------+
LOCAL
:
現在のブランチにあるファイルの内容を含む一時ファイル。BASE
:
マージの共通ベースを含む一時ファイル。REMOTE
:
マージするファイルの内容を含む一時ファイル。MERGED
:
競合マーカーを含むファイル。Git は可能な限り多くの自動競合解決を実行しており、このファイルの状態は両方の組み合わせであり
LOCAL
、REMOTE
Git が解決できなかったものを囲む競合マーカーが付いています。
は、解決の結果をこのmergetool
ファイルに書き込む必要があります。
結論
git リベース
gitマージ
言い換えれば、LOCALは常にオリジナルであり、REMOTEは常にコミットが以前に存在しなかった人です。なぜなら、それらはマージされているか、または上にリベースされているからです。
証明する!
そうです。私の言葉を鵜呑みにしないでください!これは、自分で確認できる簡単な実験です。
まず、git mergetool が適切に構成されていることを確認してください。(そうでなければ、おそらくこの質問を読んでいないでしょう。) 次に、作業するディレクトリを見つけます。
リポジトリをセットアップします。
md LocalRemoteTest
cd LocalRemoteTest
最初のコミットを作成します (空のファイルを使用):
git init
notepad file.txt (use the text editor of your choice)
(save the file as an empty file)
git add -A
git commit -m "Initial commit."
マスターではないブランチでコミットを作成します。
git checkout -b notmaster
notepad file.txt
(add the text: notmaster)
(save and exit)
git commit -a -m "Add notmaster text."
master ブランチでコミットを作成します。
git checkout master
notepad file.txt
(add the text: master)
(save and exit)
git commit -a -m "Add master text."
gitk --all
この時点で、リポジトリは次のようになります。
次にリベース テストを行います。
git checkout notmaster
git rebase master
(you'll get a conflict message)
git mergetool
LOCAL: master
REMOTE: notmaster
いよいよマージテストです。変更を保存せずに mergetool を閉じてから、リベースをキャンセルします。
git rebase --abort
それで:
git checkout master
git merge notmaster
git mergetool
LOCAL: master
REMOTE: notmaster
git reset --hard (cancels the merge)
結果は、一番上に表示されているものと同じになるはずです。