Mendorong repositori Git yang ada ke SVN

385

Saya telah melakukan semua pekerjaan saya di Git dan mendorong ke GitHub. Saya sangat senang dengan perangkat lunak dan situsnya, dan saya tidak ingin mengubah praktik kerja saya saat ini.

Penasihat PhD saya meminta semua siswa untuk menyimpan pekerjaan mereka di repositori SVN yang diselenggarakan di universitas. Saya telah menemukan banyak dokumentasi dan tutorial tentang menarik repositori SVN yang ada ke Git, tetapi tidak ada yang mendorong repositori Git ke repositori SVN yang baru. Saya berharap harus ada cara untuk melakukan ini dengan kombinasi git-svn dan cabang baru dan rebasing dan semua istilah yang indah, tapi saya seorang pemula Git dan tidak merasa percaya diri dengan salah satu dari mereka.

Saya kemudian ingin menjalankan beberapa perintah untuk mendorong commit ke repositori SVN ketika saya memilih. Saya ingin tetap menggunakan Git dan hanya memiliki mirror repositori SVN yang ada di Git.

Saya akan menjadi satu-satunya orang yang pernah berkomitmen ke SVN, jika ini ada bedanya.

kunyah
sumber
1
Catatan: Anda mungkin akan kehilangan prangko tanggal asli Anda saat melakukan ini. Tanggal baru akan didasarkan pada waktu impor ke Subversion.
nobar
Bagi mereka yang mencari informasi terkini, beberapa orang mungkin menemukan posting berikut bermanfaat saat mencari otomatisasi: deliciousbrains.com/deploying-wordpress-plugins-travis
Josh Habdas

Jawaban:

403

Saya membutuhkan ini juga, dan dengan bantuan jawaban Bombe + bermain-main, saya membuatnya bekerja. Inilah resepnya:

Impor Git -> Subversi

1. cd /path/to/git/localrepo
2. svn mkdir --parents protocol:///path/to/repo/PROJECT/trunk -m "Importing git repo"
3. git svn init protocol:///path/to/repo/PROJECT -s
4. git svn fetch
5. git rebase origin/trunk
5.1.  git status
5.2.  git add (conflicted-files)
5.3.  git rebase --continue
5.4.  (repeat 5.1.)
6. git svn dcommit

Setelah # 3 Anda akan mendapatkan pesan samar seperti ini:

Menggunakan tingkat URL yang lebih tinggi: protocol:///path/to/repo/PROJECT => protocol:///path/to/repo

Abaikan saja itu.

Ketika Anda menjalankan # 5, Anda mungkin mendapatkan konflik. Atasi ini dengan menambahkan file dengan status "unmerged" dan melanjutkan rebase. Akhirnya, Anda akan selesai; lalu sinkronkan kembali ke repositori SVN, menggunakandcommit . Itu saja.

Menyimpan repositori dalam sinkronisasi

Anda sekarang dapat menyinkronkan dari SVN ke Git, menggunakan perintah berikut:

git svn fetch
git rebase trunk

Dan untuk menyinkronkan dari Git ke SVN, gunakan:

git svn dcommit

Catatan akhir

Anda mungkin ingin mencoba ini pada salinan lokal, sebelum mendaftar ke repositori langsung. Anda dapat membuat salinan repositori Git Anda ke tempat sementara; cukup gunakan cp -r, karena semua data ada di dalam repositori itu sendiri. Anda kemudian dapat mengatur repositori pengujian berbasis file, menggunakan:

svnadmin create /home/name/tmp/test-repo

Dan periksa copy pekerjaan, menggunakan:

svn co file:///home/name/tmp/test-repo svn-working-copy

Itu akan memungkinkan Anda untuk bermain-main dengan hal-hal sebelum membuat perubahan yang langgeng.

Tambahan: Jika Anda mengacau git svn init

Jika Anda secara tidak sengaja menjalankan git svn initdengan URL yang salah, dan Anda tidak cukup pintar untuk mengambil cadangan dari pekerjaan Anda (jangan tanya ...), Anda tidak bisa hanya menjalankan perintah yang sama lagi. Namun Anda dapat membatalkan perubahan dengan menerbitkan:

rm -rf .git/svn
edit .git/config

Dan hapus bagian [svn-remote "svn"]seksi.

Anda kemudian dapat menjalankan git svn initlagi.

troelskn
sumber
2
Jawaban bagus. Apakah ini juga mengacaukan tanggal komit?
Drew Noakes
4
Pertanyaan bagus - Sayangnya, saya juga tidak tahu jawabannya. Ini lebih merupakan panduan praktis tentang apa yang saya temukan bekerja. Saya tidak sepenuhnya memahami semua detail. Mengenai tanggal komitmen, saya kira Anda bisa melakukan tes dan mencari tahu. Ingatlah bahwa Anda dapat memulai repo lokal (berbasis fs), untuk menguji berbagai hal.
troelskn
10
Saya telah mengikuti langkah-langkah yang sama ini dengan menggunakan "git rebase --onto trunk --root" sebagai pengganti langkah 5 dan jauh lebih sukses. Hanya sedikit konflik yang bisa diselesaikan, bukan ton.
kubi
5
Dalam kasus saya, urutan ini tidak berfungsi. Selalu pesan "Tidak dapat menentukan informasi SVN hulu dari sejarah HEAD" ditampilkan. Jadi, tidak ada komitmen yang mungkin.
Fedir RYKHTIK
2
Nevermind, saya mencoba untuk menjadi pintar dan menghilangkan -s karena saya tidak ingin mengikuti pengaturan standar SVN (trunk / branch / tags /). Tidak bisa berfungsi sama sekali tanpa itu.
James McMahon
33

Inilah cara kami membuatnya berfungsi:

Kloning repositori Git Anda di suatu tempat di komputer Anda.

Buka .git / config dan tambahkan berikut ini (dari Mempertahankan cermin SVN read-only dari repositori Git ):

[svn-remote "svn"]
    url = https://your.svn.repo
    fetch = :refs/remotes/git-svn

Sekarang, dari jendela konsol, ketikkan ini:

git svn fetch svn
git checkout -b svn git-svn
git merge master

Sekarang, jika rusak di sini karena alasan apa pun, ketikkan tiga baris ini:

git checkout --theirs .
git add .
git commit -m "some message"

Dan akhirnya, Anda bisa berkomitmen ke SVN:

git svn dcommit

Catatan: Saya selalu memo folder itu sesudahnya.

Alex Rouillard
sumber
6
+1 ini benar-benar bekerja untuk saya (tidak memiliki trunk / base apa pun), berbeda dengan jawaban lain yang terus memberiUnable to determine upstream SVN information from HEAD history.
stijn
2
Saya mencoba teknik ini, tetapi itu tidak mengimpor sejarah. Btw, "master git merge" sekarang "master git - memungkinkan-tidak berhubungan-histori master"
Berend de Boer
1
Jika Anda benar-benar ingin menimpa apa yang ada di SVN dengan apa yang ada di git, gunakan git merge -s recursive -Xtheirs --allow-unrelated-histories master.
user1475814
28

Menggunakan git rebasesecara langsung akan kehilangan komit pertama. Git memperlakukannya berbeda dan tidak dapat mem-rebase.

Ada prosedur yang akan mempertahankan sejarah lengkap: http://kerneltrap.org/mailarchive/git/2008/10/26/3815034

Saya akan menuliskan solusinya di sini, tetapi kredit untuk Björn.

Inisialisasi git-svn:

git svn init -s --prefix=svn/ https://svn/svn/SANDBOX/warren/test2

--Prefix memberi Anda cabang pelacakan jarak jauh seperti "svn / trunk" yang bagus karena Anda tidak mendapatkan nama ambigu jika Anda memanggil cabang lokal Anda hanya "trunk" lalu. Dan-s merupakan jalan pintas untuk tata letak trunk / tag / cabang standar.

Ambil barang awal dari SVN:

git svn fetch

Sekarang lihat hash dari komit root Anda (harus menunjukkan komit tunggal):

git rev-list --parents master | grep '^.\{40\}$'

Lalu dapatkan hash dari commit trunk yang kosong:

git rev-parse svn/trunk

Buat korupsi:

echo <root-commit-hash> <svn-trunk-commit-hash> >> .git/info/grafts

Sekarang, "gitk" harus ditampilkan svn/trunksebagai komit pertama yang menjadi dasar cabang master Anda.

Jadikan cangkok permanen:

git filter-branch -- ^svn/trunk --all

Jatuhkan korupsi:

rm .git/info/grafts

gitk masih harus ditampilkan svn/trunkdalam leluhur master.

Linearkan riwayat Anda di atas trunk:

git svn rebase

Dan sekarang "git svn dcommit -n" akan memberi tahu Anda bahwa ia akan berkomitmen untuk trunk.

git svn dcommit
Peter Mortensen
sumber
Bisakah Anda menjelaskan bagaimana teknik ini berbeda dari di atas dengan lebih jelas.
cmcginty
3
Ketika saya mencoba "git rev-parse svn / trunk" ini melaporkan revisi yang tidak diketahui atau jalur yang tidak ada di pohon kerja.
Adam Ness
Ini adalah satu-satunya jawaban yang bekerja untuk saya, kecuali langkah-langkah git filter-branch dan drop graft tidak diperlukan: Saya melakukan rebase setelah membuat graft, dan kemudian git svn dcommit.
fc7
8

Buat direktori baru di repositori Subversion untuk proyek Anda.

# svn mkdir --parents svn://ip/path/project/trunk

Ubah ke proyek Anda yang dikelola Git dan inisialisasi git-svn.

# git svn init svn://ip/path/project -s
# git svn fetch

Ini akan membuat satu komit karena direktori proyek SVN Anda masih kosong. Sekarang rebase semua yang ada di komit itu, git svn dcommitdan Anda harus selesai. Ini akan sangat mengacaukan tanggal komit Anda.

Bombe
sumber
Saya menggunakan jawaban ini dengan instruksi di hassox.blogspot.com/2007/12/using-git-with-svn.html Saya mengikuti perintah ini, lalu "#git branch -a" untuk melihat nama trunk. Lalu: # git checkout -b local-svn trunk # git merge master # git svn dcommit Ingatlah untuk .gitignore direktori .svn!
cflewis
Karena saya baru saja melakukan operasi yang sama, saya ingin membuatnya eksplisit bahwa untuk beberapa waktu sekarang (Januari '09), git dapat melakukan operasi rebase pada root commit. Ini membuat prosesnya jauh lebih sederhana daripada yang ditunjukkan oleh banyak artikel lama, lihat komentar di its.arubything.com/2009/1/4/…
Louis Jacomet
Apa yang dilakukan opsi "-s" git svn init? Saya tidak bisa melihat ini di halaman manual untuk git svn.
Nathan
Baca halaman manual lagi, mungkin cari "-s" karena ada di sana. Ini adalah alias untuk “--stdlayout”.
Bombe
7

Git -> SVN dengan riwayat komit lengkap

Saya punya proyek Git dan harus memindahkannya ke SVN. Ini adalah bagaimana saya membuatnya, menjaga seluruh sejarah komit. Satu-satunya hal yang hilang adalah waktu komit asli karena libSVN akan mengatur waktu setempat ketika kita melakukannya git svn dcommit.

Howto:

  1. Memiliki repositori SVN tempat kami ingin mengimpor barang-barang kami dan mengkloningnya dengan git-svn:

    git svn clone https://path.to/svn/repository repo.git-svn`
    
  2. Pergi kesana:

    cd repo.git-svn
    
  3. Tambahkan remote dari repositori Git (dalam contoh ini saya menggunakan C: /Projects /repo.git ). Anda ingin mendorong ke SVN dan memberinya nama old-git:

    git remote add old-git file:///C/Projects/repo.git/
    
  4. Ambil informasi dari cabang master dari repositori old-git ke repositori saat ini:

    git fetch old-git master
    
  5. Periksa cabang master dari remote lama-git ke cabang baru bernama lama dalam repositori saat ini:

    git checkout -b old old-git/master`
    
  6. Rebase untuk meletakkan HEAD di atas old-git / master. Ini akan mempertahankan semua komitmen Anda. Apa yang dilakukan ini pada dasarnya adalah mengambil semua pekerjaan Anda di Git dan meletakkannya di atas pekerjaan yang Anda akses dari SVN.

    git rebase master
    
  7. Sekarang kembali ke cabang utama Anda:

    git checkout master
    

    Dan Anda dapat melihat bahwa Anda memiliki riwayat commit yang bersih. Ini yang ingin Anda dorong ke SVN.

  8. Dorong pekerjaan Anda ke SVN:

    git svn dcommit
    

Itu saja. Ini sangat bersih, tidak ada peretasan, dan semuanya berfungsi dengan baik di luar kotak. Nikmati.

codingdave
sumber
Proses serupa juga dirinci di chani.wordpress.com/2012/01/25/…
TWiStErRob
Seperti. Namun, saya menemukan caranya sangat membingungkan dan milik saya jauh lebih pendek (8 langkah dari 19/23). Mungkin saya tidak mendapatkannya dengan benar, tetapi saya pikir dia mencampur perintah svn dan git pada peluru keduanya.
codingdave
Ah, ya, perbedaannya adalah bahwa proses Anda mengimpor git ke akar repo SVN, miliknya mengimpornya ke subfolder, itu sebabnya beberapa git svnpersiapan diperlukan.
TWiStErRob
Pada langkah 7, bukankah seharusnya ada git merge lama? Bagi saya sepertinya Anda membuat dommit master yang belum Anda ubah ?!
Alexander
@Alexander menggunakan 'git rebase master' kami menghasilkan penggabungan maju cepat, yaitu penggabungan linier tanpa penggabungan komit memiliki dua orang tua. Kami ingin memiliki sejarah linier di sini.
codingdave
4

Saya akan mengusulkan instruksi yang sangat singkat dalam 4 perintah menggunakan SubGit . Lihat posting ini untuk detailnya.

Dmitry Pavlenko
sumber
3

Saya perlu melakukan repositori Git saya yang ada ke repositori SVN kosong.

Beginilah cara saya melakukan ini:

$ git checkout master
$ git branch svn
$ git svn init -s --prefix=svn/ --username <user> https://path.to.repo.com/svn/project/
$ git checkout svn
$ git svn fetch
$ git reset --hard remotes/svn/trunk
$ git merge master
$ git svn dcommit

Itu bekerja tanpa masalah. Saya harap ini membantu seseorang.

Karena saya harus mengotorisasi sendiri dengan nama pengguna yang berbeda ke repositori SVN (saya originmenggunakan otentikasi kunci publik / pribadi), saya harus menggunakan --usernameproperti.

Jay Linski
sumber
Anda mungkin perlu menginstal git-svnsebelum ini memungkinkan, lihat stackoverflow.com/questions/527037/git-svn-not-a-git-command
flexponsive
2

Jika Anda ingin terus bekerja dengan Git sebagai repositori utama Anda dan hanya perlu "mengekspor" revisi ke SVN dari waktu ke waktu, Anda bisa menggunakan Penjahit untuk menjaga repositori SVN tetap sinkron. Itu dapat menyalin revisi antara sistem kontrol sumber yang berbeda dan akan memperbarui SVN dengan perubahan yang Anda buat di Git.

Saya belum mencoba konversi Git-ke-SVN, tetapi untuk SVN -> contoh SVN lihat jawaban ini .

sth
sumber
2

Namun urutan lain yang berhasil (dengan beberapa komentar pada setiap langkah):

  1. Instal git-svndan subversiontoolkit:

    sudo apt-get install git-svn subversion
    
  2. Beralih di dalam PROJECT_FOLDER

    cd PROJECT_FOLDER
    
  3. Buat jalur proyek di server Subversion (sayangnya git-svnplugin saat ini memiliki cacat dibandingkan dengan TortoiseSVN). Tidak dapat menyimpan kode sumber langsung ke PROJECT_FOLDER. Sebagai gantinya, secara default, itu akan mengunggah semua kode ke PROJECT_FOLDER/trunk.

    svn mkdir - protokol orang tua: /// path / ke / repo / PROJECT_FOLDER / trunk -m "membuat git repo placeholder"

Ini adalah tempat trunkdi mana ujung jalan adalah wajib

  1. Inisialisasi git-svnkonteks plugin di dalam .gitfolder

    git svn init -s protocol:///path/to/repo/PROJECT_FOLDER
    

    Ini adalah tempat trunkdi mana pada ujung jalan tidak perlu

  2. Ambil Subversioninformasi repositori kosong

    git svn fetch
    

    Langkah ini membantu menyinkronkan server Subversion dengan git-svnplugin. Ini adalah saat ketika git-svnplugin menetapkan remotes/originpath dan menghubungkannya dengan trunksubfolder di sisi server.

  3. Rebase komitmen Git lama terjadi sebelum git-svnplugin terlibat dalam proses (langkah ini opsional )

    git rebase origin/trunk
    
  4. Tambahkan file baru / yang dimodifikasi untuk dikomit (langkah ini biasa untuk aktivitas Git dan opsional )

    git add .
    
  5. Komit file yang baru ditambahkan ke dalam repositori Git lokal (langkah ini opsional dan hanya berlaku jika langkah 7 telah digunakan):

    git commit -m "Importing Git repository"
    
  6. Mendorong semua proyek mengubah sejarah ke server Subversion:

    git svn dcommit
    
Oleg Kokorin
sumber
1

Anda dapat membuat repositori SVN baru. Ekspor proyek Git Anda (menyempurnakan file .git). Tambahkan ke repositori SVN (menginisialisasi repositori dengan apa yang Anda miliki sejauh ini di Git). Kemudian gunakan instruksi untuk mengimpor repositori SVN dalam proyek Git yang baru.

Tapi ini akan kehilangan riwayat Git Anda sebelumnya.

Vasil
sumber
1

Jika Anda tidak harus menggunakan SVN tertentu dan Anda menggunakan GitHub, Anda dapat menggunakan konektor SVN mereka.

Informasi lebih lanjut ada di sini: Berkolaborasi dalam GitHub dengan Subversion

elmariofredo
sumber
SVN apa? Di ( "... setiap SVN dan ..." ). Versi SVN? Klien SVN? Atau sesuatu yang lain?
Peter Mortensen
1

Saya ingin berbagi alat hebat yang digunakan di komunitas WordPress bernama Scatter

Git plugin WordPress dan sedikit pencaritas kewarasan

Ini memungkinkan pengguna untuk dapat mengirim repositori Git mereka ke wordpress.org SVN secara otomatis. Secara teori, kode ini dapat diterapkan ke repositori SVN.

r109
sumber
Tautan tampaknya rusak secara efektif ( "Server di evansolomon.me terlalu lama untuk merespons." ).
Peter Mortensen
1

Saya baru-baru ini harus memigrasi beberapa repositori Git ke SVN, dan setelah mencoba semua solusi yang bisa saya temukan, yang akhirnya berhasil bagi saya adalah Mercurial (ya, menggunakan VCS ketiga ). Dengan menggunakan panduan ini , saya membuat proses berikut (di Linux, tetapi ide dasarnya juga bisa digunakan di Windows).

  1. Paket yang diperlukan:

    $ sudo apt-get install git subversion mercurial python-subversion
    
  2. Mercurial perlu dikonfigurasi dengan menambahkan yang berikut ke ~/.hgrc :

    [extensions]
    hgext.convert=
    
  3. Buat beberapa direktori kerja sementara (saya memiliki beberapa repositori untuk dimigrasi sehingga saya membuat direktori untuk versi SVN dan Git, untuk membuatnya terpisah):

    $ mkdir svn
    $ mkdir git
    
  4. Buat repositori lokal SVN yang kosong:

    $ svnadmin create svn/project
    
  5. Klon repositori Git yang ada:

    $ git clone server/path/project.git git/project
    
  6. Biarkan Mercurial melakukan tugasnya:

    $ hg convert --dest-type svn git/project svn/project
    
  7. Sekarang repositori SVN harus berisi histori komit penuh, tetapi tidak dengan cap waktu asli. Jika ini bukan masalah, lewati bagian selanjutnya ke langkah 11.

  8. Dengan sedikit kerja, tanggal dan waktu setiap komit dapat diubah . Karena repositori saya cukup kecil, itu layak bagi saya untuk melakukannya secara manual. Pertama, buat pre-revprop-changekait di repositori SVN dengan konten berikut, untuk memungkinkan properti yang perlu diubah:

    #!/bin/bash
    exit 0;
    

    Script ini harus dapat dieksekusi:

    $ chmod +x svn/project/hooks/pre-revprop-change
    
  9. Mercurial membuat salinan repositori SVN yang berfungsi, bernama project -wc, jadi beralihlah ke sana dan edit waktu komit:

    $ cd project-wc
    $ svn propedit svn:date --revprop -r 1
    

    Masukkan tanggal dan waktu yang benar (perhatikan zona waktu!) Dan simpan. Anda harus mendapatkan pesan yang mengatakan "Tetapkan nilai baru untuk properti svn: tanggal revisi 1".
    Sekarang bilas dan ulangi untuk setiap revisi lainnya.

  10. Opsional memeriksa riwayat komit untuk memastikan semuanya terlihat OK:

    $ svn log -r 1:HEAD
    

    Kemudian naik kembali satu tingkat:

    $ cd ..
    
  11. Buang repositori:

    $ svnadmin dump svn/project > project.dump
    
  12. Dan muat dump di server Subversion Anda. Selesai!

Proses ini mungkin juga akan bekerja secara langsung antara repositori jarak jauh, tetapi saya merasa lebih mudah untuk bekerja dengan yang lokal. Memperbaiki waktu komit adalah banyak pekerjaan, tetapi secara keseluruhan prosesnya jauh lebih mudah daripada metode lain yang saya temukan.

Indrek
sumber
1

ada tiga metode:

  1. rebase : sebagai jawaban lain

  2. komit id: cari svn id komit pertama dan git komit id pertama, gema ke git / info / graft: echo "git_id svn_id}" > .git/info/graftskemudiangit svn dcommit

  3. checkout setiap git commit, salin file ke svn_repo, svn commit

bash demo : demo github

v1.x : gunakan rebase dan lakukan id

v2.x: gunakan salin file, lalu svn commit

张耀文
sumber
0

Dalam kasus saya, saya harus memulai proyek bersih dari SVN

$ Project> git svn init protocol://path/to/repo -s
$ Project> git svn fetch

tambahkan semua sumber proyek Anda ...

$ Project> git add .
$ Project> git commit -m "Importing project sources"
$ Project> git svn dcommit
dangt85
sumber
0

Saya hanya ingin berbagi pengalaman saya dengan jawaban yang diterima. Saya melakukan semua langkah dan semuanya baik-baik saja sebelum saya menjalankan langkah terakhir:

git svn dcommit

$ git svn dcommit

Penggunaan nilai yang tidak diinisialisasi $ u dalam substitusi (s ///) di /usr/lib/perl5/vendor_perl/5.22/Git/SVN.pm baris 101.

Penggunaan nilai uninitialized $ u dalam concatenation (.) Atau string di /usr/lib/perl5/vendor_perl/5.22/Git/SVN.pm baris 101. refs / remote / origin / HEAD: ' https://192.168.2.101/ svn / PROJECT_NAME 'tidak ditemukan di' '

Saya menemukan utas https://github.com/nirvdrum/svn2git/issues/50 dan akhirnya solusi yang saya terapkan dalam file berikut di baris 101 /usr/lib/perl5/vendor_perl/5.22/Git/SVN.pm

Saya diganti

$u =~ s!^\Q$url\E(/|$)!! or die

dengan

if (!$u) {
    $u = $pathname;
} 
else {
       $u =~ s!^\Q$url\E(/|$)!! or die
      "$refname: '$url' not found in '$u'\n";
}

Ini memperbaiki masalah saya.

Pavel Slepiankou
sumber
-1

Bagaimana jika Anda tidak ingin melakukan setiap commit yang Anda buat di Git, ke repositori SVN? Bagaimana jika Anda hanya ingin mengirim komit secara selektif? Saya punya solusi yang lebih baik.

Saya menyimpan satu repositori Git lokal di mana yang saya lakukan hanyalah mengambil dan menggabungkan dari SVN. Dengan begitu saya dapat memastikan bahwa saya memasukkan semua perubahan yang sama dengan SVN, tetapi saya menjaga sejarah komit saya terpisah dari SVN sepenuhnya.

Kemudian saya menyimpan copy pekerjaan lokal SVN terpisah yang ada di folder terpisah. Itu yang saya buat komit kembali ke SVN, dan saya hanya menggunakan utilitas baris perintah SVN untuk itu.

Ketika saya siap untuk mengkomit keadaan repositori Git lokal saya ke SVN, saya cukup menyalin seluruh kekacauan file ke copy pekerjaan SVN lokal dan mengkomitnya dari sana menggunakan SVN daripada Git.

Dengan cara ini saya tidak perlu melakukan rebasing, karena rebasing seperti freebasing.

CommaToast
sumber