Geçmişte bazı iki keyfi işlem arasına bir commit nasıl enjekte edilir?


Yanıtlar:


178

OP'nin cevabından bile daha kolay.

  1. git rebase -i <any earlier commit>. Bu, yapılandırılmış metin düzenleyicinizde işlemlerin bir listesini görüntüler.
  2. Sonrasına eklemek istediğiniz commit'i bulun (bunun olduğunu varsayalım a1b2c3d). Düzenleyicinizde, o satır için, değiştirmek pickiçin edit.
  3. Yeniden oluşturmaya, metin düzenleyicinizi kapatarak başlayın (değişikliklerinizi kaydedin). Bu sizi daha önce seçtiğiniz commit ile ( a1b2c3d) sanki henüz kaydedilmiş gibi bir komut isteminde bırakır .
  4. Değişiklikleri ve yapın git commit( DEĞİL en aksine değiştiren edits). Bu, seçtiğiniz bir işlemden sonra yeni bir işlem oluşturur .
  5. git rebase --continue. Bu, ardışık kaydetmeleri yeniden oynatır ve yeni kaydetmenizi doğru yere yerleştirir.

Bunun tarihi yeniden yazacağına ve çekmeye çalışan herkesi kıracağına dikkat edin.


1
Bu, üzerine yeniden oluşturduğumdan hemen sonra değil, taahhütten sonra yeni commit'i ekledi. Sonuç, eklemek istediğim değişikliklerle sonunda yeni bir taahhütte bulunmuşum gibi aynıydı. Tarihim A -- B -- C -- Darzulanmak yerine oldu A -- D -- B -- C.
XedinUnknown

2
@XedinUnknown: O halde Rebase'i düzgün kullanmadınız.
SLaks

3
Şimdi Dherhangi bir yerde taahhüt olabilir. Varsayalım ki bu dalda olmayan A - B - Cbazı taahhütlerimiz var D. SHA'sını biliyoruz ancak yapabiliriz git rebase -i HEAD~3. Şimdi Ave B picksatırları arasına istenen hash değerini veren yeni bir pick satır pick SHAekliyoruz D. Tam hash olması gerekmez, sadece kısaltılmış olanı. git rebase -isadece kiraz seçer pick, arabellekteki satırlara göre listelenen taahhütler ; sizin için listeledikleri orijinal olanlar olmak zorunda değiller.
Kaz

1
@Kaz Bu farklı, geçerli bir cevap gibi görünüyor.
BartoszKP

3
Daha da kolay, breakanahtar kelimeyi düzenleyicideki kendi satırında iki kaydetme arasında (veya ilk satırda, belirttiğiniz commitden önce bir commit eklemek için) kullanabilirsiniz.
SimonT

30

Cevap burada bulundu oldukça basit çıktı . Bir dalda olduğunuzu varsayalım branch. Şu adımları uygulayın:

  • yeni kaydetmeyi eklemek istediğinizde kaydetmeden geçici bir dal oluşturun (bu durumda kesinleştirme A):

    git checkout -b temp A
    
  • değişiklikleri yapın ve onları kesin, bir commit yaratın, hadi buna diyelim N:

    git commit -a -m "Message"
    

    (veya git addardından git commit)

  • Yeni taahhütten sonra (bu durumda taahhüt eder Bve C) sahip olmak istediğiniz taahhütleri yeni taahhüde yeniden ekleyin:

    git rebase temp branch
    

(muhtemelen kullanmak gerekir -pherhangi olsaydı, birleştirmeleri korumak için - sayesinde hiç bir artık mevcut comment tarafından ciekawy )

  • geçici şubeyi silin:

    git branch -d temp
    

Bundan sonra tarih şu şekildedir:

A -- N -- B -- C

Yeniden yapılanma sırasında bazı çatışmaların ortaya çıkması elbette mümkündür.

Şubenizin yalnızca yerel olmaması durumunda, bu, yeniden yazma geçmişini ortaya çıkarır, bu nedenle ciddi sorunlara neden olabilir.


2
SLaks tarafından kabul edilen cevabı takip edemedim, ancak bu benim için çalıştı. İstediğim taahhüt geçmişini aldıktan sonra git push --force, uzak depoyu değiştirmek zorunda kaldım .
escapecharacter

1
Rebase'i -Xtheirs seçeneğini kullanarak kullandığınızda, çakışmaları otomatik olarak doğru bir şekilde çözer git rebase temp branch -Xtheirs. Bir komut dosyasına enjekte etmek için faydalı cevap!
David C

Benim gibi acemiler için bunu sonradan eklemek isterim git rebase temp branch, ancak öncesinde git branch -d tempyapmanız gereken tek şey, çatışmaları ve sorunları düzeltmek ve sahneye git rebase --continuekoymak, yani hiçbir şey işlemeye gerek yok, vb.
Pugsley

19

Daha da kolay çözüm:

  1. Sonunda yeni commitinizi oluşturun, D. Artık şunlara sahipsiniz:

    A -- B -- C -- D
    
  2. O zaman koş:

    $ git rebase -i hash-of-A
    
  3. Git, editörünüzü açacak ve şöyle görünecektir:

    pick 8668d21 B
    pick 650f1fc C
    pick 74096b9 D
    
  4. Sadece D'yi bu şekilde en üste taşıyın, sonra kaydedin ve çıkın

    pick 74096b9 D
    pick 8668d21 B
    pick 650f1fc C
    
  5. Şimdi sahip olacaksınız:

    A -- D -- B -- C
    

6
Güzel fikir, ancak bu değişikliklerin doğru olmasını istediğinizde D'yi C'ye eklemek zor olabilir. A'ya
BartoszKP

Birlikte yeniden düzenlemek istediğim 3 işlemim ve ortada alakasız bir taahhüdüm olduğu bir durumum var. Bu taahhüdü daha önce veya sonra taahhütler doğrultusunda hareket ettirebilmek çok güzel.
2018

13

Tarih taahhüt varsayarsak preA -- A -- B -- CBir arasına taahhüt eklemek istiyorsanız, Ave B, adımlar aşağıdaki gibi şunlardır:

  1. git rebase -i hash-of-preA

  2. Git, editörünüzü açacaktır. İçerik bundan hoşlanabilir:

    pick 8668d21 A
    pick 650f1fc B
    pick 74096b9 C
    

    İlk değiştirme pickiçin edit:

    edit 8668d21 A
    pick 650f1fc B
    pick 74096b9 C
    

    Kaydet ve çık.

  3. Kodunuzu değiştirin ve ardından git add . && git commit -m "I"

  4. git rebase --continue

Artık Git kaydetme geçmişiniz preA -- A -- I -- B -- C


Bir çakışma ile karşılaşırsanız, Git bu işlemde duracaktır. Sen kullanabilirsiniz git diffçatışma işaretleri bulmak ve bunları çözmek için. Tüm çatışmaları çözdükten sonra, git add <filename>Git'e çatışmanın çözüldüğünü söylemeniz ve ardından yeniden çalıştırmanız gerekir.git rebase --continue .

Yeniden temellemeyi geri almak istiyorsanız, kullanın git rebase --abort.


11

İşte okuduğum diğer cevaplarda görülen yeniden temelde "düzenleme hilesi" yapmaktan kaçınan bir strateji.

Kullanarak git rebase -i, o commit'den beri bir commit listesi elde edersiniz. Dosyanın en üstüne bir "ara" eklemeniz yeterlidir, bu, yeniden ödemenin bu noktada kırılmasına neden olur.

break
pick <B's hash> <B's commit message>
pick <C's hash> <C's commit message>

Bir kez başlatıldığında, git rebaseşimdi "kırılma" noktasında duracaktır. Artık dosyalarınızı düzenleyebilir ve kaydetmenizi normal şekilde oluşturabilirsiniz. Daha sonra ile yeniden ödemeye devam edebilirsiniz git rebase --continue. Bu, düzeltmeniz gereken çatışmalara neden olabilir. Eğer kaybolursanız, kullanmayı her zaman iptal edebileceğinizi unutmayın git rebase --abort.

Bu strateji herhangi bir yere bir commit eklemek için genelleştirilebilir, sadece "break" u bir commit eklemek istediğiniz noktaya koyun.

Geçmişi yeniden yazdıktan sonra unutmayınız git push -f. Şubenizi getiren diğer kişilerle ilgili olağan uyarılar geçerlidir.


Üzgünüm, bunun "yeniden ödemeden kaçınmanın" nasıl olduğunu anlamakta güçlük çekiyorum. Sen edilir çalıştıran rebaseburada. Taahhüdü yeniden ödeme sırasında mı yoksa önceden mi oluşturacağınız çok fark etmez.
BartoszKP

Woops, yeniden destekleme sırasında "düzenleme hilesinden" kaçınmayı kastettim, sanırım bunu kötü bir şekilde ifade ettim.
axerologementy

Sağ. Cevabım ayrıca yeniden tabanlamanın "düzenle" özelliğini kullanmıyor. Yine de, bu başka bir geçerli yaklaşım - teşekkürler! :-)
BartoszKP

Bu, açık ara en iyi çözüm!
Theodore R. Smith

6

Zaten burada birçok iyi cevap var. Sadece 4 kolay adımda "geri ödemesiz" bir çözüm eklemek istedim.


özet

git checkout A
git commit -am "Message for commit D"
git cherry-pick A..C
git branch -f master HEAD

açıklama

(Not: Bu çözümün bir avantajı, son adıma kadar şubenize dokunmamanızdır, sonuçtan% 100 emin olduğunuzda, çok kullanışlı bir "ön onay" adımınız olur. AB testine izin veriyor .)


Başlangıç ​​durumu ( masterŞube adınızı varsaydım )

A -- B -- C <<< master <<< HEAD

1) HEAD'i doğru yere doğrultarak başlayın

git checkout A

     B -- C <<< master
    /
   A  <<< detached HEAD

(İsteğe bağlı olarak burada, HEAD'i git checkout -b temp Aayırmak yerine, sürecin sonunda silmemiz gereken geçici bir dal oluşturabilirdik . Her iki değişken de çalışır, her şey aynı kaldığı için tercih ettiğiniz gibi yapın)


2) Eklenecek yeni D kaydını oluşturun

# at this point, make the changes you wanted to insert between A and B, then

git commit -am "Message for commit D"

     B -- C <<< master
    /
   A -- D <<< detached HEAD (or <<< temp <<< HEAD)

3) Ardından, son eksik olan B ve C işlemlerinin kopyalarını getirin (daha fazla işlem varsa aynı satır olacaktır)

git cherry-pick A..C

# (if any, resolve any potential conflicts between D and these last commits)

     B -- C <<< master
    /
   A -- D -- B' -- C' <<< detached HEAD (or <<< temp <<< HEAD)

(gerekirse burada rahat AB Testi)

Şimdi kodunuzu inceleme, test edilmesi gereken her şeyi test etme zamanı ve ayrıca sahip olduklarınızı ve işlemlerden sonra ne elde edeceğinizi ayırt edebilir / karşılaştırabilir / inceleyebilirsiniz .


4)C ve arasındaki testlerinize bağlı olarak C'ya OK ya da KO.

(EITHER) 4-OK) Son olarak,master

git branch -f master HEAD

     B -- C <<< (B and C are candidates for garbage collection)
    /
   A -- D -- B' -- C' <<< master

(OR) 4-KO) Sadece ayrılmaster Değiştirmeden

Geçici bir dal oluşturduysanız, sadece ile silin git branch -d <name>, ancak ayrılmış HEAD yoluna gittiyseniz, bu noktada hiçbir işlem yapmanız gerekmez, yeni taahhütler, yeniden bağladıktan hemen sonra çöp toplama için uygun olacaktır.HEAD a ilegit checkout master

Her iki durumda da (Tamam veya KO), bu noktada masteryeniden bağlamak için tekrar kontrol edin HEAD.

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.