Yayınlanan bir şubeye bir yeniden ödeme veya sıfırlama gönderdikten sonra nasıl kurtarabilirim / yeniden senkronize edebilirim?


88

Hepimiz Ancak, bir Rebase durumunda durumla nasıl başa için yayınlanan herhangi tarifleri görmedim vb, bu tehlikeli olduğunu, tek Rebase işi yayınlanan asla duymuş olduğu yayınladı.

Şimdi, bunun yalnızca depo yalnızca bilinen (ve tercihen küçük) bir grup insan tarafından klonlanması durumunda gerçekten mümkün olduğunu unutmayın; böylece, geri ödemeyi her kim başlatırsa veya sıfırlarsa, bir dahaki sefere dikkat etmeleri gerekeceğini herkese bildirebilir. getir (!).

Gördüğüm açık bir çözüm, yerel taahhütleriniz yoksa foove yeniden borçlandırılırsa işe yarayacak :

git fetch
git checkout foo
git reset --hard origin/foo

Bu foo, uzak depoya göre yerel durumu kendi tarihinin lehine atacaktır .

Ancak kişi o şubede önemli yerel değişiklikler yaparsa durumla nasıl başa çıkılır?


Basit durum tarifi için +1. Özellikle farklı işletim sistemlerine sahiplerse, makineler arasında kişisel senkronizasyon için idealdir. Kılavuzda belirtilmesi gereken bir şey.
Philip Oakley

Kişisel senkronizasyon için ideal tarif git pull --rebase && git push. masterSadece üzerinde çalışırsanız , o zaman bu, diğer ucunda geri çekip itmiş olsanız bile, hemen hemen sizin için doğru olanı yapacaktır.
Aristo Pagaltzis

Bir PC ve bir Linux makineleri arasında senkronize edip geliştirdiğim için, her yeniden ödeme / güncelleme için yeni bir şube kullanmanın iyi sonuç verdiğini görüyorum. git reset --hard @{upstream}"Sahip olduğumu / sahip olduğumu unut, uzaktan aldığım şeyi kullan" için sihirli refspec büyüsünün artık varyantı da kullanıyorum. Son yorumumu stackoverflow.com/a/15284176/717355
Philip Oakley

Git2.0 ile şubenizin eski kökenini bulabileceksiniz (yukarı akım dalı a ile yeniden yazılmadan önce push -f): aşağıdaki
cevabıma

Yanıtlar:


75

İtilen bir geri ödemeden sonra tekrar senkronize olmak çoğu durumda o kadar da karmaşık değildir.

git checkout foo
git branch old-foo origin/foo # BEFORE fetching!!
git fetch
git rebase --onto origin/foo old-foo foo
git branch -D old-foo

Yani. ilk önce uzak şubenin başlangıçta bulunduğu yer için bir yer imi oluşturursunuz, ardından bunu, yerel taahhütlerinizi o noktadan itibaren yeniden oluşturulan uzak şubeye yeniden oynatmak için kullanırsınız.

Yeniden kullanmak şiddet gibidir: eğer probleminizi çözmezse, daha fazlasına ihtiyacınız vardır. ☺

Yeniden ödeme öncesi origin/footaahhüt kimliğine bakarsanız ve bunu kullanırsanız, bunu elbette yer imi olmadan yapabilirsiniz .

Getirmeden önce bir yer imi yapmayı unuttuğunuz durumla da bu şekilde başa çıkarsınız. Hiçbir şey kaybolmaz - sadece uzak dal için yeniden günlüğe bakmanız gerekir:

git reflog show origin/foo | awk '
    PRINT_NEXT==1 { print $1; exit }
    /fetch: forced-update/ { PRINT_NEXT=1 }'

Bu origin/foo, geçmişini değiştiren en son getirme işleminden önce işaret eden kaydetme kimliğini yazdıracaktır .

O zaman basitçe yapabilirsiniz

git rebase --onto origin/foo $commit foo

11
Kısa not: Bence oldukça sezgisel, ancak awk'ı iyi bilmiyorsanız ... bu tek git reflog show origin/foosatırlık, "getir: zorunlu güncelleme" diyen ilk satırın çıktısına bakıyor ; bir getirme, uzak dalın ileri sarma dışında herhangi bir şey yapmasına neden olduğunda git'in kaydettiği şey budur. (Bunu elle de yapabilirsiniz - zorunlu güncelleme muhtemelen en son şeydir.)
Cascabel

2
Şiddet gibi bir şey değil. Şiddet ara sıra eğlencelidir
Iolo

5
@iolo Doğru, yeniden sıralama her zaman eğlencelidir.
Dan Bechard

1
Şiddet gibi, neredeyse her zaman yeniden satış yapmaktan kaçının. Ama nasıl olacağına dair bir ipucu var.
Bob Stein

2
Başkalarının etkileneceği bir geri ödemeyi zorlamaktan kaçının.
Aristotle Pagaltzis

11

Yukarı akım yeniden ödemeden kurtarma derdimGit-rebase man sayfasının bölümünden hemen hemen tüm bunları kapsadığını .

Bu, kendi yeniden tabanınızdan kurtulmaktan gerçekten farklı değil - bir şubeyi hareket ettirirsiniz ve geçmişinde bulunan tüm şubeleri yeni konumuna geri alırsınız.


4
Ah, öyle. Ama şimdi ne dediğini anlasam da, bunu kendi başıma çözmeden önce sahip olamazdım. Ve yemek kitabı tarifi de yok (belki de haklı olarak bu tür belgelerde). "Zor durum" olarak adlandırmanın FUD olduğunu da ortaya koyacağım. Yeniden yazılmış tarihin, kurum içi gelişimin çoğu ölçeğinde önemsiz bir şekilde yönetilebilir olduğunu ileri sürüyorum. Bu konunun her zaman batıl inançla ele alınması beni rahatsız ediyor.
Aristotle Pagaltzis

4
@Aristotle: Tüm geliştiricilerin git'i nasıl kullanacaklarını bildiği ve tüm geliştiricilerle etkili bir şekilde iletişim kurabildiğiniz göz önüne alındığında, bunun çok yönetilebilir olduğu konusunda haklısınız. Mükemmel bir dünyada, hikayenin sonu bu olur. Ancak dışarıdaki pek çok proje, yukarı yönde bir geri ödemenin gerçekten korkutucu bir şey olacağı kadar büyük. (Ve sonra benim işyerim gibi, geliştiricilerin çoğunun bir geri ödeme adını bile duymadığı yerler var .) Bence "batıl inanç", mümkün olan en güvenli, en genel tavsiyeyi sağlamanın bir yolu. Kimse başkasının deposunda felakete neden olan kişi olmak istemez.
Cascabel

2
Evet, nedenini anlıyorum. Ve buna tamamen katılıyorum. Ancak, "sonuçlarını anlamıyorsanız bunu denemeyin" ve "bunu kötü olduğu için asla yapmamalısınız" ve tek başına bu konuyu ele aldığım arasında bir fark var. Korkuyu aşılamaktansa talimat vermek her zaman daha iyidir.
Aristotle Pagaltzis

@Aristotle: Kabul edildi. "Ne yaptığınızı bildiğinizden emin olun" sonuna doğru yönelmeye çalışıyorum, ancak özellikle çevrimiçi olarak, google'dan sıradan bir ziyaretçinin not alması için yeterince ağırlık vermeye çalışıyorum. Haklısın, muhtemelen çoğunun azaltılması gerekiyor.
Cascabel

11

Git ile başlayan 2014 1. Çeyrek 1.9 / 2.0, sen de açıklandığı gibi, yeniden yazılamaz memba dalı üzerinde rebasing önce önceki şube kökenli işaretlemek zorunda kalmazsınız Aristoteles Pagaltzis 'ın cevabı :
Bkz 07d406b işlemek ve d96855f taahhüt :

İle topicoluşturulan dal üzerinde çalıştıktan sonra git checkout -b topic origin/master, uzaktan izleme dalının geçmişi origin/mastergeri sarılıp yeniden oluşturulmuş ve bu şekilde bir geçmişe yol açmış olabilir:

                   o---B1
                  /
  ---o---o---B2--o---o---o---B (origin/master)
          \
           B3
            \
             Derived (topic)

nerede origin/masterkaydedilmesini noktaya kullanılan B3, B2, B1ve şimdi işaret Bve senin topicne zaman geri dalı üstünde başlandı origin/masteridi B3.

Bu mod , çatal noktası olarak origin/masterbulmak için reflog'unu kullanır, böylelikle güncellemenin üstüne şu şekilde B3yeniden topicyüklenebilirorigin/master :

$ fork_point=$(git merge-base --fork-point origin/master topic)
$ git rebase --onto origin/master $fork_point topic

Bu nedenle git merge-basekomutun yeni bir seçeneği var:

--fork-point::

Bir dalın (veya yol açan herhangi bir geçmişin <commit>) başka bir daldan (veya herhangi bir referanstan) çatallandığı noktayı bulun <ref>.
Bu, sadece iki commit'in<ref><commit><ref> ortak atasını aramakla kalmaz , aynı zamanda, dalın daha önceki bir enkarnasyonundan çatallanıp çatallaşmaya yol açan tarihin reflog'unu da hesaba katar .


" git pull --rebase" Komutu base, "" temel "durumla başa çıkmak için, şubenin çalışmasının dayandığı " "dalın (tipik olarak bir uzaktan izleme dalı) reflog girişlerini kullanarak yeniden oluşturulan dalın çatal noktasını hesaplar. şube geri sarıldı ve yeniden inşa edildi.

Örneğin, tarih nerede görünüyorsa:

  • " base" dalının şu anki ucu " " konumunda B, ancak daha önceki getirme, ucunun önceden B3ve sonra B2ve sonra B1 geçerli kaydetmeye gelmeden önce olduğunu gözlemledi ve
  • en son "temel" üzerine yeniden temel alınan şube, taahhüt üzerine kuruludur B3,

o bulmaya çalışır B3"çıkışında geçerek git rev-list --reflog base" (yani B, B1, B2, B3) bir o anki ucunun bir atası işlemek bulana kadar "Derived (topic) ".

Dahili olarak, bunu get_merge_bases_many()tek seferde hesaplayabilen buna sahibiz . " " In tüm tarihsel ipuçlarını birleştirerek sonuçlanacak hayali bir birleştirme taahhüdü
arasında bir birleştirme temeli Derivedolmasını isterdik base (origin/master).
Böyle bir kayıt olduğunda, " base" reflog girdilerinden biriyle tam olarak eşleşen tek bir sonuç almalıyız .


Git 2.1 (Q3 2014) bu bu özellik daha sağlam hale katacak: bkz 1e0dacd taahhüt tarafından John Keeping ( johnkeeping)

Aşağıdaki topolojiye sahip olduğumuz senaryoyu doğru şekilde ele alın:

    C --- D --- E  <- dev
   /
  B  <- master@{1}
 /
o --- B' --- C* --- D*  <- master

nerede:

  • B'Byama ile aynı olmayan sabitlenmiş bir sürümüdür B;
  • C*ve yanlış sırada uygulanırsa, sırasıyla ve D*yama ile aynıdır Cve Dmetinsel olarak çakışır;
  • Emetinsel olarak bağlıdır D.

Doğru sonuç git rebase master devIS Bçatal noktası olarak tanımlanır devve masterböylece C, D, Eihtiyaç üzerine yeniden oynatılır bu kaydedilmesini vardır master; ama Cve Dyama özdeş ile vardır C*ve D*sonuç, öyle ki, ve böylece düşmüş olabilir:

o --- B' --- C* --- D* --- E  <- dev

Çatal noktası tanımlanmadıysa, o zaman Biçeren bir dalı seçmek B'bir çatışmaya neden olur ve yama ile özdeş taahhütler doğru şekilde tanımlanmazsa, o zaman Ciçeren D(veya eşdeğer olarak D*) bir dalı seçmek bir çatışmaya neden olur.


" --fork-point" Modu "git rebaseGit 2.27 (Q2 2020) ile düzeltilen 2.20 çağında C de komut yeniden yazıldığında "geriledi.

Junio ​​C Hamano ( ) tarafından yapılan commit f08132f'ye (09 Aralık 2019) bakın . ( Junio ​​C Hamano tarafından birleştirildi - - in commit fb4175b , 27 Mar 2020)gitster
gitster

rebase: --fork-pointregresyon düzeltmesi

İmza: Alex Torok
[jc: düzeltmeyi yeniledi ve Alex'in testlerini kullandı]
İmza: Junio ​​C Hamano

" git rebase --fork-point master", git merge-base --fork-pointkısa refname ile nasıl başa çıkılacağını bilen ve temeldeki get_fork_point()işlevi çağırmadan önce onu tam refname olarak değiştiren dahili olarak " " olarak adlandırılan " " iyi çalışıyordu.

Bu, komut C dilinde yeniden yazıldıktan sonra, dahili çağrısı doğrudan get_fork_point() yazıldıktan kısa bir referans vermez.

"Git merge-base" içinde kullanılan "refname argümanını tam refname argümanına dwim" mantığını temeldeki işleve taşıyın get_fork_point(), böylece "git rebase" uygulamasındaki işlevin diğer çağırıcısı da aynı şekilde davranır. bu gerileme.


1
Git push --force'un artık (git 1.8.5) daha ihtiyatlı bir şekilde yapılabileceğini unutmayın: stackoverflow.com/a/18505634/6309
VonC
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.