192

git rebase を実行するとき、競合を解決するときに「ローカル」と「リモート」で何が起こっているのかを理解するのが難しいことがよくあります。あるコミットから次のコミットへと側面が入れ替わっているような印象を受けることがあります。

これはおそらく(間違いなく)私がまだきちんと理解していないためです。

リベースするとき、誰が「ローカル」で誰が「リモート」ですか?

(競合を解決するために P4Merge を使用します)

4

4 に答える 4

272

TL;DR;

要約すると ( Benubird の コメントとして)、次の場合:

git checkout A
git rebase   B    # rebase A on top of B
  • localは(Bリベース)、
  • remoteA

と:

git checkout A
git merge    B    # merge B into A
  • localは(Aマージ)、
  • remoteB

oursリベースは (リベース開始前の現在のブランチ) とtheirs(リベースしたいブランチ ) を切り替えます。


kutschkemは、GUI の mergetool コンテキストで次のように指摘しています。

  • local は、部分的にリベースされたコミットを参照します: " ours" (上流のブランチ)
  • remote は着信変更を参照します: " theirs" - リベース前の現在のブランチ。

この回答の最後の部分にある図を参照してください。


リベース時の反転

混乱は、 rebase の反転ourstheirsrebase 中の関係に関連している可能性があります。
(関連抜粋)

git 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でリベースするときは「私たちの」と「彼らの」という用語は使用されないため、それらを参照すると答えがより混乱するようです) .

GUI git マージツール

kutschkemは次のように付け加えています。

競合を解決するとき、git は次のように言います。

local: modified file and remote: modified file. 

この時点で、質問はローカルとリモートの定義を目指していると確信しています。その時点で、私の経験から次のように思えます。

  • local は、部分的にリベースされたコミットを参照します: " ours" (上流のブランチ)
  • remote は着信変更を参照します: " 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マージ解像度を次のように表示します

kdiff3

そして、meldもそれを表示します:

メルドデフ

VimDiffについても同じで、次のように表示されます

git mergetool -t gvimdiff を使用して、Vimdiff をマージツールとして呼び出します。最近のバージョンの Git は、次のウィンドウ レイアウトで Vimdiff を呼び出します。

+--------------------------------+
| LOCAL  |     BASE     | REMOTE |
+--------------------------------+
|             MERGED             |
+--------------------------------+
  • LOCAL:
    現在のブランチにあるファイルの内容を含む一時ファイル。
  • BASE:
    マージの共通ベースを含む一時ファイル。
  • REMOTE:
    マージするファイルの内容を含む一時ファイル。
  • MERGED:
    競合マーカーを含むファイル。

Git は可能な限り多くの自動競合解決を実行しており、このファイルの状態は両方の組み合わせでありLOCALREMOTEGit が解決できなかったものを囲む競合マーカーが付いています。
は、解決の結果をこのmergetoolファイルに書き込む必要があります。

于 2010-06-16T09:37:15.950 に答える
46

結論

git リベース

  • LOCAL = リベースするベース
  • REMOTE = 上に移動しているコミット

gitマージ

  • LOCAL = マージ先の元のブランチ
  • REMOTE = コミットをマージする他のブランチ

言い換えれば、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

この時点で、リポジトリは次のようになります。

ベースコミットと 2 つのワンコミットブランチを持つリポジトリ

次にリベース テストを行います。

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)

結果は、一番上に表示されているものと同じになるはずです。

于 2014-05-02T18:41:38.873 に答える
3

問題を正確に把握できませんでしたが、次の図で問題が解決すると思います。(リベース : リモート リポジトリ ---> ワークスペース)

http://assets.osteele.com/images/2008/git-transport.png

出典:私の Git ワークフロー

于 2010-06-16T07:50:01.717 に答える