Mengapa arti "milik kita" dan "milik mereka" dibalik dengan git-svn

91

Saya menggunakan git-svn dan saya perhatikan bahwa ketika saya harus memperbaiki konflik penggabungan setelah melakukan a git svn rebase, arti dari --oursdan --theirsopsi untuk misalnyagit checkout dibalik. Artinya, jika ada konflik dan saya ingin menyimpan versi yang berasal dari server SVN dan membuang perubahan yang saya buat secara lokal, saya harus menggunakan ours, ketika saya mengharapkannya theirs.

Mengapa demikian?

Contoh:

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"
Marc Liyanage
sumber
Jut memperbarui jawaban saya dengan banyak diagram untuk lebih mengilustrasikan sisi "milik kami" dan "milik mereka".
VonC
1
Lihat juga github.com/git/git/commit/…
VonC

Jawaban:

232

Itu sepertinya konsisten dengan apa yang dilakukan rebase.

  • git svn rebase akan mengambil revisi dari induk SVN dari HEAD saat ini dan mengubah peringkat pekerjaan saat ini (tidak terikat ke SVN) terhadapnya.

  • git rebasetidak menyebutkan:
    Perhatikan bahwa rebase merge bekerja dengan mengulang setiap komit dari cabang yang bekerja di atas <upstream>cabang.
    Karena itu, saat konflik penggabungan terjadi:

    • sisi yang dilaporkan sebagai milik kami adalah seri yang didasarkan sejauh ini, dimulai dengan<upstream> ,
    • dan mereka adalah cabang yang bekerja .
      Dengan kata lain, sisi-sisinya bertukar .

git rebase memutar ulang setiap komit dari cabang yang bekerja di atas <upstream>cabang.

Jika Anda menggabungkan kedua definisi tersebut:

  • komit yang berasal dari SVN adalah yang di atasnya komit Git lokal diputar ulang. Mereka adalah bagian dari "rangkaian berbasis ulang sejauh ini", dan dirujuk sebagai "milik kami" (dalam kasus Anda, test.txtfile dengan barkonten)
  • cabang yang berfungsi (berisi komit Git yang tidak diketahui SVN, dalam kasus Anda, test.txtfile dengan bazkonten) adalah "milik mereka", dan setiap komit Git lokal tersebut sedang diputar ulang.

Dengan kata lain, SVN atau tidak:

  • <upstream>cabang " " (di atasnya ada yang diputar ulang, dan yang merupakan bagian dari komitmen yang didasarkan sejauh ini ") adalah" milik kami ".
  • apa yang diputar ulang (cabang yang berfungsi) adalah " milik mereka ".

Tip mnemonik yang bagus dari CommaToast :

apapun yang HEAD tunjuk adalah "milik kita"

(dan hal pertama yang git rebase upstreamdilakukan a untuk memeriksa upstreamcabang di atasnya yang ingin Anda rebase: HEAD merujuk ke upstream- ourssekarang.)


Kebingungan kemungkinan datang dari peran cabang yang bekerja dalam sebuah karya klasik git merge.
Saat Anda menggabungkan:

  • "cabang yang berfungsi" adalah yang berisi apa yang "sejauh ini digabungkan", dan dianggap sebagai "milik kami",
  • sedangkan komit lainnya mewakili apa yang sedang - tidak diputar ulang tetapi - bergabung di atas cabang yang berfungsi, dan dianggap sebagai "mereka".

Seperti yang git rebasedisebutkan di halaman manual, penggabungan selama rebase berarti sisi tersebut ditukar.


Cara lain untuk mengatakan hal yang sama adalah dengan mempertimbangkan bahwa:

  • apa yang kami miliki di cabang yang diperiksa adalah ' milik kami ',
  • apa yang kami miliki (dan sedang digabungkan atau diputar ulang) adalah ' milik mereka '.

Saat digabungkan :

x--x--x--x--x(*) <- current branch B ('*'=HEAD)
    \
     \
      \--y--y--y <- other branch to merge

, kami tidak mengubah cabang 'B' saat ini, jadi apa yang kami miliki masih apa yang sedang kami kerjakan (dan kami menggabungkan dari cabang lain)

x--x--x--x--x---------o(*)  MERGE, still on branch B
    \       ^        /
     \     ours     /
      \            /
       --y--y--y--/  
               ^
              their

Tapi pada rebase , kami beralih sisi karena hal pertama yang dilakukan rebase adalah melakukan checkout cabang upstream! (untuk memutar ulang komit saat ini di atasnya)

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

A git rebase upstreampertama-tama akan mengubah HEADB ke cabang hulu HEAD(karena itu beralih dari 'milik kita' dan 'milik mereka' dibandingkan dengan cabang yang bekerja "saat ini" sebelumnya.)

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

, dan kemudian rebase akan memutar ulang komitmen 'mereka' pada cabang B 'kami' yang baru:

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

Satu-satunya langkah tambahan git svn rebaseadalah bahwa "pengambilan" svn dilakukan pertama kali di cabang jarak jauh Git yang mewakili komitmen SVN.
Anda awalnya:

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

, Anda terlebih dahulu memperbarui cabang pelacakan SVN dengan komitmen baru yang berasal dari SVN

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

, lalu Anda mengalihkan cabang saat ini ke sisi SVN (yang menjadi "milik kami")

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")

, sebelum memutar ulang komit yang sebelumnya Anda kerjakan (tapi yang sekarang menjadi "milik mereka" selama rebase itu)

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
VonC
sumber
9
Wow, jawaban yang bagus sekali, terima kasih! Saya pasti benar-benar melewatkan komentar itu di git rebasehalaman manual ...
Marc Liyanage
@epologee: sama-sama. Ini juga berguna ketika Anda hanya menggunakan git, untuk memahami apa yang terjadi selama rebase vs. penggabungan. Dan itu menambah definisi hulu: stackoverflow.com/questions/2739376/…
VonC
5
Tuhanku!!! Jenis obat apa yang dipakai Torvalds? Ini terlalu rumit! Git adalah alat yang sangat berbahaya. Anda dapat dengan mudah menghancurkan semua pekerjaan Anda jika Anda mencoba menggunakan pengetahuan luar atau intuisi Anda. Pengembangan perangkat lunak telah melewati lubang cacing!
ATL_DEV
@ user148298 Tidak ada yang salah untuk fungsi ini. Anda tidak perlu mengetahui semua hal semacam itu kecuali Anda adalah seorang ahli git. Dan jika Anda memang membutuhkan fungsi lanjutan, Anda harus mempelajarinya terlebih dahulu.
Earth Engine