Git-svn dcommit git'te birleştirildikten sonra tehlikeli midir?


133

Git-svn'i denemek için motivasyonum, çaba harcamadan birleşme ve dallanma. Sonra adam git-svn (1) diyor ki:

Dcommit yapmayı planladığınız bir dalda git-merge veya git-pull çalıştırmanız önerilmez. Subversion, makul veya faydalı herhangi bir şekilde birleşmeleri temsil etmez; Subversion kullanan kullanıcılar yaptığınız birleştirmeleri göremez. Ayrıca, bir SVN dalının aynası olan bir git dalını birleştirir veya çekerseniz, dcommit yanlış dal için işlem yapabilir.

Bu, svn / trunk'tan (veya bir şubeden) yerel bir dal oluşturamayacağım, hack edemeyeceğim, svn / trunk'a geri dönüp sonra dcommit yapamayacağım anlamına mı geliyor? SVN kullanıcıları her zaman oldu svn pre 1.5.x birleştirme aynı karmaşa göreceksiniz, ama başka sakıncaları var mı? Bu son cümle beni de endişelendiriyor. İnsanlar bu tür şeyleri rutin olarak yapıyor mu?


14
Bu sadece yanlış: Subversion, herhangi bir makul veya faydalı bir şekilde birleşmeleri temsil etmez; Subversion kullanan kullanıcılar sizin yaptığınız birleştirmeyi göremez. Ayrıca, bir SVN dalının aynası olan bir git dalını birleştirir veya çekerseniz, dcommit yanlış dal için işlem yapabilir. Subversion sadece git birleştirme izleme bilgilerini değil, aynı zamanda çok daha ayrıntılı bilgileri de temsil edebilir. Uygun svn: mergeinfo oluşturmayan veya uygun bir dal için dcommit yapmayan git-svn'dir.
Alexander Kitaev

2
@AlexanderKitaev: git-svn dokümanları değişti ve ek --mergeinfo=<mergeinfo>olarak birleştirme bilgisini SVN'ye aktarabilecek bir seçenek var. Yine de nasıl kullanılması gerektiğinden emin değilim.
Mr_and_Mrs_D

Yanıtlar:


174

Aslında --no-ffgit birleştirme seçeneğiyle daha da iyi bir yol buldum . Daha önce kullandığım tüm bu squash tekniği artık gerekli değil.

Yeni iş akışım şu şekilde:

  • Ben den dcommit tek dal ve o klon SVN deposu olan bir "ana" şube var ( -sdepo içerisindeki standart SVN düzenine sahip varsayalım trunk/, branches/ve tags/):

    git svn clone [-s] <svn-url>
    
  • Yerel bir dal "iş" üzerinde çalışıyorum (dal "iş" -boluşturur)

    git checkout -b work
    
  • yerel olarak "iş" şubesine girme ( -staahhüt mesajınızı kapatmak için). Devamında, 3 yerel taahhütte bulunduğunuzu varsayıyorum

    ...
    (work)$> git commit -s -m "msg 1"
    ...
    (work)$> git commit -s -m "msg 2"
    ...
    (work)$> git commit -s -m "msg 3"
    

Şimdi SVN sunucusuna katılmak istiyorsunuz

  • [Sonunda] görmek istemediğiniz değişiklikleri SVN sunucusunda saklayın (genellikle derlemeyi hızlandırmak ve belirli bir özelliğe odaklanmak istediğiniz için ana dosyada bazı kodları yorumladınız)

    (work)$> git stash
    
  • ana dalı SVN deposuyla yeniden oluştur (SVN sunucusundan güncelleştirmek için)

    (work)$> git checkout master
    (master)$> git svn rebase
    
  • iş koluna geri dön ve usta ile geri dön

    (master)$> git checkout work
    (work)$> git rebase master
    
  • Örneğin, her şeyin yolunda olduğundan emin olun:

    (work)$> git log --graph --oneline --decorate
    
  • Şimdi bu harika --no-ffseçeneği kullanarak üç işin tamamını "iş" dalından "usta" haline getirmenin zamanı geldi

    (work)$> git checkout master
    (master)$> git merge --no-ff work
    
  • Günlüklerin durumunu görebilirsiniz:

    (master)$> git log --graph --oneline --decorate
    * 56a779b (work, master) Merge branch 'work'
    |\  
    | * af6f7ae msg 3
    | * 8750643 msg 2
    | * 08464ae msg 1
    |/  
    * 21e20fa (git-svn) last svn commit
    
  • Şimdi muhtemelen amendSVN arkadaşlarınız için son taahhüdü düzenlemek ( ) istiyorsunuz (aksi takdirde "Şube işini birleştir" mesajıyla yalnızca tek bir taahhüt göreceklerdir

    (master)$> git commit --amend
    
  • Sonunda SVN sunucusunda çalışın

    (master)$> git svn dcommit
    
  • İşe geri dönün ve sonunda saklanan dosyalarınızı kurtarın:

    (master)$> git checkout work
    (work)$> git stash pop
    

4
Bu tam olarak bu git n00b'nin aradığı iş akışı. Bir hatayı düzeltmek için yerel bir şube oluşturun, her şeyi yapın, sonra bir SINGLE taahhüdüyle svn'ye gönderin. Burada en yüksek puanlı cevap kullanarak ne yaptığımı berbat - hatasız svn rebase gitemedi.
João Bragança

19
Operasyonda belirtilen git-svn belgelerinin tam olarak karşıladığı şey bu değil mi? --no-ffSeçeneği ile birleştirme çalıştırarak , hızlı ileri sarma yerine açıkça bir birleştirme taahhüdü (iki ebeveyn ile bir taahhüt) oluşturursunuz. Svn-izleme dalındaki tüm taahhütlerin tek ebeveynli taahhütler olduğundan emin olmak için, tüm birleştirmeler hızlı ileri ( --ff-onlybu konuda yardımcı olabilir) veya gövde arkanızdan değiştiyse, a --squash, değil mi?
jemmons

4
Bu, hemen sildiğiniz bir defalık dal için çalışır, ancak git svn dcommitverdiğiniz git komutunu yeniden yazar. Bu, diğer ebeveyni kaybettiğiniz anlamına gelir ve şimdi git repo'nuzun o dalı birleştirdiğiniz bir kaydı yok master. Bu, çalışma dizininizi tutarsız bir durumda da bırakabilir.
rescdsk

9
git merge --no-ff work -m "commit message"fazladan bir git commit --amendadım yerine kullanmak
tekumara

3
benim için "git merge - onlyff work" kullanmayı tercih ediyorum çünkü sadece sonuncumu değil tüm taahhütlerimi korumak istiyorum
Moataz Elmasry

49

Git-svn ile yerel şubeler oluşturmak kesinlikle mümkündür. Sadece yerel şubeleri kendiniz için kullandığınız ve yukarı akış svn dalları arasında birleştirmek için git kullanmaya çalışmadığınız sürece, iyi olmalısınız.

Svn sunucusunu izlemek için kullandığım bir "ana" dalı var. Dcommit olduğum tek şube bu. Biraz iş yapıyorsam, bir konu dalı oluşturup üzerinde çalışıyorum. Taahhüt etmek istediğimde aşağıdakileri yaparım:

  1. Her şeyi konu şubesine ada
  2. git svn rebase (işinizle svn arasındaki çakışmaları giderin)
  3. git ödeme yöneticisi
  4. git svn rebase (bu, bir sonraki adımı hızlı ileri bir birleştirme yapar, aşağıdaki Aaron'ın yorumlarına bakın)
  5. git merge topic_branch
  6. herhangi bir birleşme çatışmasını çözme (bu noktada herhangi bir şey olmamalıdır)
  7. git svn dcommit

Ben de svn kadar itilmesi gereken bazı yerel değişiklikleri (hata ayıklama için) korumak zorunda başka bir durum var. Bunun için yukarıdaki ana şubeye değil, aynı zamanda normalde çalıştığım "iş" adlı bir şubeye sahibim. Konu dalları çalışma dışıdır. Orada iş yapmak istediğimde, master'a göz atıyorum ve svn'ye taahhüt etmek istediğim iş dalından taahhütleri almak için kiraz toplama kullanıyorum. Çünkü üç yerel değişiklik taahhüdünde bulunmaktan kaçınmak istiyorum. Sonra, ana daldan dcommit ve her şeyi yeniden.

git svn dcommit -nTam olarak ne yapmak istediğinizi taahhüt etmek üzere olduğunuzdan emin olmak için ilk önce koşmaya değer . Git'in aksine, svn'de yeniden tarih yazmak zor!

Bu yerel değişiklik taahhütlerini atlarken bir konu dalındaki değişikliği birleştirmek için kiraz toplama kullanmaktan daha iyi bir yol olması gerektiğini hissediyorum, bu yüzden herhangi bir fikri varsa, memnuniyetle karşılanacaktır.


Bunu doğru anlarsam, git'de git'i svn ile birleştirmek sorun değil, svn ile svn değil mi? Yani svn / şubemi git içinde svn / trunk ile birleştiremiyorum?
Knut Eldhuset

1
Önemsiz bir şey yapmak istiyorsanız SVN'de geçmişi yeniden yazmak zor. Önemsiz durumlarda pratik olarak imkansızdır.
Aristoteles Pagaltzis

19
Greg Hewgill'in cevabının çok oyu var, ama bunun yanlış olduğuna inanıyorum. Topic_branch'tan master'a geçmek, yalnızca ileriye doğru birleştirme olduğunda güvenlidir. Birleştirme taahhüdü gerektiren gerçek bir birleştirme ise, dcommit yaptığınızda birleştirme taahhüdü kaybolacaktır. Topic_branch'ı bir dahaki sefere birleştirmeye çalıştığınızda git, ilk birleştirmenin asla gerçekleşmediğini düşünür ve tüm cehennem kırılır. Git svn dcommit neden yerel şubeler için birleştirme taahhütlerinin geçmişini kaybediyor? Sorusuna
Aaron

1
@Greg Hewgill, düzenleme net değil. Rebase'in "bir sonraki taahhüdü hızlı ileri bir birleştirme haline getirdiğini" yazdınız. Bunun ne anlama geldiğini bilmiyorum, çünkü bir hızlı ileri birleştirme bir taahhüt içermez, ama belki de "bir sonraki birleştirmeyi bir hızlı ileri birleştirme yapar" demek istediniz. Ama demek istediğin buysa, doğru değil. Topic_branch ile master arasındaki birleşmenin hızlı ileri bir birleşim olup olmadığı, şube noktasından bu yana master üzerinde herhangi bir işlem yapılıp yapılmadığına bağlıdır. Efendiyi rebase bir sonraki birleştirme mutlaka bu yüzden, yani master üzerinde yeni kaydedilmesini oluşturur değil ileri sarma birleştirme.
Aaron

1
@Aaron: Evet, orada ne düşündüğümü bilmiyorum. Tekrar düzelttim, umarım bu mantıklıdır. Sorunlardan biri, Git'te bir şeyler yapmanın birçok yolu olması, belirli bir eylem sırasını tanımlamanın oldukça açıklanması gerektiğidir .
Greg Hewgill

33

Basit çözüm: Birleştirdikten sonra 'iş' dalını kaldırın

Kısa cevap: git'i istediğiniz gibi kullanabilirsiniz (birleştirme dahil olmak üzere basit bir iş akışı için aşağıya bakın). Geçici çalışma dalını silmek için ' git branch -d work ' ile her ' git merge work ' komutunu izlediğinizden emin olun .

Arka plan açıklaması: Birleştirme / dcommit sorunu, bir dalı 'git svn dcommit' olduğunda, bu dalın birleştirme geçmişinin 'düzleştirildiğidir': git, bu dalda giden tüm birleştirme işlemlerini unutur: Yalnızca dosya içeriği korunur, ancak bu içeriğin (kısmen) başka bir branştan gelmesi kaybolur. Bakınız: git svn dcommit neden yerel şubeler için birleştirme taahhütlerinin geçmişini kaybediyor?

(Not: Git-svn'nin bu konuda yapabileceği pek bir şey yoktur: svn, çok daha güçlü git birleşmelerini anlamıyor. Bu nedenle, svn deposunun içinde bu birleştirme bilgileri hiçbir şekilde temsil edilemez.)

Ama bütün sorun bu. 'Ana dal' ile birleştirildikten sonra 'iş' dalını silerseniz, git deponuz% 100 temizdir ve svn deponuz gibi görünür.

Benim iş akışı: Tabii ki, ilk önce uzak svn deposunu yerel bir git deposuna klonladım (bu biraz zaman alabilir):

$> git svn clone <svn-repository-url> <local-directory>

Tüm işler "yerel dizin" içinde olur. Sunucudan güncellemeler almam gerektiğinde ('svn update' gibi) şunu yaparım:

$> git checkout master
$> git svn rebase

Tüm geliştirme işlerimi şu şekilde yaratılmış olan ayrı bir dalda yapıyorum:

$> git checkout -b work

Tabii ki, işiniz için istediğiniz kadar dal oluşturabilir ve aralarında dilediğiniz gibi birleştirebilir ve yeniden oluşturabilirsiniz (sadece işiniz bittiğinde onları silebilirsiniz - aşağıda tartışıldığı gibi). Normal işimde çok sık taahhüt ediyorum:

$> git commit -am '-- finished a little piece of work'

Bir sonraki adım (git rebase -i) isteğe bağlıdır --- sadece svn'de arşivlemeden önce tarihi temizler: Başkalarıyla paylaşmak istediğim sabit bir mil taşına ulaştığımda, bu 'çalışmanın' tarihini yeniden yazarım taahhüt mesajlarını temizleyin ve temizleyin (diğer geliştiricilerin yolda yaptığım tüm küçük adımları ve hataları görmesi gerekmez - sadece sonuç). Bunun için yaparım

$> git log

ve svn deposunda bulunan son taahhüdün sha-1 karmasını kopyalayın (git-svn-id ile gösterildiği gibi). Sonra ararım

$> git rebase -i 74e4068360e34b2ccf0c5869703af458cde0cdcb

Sadece benim yerine son svn taahhüdümüzün sha-1 karmasını yapıştırın. Ayrıntılar için 'git help rebase' ile belgeleri okumak isteyebilirsiniz. Kısacası: Bu komut önce taahhütlerinizi sunan bir düzenleyici açar ---- sadece önceki seçimlerle ezmek istediğiniz tüm taahhütler için 'seçim'i' squash 'olarak değiştirin. Tabii ki, ilk satır bir 'seçim' olarak kalmalıdır. Bu şekilde, birçok küçük taahhüdünüzü bir veya daha fazla anlamlı birime yoğunlaştırabilirsiniz. Kaydedin ve düzenleyiciden çıkın. İşlem günlüğü iletilerini yeniden yazmanızı isteyen başka bir düzenleyici alacaksınız.

Kısacası: 'Kod korsanlığı'nı bitirdikten sonra,' iş 'şubeme diğer programcılara nasıl sunmak istediğimi (veya tarihe göz attığımda birkaç hafta içinde işi nasıl görmek istediğimi) görünene kadar masaj yapıyorum. .

Svn deposundaki değişiklikleri zorlamak için şunu yaparım:

$> git checkout master
$> git svn rebase

Şimdi svn deposunda bu sırada gerçekleşen tüm değişikliklerle güncellenen eski 'ana' şubeye geri döndük (yeni değişiklikleriniz 'iş' dalında gizli).

Yeni 'iş' değişikliklerinizle çatışabilecek değişiklikler varsa, yeni işinizi zorlayabilmeniz için önce bunları yerel olarak çözmeniz gerekir (aşağıdaki ayrıntılara bakın). Ardından, değişikliklerimizi svn'ye gönderebiliriz:

$> git checkout master
$> git merge work        # (1) merge your 'work' into 'master'
$> git branch -d work    # (2) remove the work branch immediately after merging
$> git svn dcommit       # (3) push your changes to the svn repository

Not 1: 'git branch -d work' komutu oldukça güvenlidir: Yalnızca artık ihtiyacınız olmayan dalları silmenizi sağlar (çünkü zaten geçerli dalınızla birleştirilmiştir). Çalışmanızı 'ana' dal ile birleştirmeden önce bu komutu yanlışlıkla uygularsanız, bir hata mesajı alırsınız.

Not 2: Birleştirme ve dcommit arasında 'git branch -d work' ile şubenizi sildiğinizden emin olun: Dcommit'ten sonra dalı silmeye çalışırsanız bir hata mesajı alırsınız: 'git svn dcommit' yaptığınızda git şunu unutur: şubeniz 'usta' ile birleştirildi. Güvenlik kontrolünü yapmayan 'git branch -D work' ile kaldırmalısınız.

Şimdi, yanlışlıkla 'usta' dalına saldırmaktan kaçınmak için hemen yeni bir 'iş' dalı oluşturuyorum:

$> git checkout -b work
$> git branch            # show my branches:
  master
* work

'İşinizi' svn'deki değişikliklerle entegre etmek: 'git svn rebase', benim 'iş' dalımda çalışırken diğerlerinin svn deposunu değiştirdiğini gösterdiğinde:

$> git checkout master
$> git svn rebase              # 'svn pull' changes
$> git checkout work           # go to my work
$> git checkout -b integration # make a copy of the branch
$> git merge master            # integrate my changes with theirs
$> ... check/fix/debug ...
$> ... rewrite history with rebase -i if needed

$> git checkout master         # try again to push my changes
$> git svn rebase              # hopefully no further changes to merge
$> git merge integration       # (1) merge your work with theirs
$> git branch -d work          # (2) remove branches that are merged
$> git branch -d integration   # (2) remove branches that are merged
$> git svn dcommit             # (3) push your changes to the svn repository

Daha güçlü çözümler var: Sunulan iş akışı basit: Git'in yetkilerini sadece 'update / hack / dcommit' her turunda kullanıyor --- ancak uzun vadeli proje geçmişini svn deposu kadar doğrusal bırakıyor. Sadece eski bir svn projesinde küçük ilk adımlarda git merges kullanmaya başlamak istiyorsanız bu sorun olmaz.

Eğer git birleştirmeye de daha aşina hale geldiğinde, diğer iş akışlarını keşfetmek için çekinmeyin: Eğer ne yaptığınızı biliyorsanız, yapabilirsiniz svn birleştirme ile git birleştirmeleri mix ( sadece svn birleştirme ile yardım etmeye (veya benzeri) git-svn kullanarak? )


Bu gereksiz bir şekilde karmaşık görünüyor. İnsanların yaptığını duydum git merge --squash work, neden yapmıyorsunuz? Birden fazla 'seçim' oluşturuyorsanız (8 taahhüdünüz olduğunu ve 4 taahhüdün her birini 1'e dönüştürdüğünüzü ve 2 taahhüdü ustalaştırarak birleştirdiğinizi) birleştirmeden önce şubede squash taahhütleri yaptığını görebiliyorum. Ayrıca 'iş' rebase
şubemi güncellediğimde, şubem

8

Üstte Greg Hewgill yanıtı güvenli değil! Eğer iki "git svn rebase" arasındaki bagajda herhangi bir yeni taahhüt ortaya çıkarsa, birleştirme hızlı ileri alınmayacaktır.

Git-birleştirme için "--ff-only" bayrağı kullanılarak sağlanabilir, ancak genellikle dalda "git svn rebase", yalnızca "git rebase master" (yalnızca yerel dalı). Daha sonra "git merge thebranch" ın hızlı ilerleyeceği garanti edilir.


6

Git'te svn dallarını birleştirmenin güvenli bir yolu git merge --squash kullanmaktır. Bu, bir mesaj eklemeniz için tek bir taahhüt oluşturur ve durur.

Diyelim ki svn-branch adlı bir konu svn şubeniz var.

git svn fetch
git checkout remotes/trunk -b big-merge
git merge --squash svn-branch

bu noktada svn-dalındaki tüm değişiklikleri bir endekste bekleyen tek bir işleme dönüştürüyorsunuz

git commit

Diğerlerinin de belirttiği gibi, bu taahhütlerin ayrıntı düzeyini kaybeder.
Kzqai

@Tchalvak: Bazen sadece bunu istiyorsun. Ben sık sık bir özellik şube ala "önceki taahhüt gelen sabit karışıklık" ve bu çıkmaz biter ben iyi bir itibar nedeniyle gizlemek istiyorum :-)
schoetbi

1
Evet, bunun bir ip yürüyüşü olduğunu düşünmeme rağmen, ne zaman squash yaptığınızda, daha sonra bireysel taahhütleri ayırma yeteneğinizi de kaybedersiniz. Sadece farklı standartlarda karar verme meselesi.
Kzqai

1
@schoetbi evet, yayınlamadan önce bazen dağınık geçmişi temizlemeniz gerekir. Burada 'git rebase -i <trunk>' çok yardımcı olur: / reorder / remove ve split (!) İşlemlerini gerçekleştirebilir, msg'yi seçici olarak düzeltebilirsiniz.
inger

5

Yerel git dalını master git dalına yeniden birleştirin, sonra dcommit ve bu şekilde tüm bu işlemleri sırayla yaptığınız gibi görünür, böylece svn insanlar alıştıkça doğrusal olarak görebilirler. Konu denilen yerel bir şubeniz olduğunu varsayarsak,

git rebase master topic

daha sonra taahhütlerinizi hazırlamanız için hazır olduğunuz ana dal üzerinde oynatacak

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.