1. ホーム
  2. git

[解決済み] なぜgit-svnでは "ours "と "theirs "の意味が逆転しているのか?

2023-02-05 15:13:27

質問

私は git-svn を使っていますが、あるコマンドを実行した後にマージの衝突を修正する必要があることに気づきました。 git svn rebase を実行した後にマージの衝突を修正しなければならないとき、その --ours--theirs オプションは、例えば git checkout は逆になっています。つまり、もし衝突があって、SVN サーバから来たバージョンを維持し、ローカルで行った変更を捨てたい場合、私は ours であることが期待される場合、私は theirs .

なぜなんでしょう?

例を挙げます。

mkdir test
cd test
svnadmin create svnrepo
svn co file://$PWD/svnrepo svnwc
cd svnwc
echo foo > test.txt
svn add test.txt
svn ci -m 'svn commit 1'
cd ..
git svn clone file://$PWD/svnrepo gitwc
cd svnwc
echo bar > test.txt 
svn ci -m 'svn commit 2'
cd ..
cd gitwc
echo baz > test.txt 
git commit -a -m 'git commit 1'
git svn rebase

git checkout --ours test.txt
cat test.txt 
# shows "bar" but I expect "baz"

git checkout --theirs test.txt
cat test.txt 
# shows "baz" but I expect "bar"

どのように解決するのですか?

リベースが行うことと矛盾しないように思えます。

  • git svn rebase は、現在の HEAD の SVN 親からリビジョンを取得し、それに対して現在の (SVN にコミットされていない) 作業をリベースします。

  • git rebase は言及しています。

    リベースマージは、作業ブランチからの各コミットを <upstream> ブランチの上で作業ブランチからの各コミットを再生することで動作します。

    このため、マージの衝突が起きたときに

    • で始まる、これまでのリベースされたシリーズであると報告されます。 <upstream> ,
    • そしてそれらは作業ブランチである .

      言い換えれば が入れ替わっているのです。 .

git rebase は、作業ブランチからの各コミットを <upstream> ブランチの上に置かれます。

両方の定義を照らし合わせると

  • SVN からのコミットは、ローカルの Git のコミットが再生される際のベースとなるコミットです。これらは "so-far rebased series" の一部であり、"our" として参照されます(あなたの場合、test.txt というファイルを bar コンテンツ)
  • 作業ブランチ (SVNに未知のGitコミットを含む、あなたの場合は test.txt というファイルを baz の内容) が "彼らの" であり、それらのローカル Git コミットがそれぞれ再生されています。

言い換えれば、SVN であろうとなかろうと。

  • は、" <upstream> " ブランチ (その上に何かが再生され、これまでにリベースされたコミットの一部である") は " 私たちの です。
  • 再生されているもの (作業ブランチ) は " のものです。 "です。

良い ニーモニックチップ カンマトースト :

<ブロッククオート

HEADが指し示すものは、すべて我々のものです。

(そして、最初に git rebase upstream をチェックアウトすることです。 upstream ブランチをチェックアウトします。HEAD は upstream -- ours 現在)


この混乱は、おそらく古典的な作業ブランチの役割から来るものです。 git merge .

マージしているとき。

  • 作業ブランチとは、これまでにマージされたものを含むブランチで、私たちのブランチとみなされます。
  • 一方、他のコミットは作業ブランチの上にマージされるものを表し、"their" と見なされます。

のように git rebase のマニュアルページで言及されているように、リベース中のマージはサイドが入れ替わることを意味します。


同じことを言う別の方法として、次のように考えることができます。

  • 私たちが持っているもの をチェックアウトしたブランチでは、' 私たちの ',
  • 私たちが持っていたもの (そしてマージされたり再生されたりする)のは' のものです。 '.

マージについて :

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


しかし リベースの際に というのも、リベースが最初に行うのは上流のブランチをチェックアウトすることだからです! (その上で現在のコミットを再生するために)

x--x--x--x--x(*) <- current branch B
    \
     \
      \--y--y--y <- upstream branch

A git rebase upstream がまず変わる HEAD を上流ブランチの HEAD に変更しました (そのため、以前の "current" 作業ブランチと比較して 'ours' と 'theirs' が入れ替わっています)。

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


による唯一の余分なステップは git svn rebase は、SVN のコミットを表す Git リモートブランチ上で svn "fetch" が最初に実行されることです。

最初はありますね。

x--x--x--x--x(*) <- current branch B, "ours" for now.
    \                                   
     \
      \--y--y--y <- SVN tracking branch, "theirs for now"

の場合、まずSVNから来た新しいコミットでSVNトラッキングブランチを更新します。

x--x--x--x--x(*) <- current branch B, still "ours", not for long
    \                                   
     \
      \--y--y--y--y'--y' <- SVN tracking branch updated

で、現在のブランチをSVN側("ours"になる)に切り替えます。

x--x--x--x--x <- for "B", now "their" during the rebase
    \                                   
     \
      \--y--y--y--y'--y'(*) <- SVN tracking branch updated, and branch B: 
                               now "ours" (this is "what we now have")

リベースの間、あなたが作業していたコミット(ただし、現在は彼らのコミット)を再生する前に

x--x..x..x..x <- old "theirs" commits, now "ghosts", available through reflogs
    \
     \
      \--y--y--y--y'--y'--x'--x'--x'(*) <-  branch B with HEAD updated ("ours")
                      ^
                      |
        upstream SVN tracking branch