Git geçmişindeki belirli bir düzeltmeyi nasıl kaldırırsınız?


213

Git geçmişinizin şöyle olduğunu varsayalım:

1 2 3 4 5

1–5 ayrı düzeltmelerdir. Hala 1, 2, 4 ve 5'i tutarken 3'ü kaldırmanız gerekir. Bu nasıl yapılabilir?

Silinecek olandan sonra yüzlerce düzeltme olduğunda etkili bir yöntem var mı?


Bu soru kötü tanımlanmış. Açıkça yazarın 1-2- (3 + 4) -5 veya 1-2-4-5 istediğini söylemez
RandyTek

14
8 yıl sonra, tam olarak hangi sorunu çözmeye çalıştığımı söyleyemem. Ancak git'te her zaman bir şey yapmanın birçok yolu vardır ve çeşitli insanların sevdiği birçok cevap vardır, bu yüzden belirsizliğin çok fazla zorluğa neden olmadığını düşünüyorum
1800 BİLGİ

1
git rebase --onto 2 3 HEADhemen hemen 2 ile rebase anlamına gelir, 3 ve HEAD arasındaki taahhütler (HEAD isteğe bağlıdır veya bu durumda 5)
neaumusic

Yanıtlar:


76

Revizyon 3 ve 4'ü tek bir revizyonda birleştirmek için git rebase'i kullanabilirsiniz. Düzeltme 3'teki değişiklikleri kaldırmak istiyorsanız, etkileşimli rebase modunda edit komutunu kullanmanız gerekir. Değişiklikleri tek bir revizyonda birleştirmek istiyorsanız squash kullanın.

Bu squash tekniğini başarıyla kullandım, ancak daha önce bir revizyonu kaldırmak zorunda kalmadım. "Bölme işlemleri" altındaki git-rebase belgeleri, umarım bunu anlamanız için yeterince fikir vermelidir. (Ya da başka biri biliyor olabilir).

Gönderen git belgeler :

Olduğu gibi tutmak istediğiniz en eski taahhütle başlayın:

git rebase -i <after-this-commit>

Mevcut şubenizdeki tüm taahhütlerle (birleştirme taahhütlerini göz ardı ederek), verilen taahhütten sonra gelen bir editör çalıştırılacaktır. Bu listedeki taahhütleri kalbinizin içeriğine göre yeniden sıralayabilir ve kaldırabilirsiniz. Liste aşağı yukarı böyle görünüyor:

deadbee seç Bu taahhüdün sonucu
fa1afe1 pick Bir sonraki işlemin sonucu
...

Oneline açıklamaları sadece sizin zevkiniz içindir; git-rebase bunlara bakmaz, ancak taahhüt adlarına (bu örnekte "deadbee" ve "fa1afe1"), bu nedenle adları silmeyin veya düzenlemeyin.

"Pick" komutunu "edit" komutuyla değiştirerek, git-rebase'e bu komutu uyguladıktan sonra durmasını söyleyebilir, böylece dosyaları ve / veya taahhüt mesajını düzenleyebilir, taahhüdü değiştirebilir ve yeniden baslamaya devam edebilirsiniz.

İki veya daha fazla komutu bire katlamak istiyorsanız, ikinci ve sonraki işlem için "pick" komutunu "squash" ile değiştirin. Komisyonların farklı yazarları olsaydı, ezilmiş taahhüdü ilk taahhüdün yazarına bağlar.


42
-1 Soru iyi tanımlanmış ancak bu cevap çok açık değil. Yazar kesin çözümün ne olduğunu söylemiyor.
Aleksandr Levchuk

1
Bu yanlış bir ipucu. BÖLME KOMİTELERİ bölümü doğru değil. Kılavuzda çok daha fazla okumak istiyorsunuz - @Rares Vernica'nın cevabına bakınız.
Aleksandr Levchuk

1
@AleksandrLevchuk Soru iyi tanımlanmamış: 3'teki değişiklik kümesinin tutulması veya atılması sorusunun belirtilme biçiminden belli değil. Değişikliklerin silinmesi durumunda diğer cevapların daha kolay bir yaklaşım sunduğunu kabul edeceğim. Ancak değişiklikler korunacaksa, bu tamamen kozmetik bir işlem olacaktır. Her iki yaklaşım da tarihi, eğer başkaları kusurlu tarihin üstüne dayandırıyorsa, tehlikeli yollarla yeniden yazar; bu durumda, kozmetik temizleme yapılmamalıdır ve değişiklik silme git geri döndürme yoluyla daha iyi yapılır.
Theodore Murdock

125

Bu yorum başına (ve bunun doğru olduğunu kontrol ettim), rado'nun cevabı çok yakın ama ayrık bir kafa durumunda git bırakır. Bunun yerine, bulunduğunuz şubeden HEADkaldırmak için bunu kaldırın ve kullanın <commit-id>:

git rebase --onto <commit-id>^ <commit-id>

1
Bana sadece taahhüt kimliğine dayalı olarak bu kayıt kimliğini tarihten nasıl kaldıracağımı söyleseydin, benim kahramanım olacaksın.
kayleeFrye_onDeck

Sihirli komutun cevaba ne yaptığını açıklayabilir misiniz? Yani her bir parametrenin anlamı nedir?
alexandroid

Bu harika ama ya tarihin ilk taahhüdünü kaldırmak istersem? (bu yüzden buraya geldim: P)
Sterling Camden

2
Nedense, bunu çalıştırdığımda hiçbir şey olmuyor. Ancak, çalışmasını ^sağlamak için değiştirmek ~1.
Antimon

Geç saatlere kadar, ancak birleşme çatışmalarına girerseniz, rebase'i iptal --strategy-option theirsedip sonunda tekrar çalıştıracağınızı ekleyeceğim .
LastStar007

122

Aşağıda, <commit-id>yalnızca <commit-id>kaldırmak istediğinizi bilerek etkileşimli olmayan bir şekilde kaldırmanın bir yolu vardır :

git rebase --onto <commit-id>^ <commit-id> HEAD

2
Benim için de çalıştı. Btw, ^ operatörü ne yapıyor? Belirtilen işlemden sonraki bir sonraki işlem anlamına mı geliyor?
hopia

3
@hopia, belirtilen taahhüdün (ilk) ebeveyni anlamına gelir. Bkz. "Git yardım revizyonları"
Emil Styrke

12
HEADAyrılmış bir kafadan kaçınmak için atlamama cevabında @ kareem'in tavsiyesine bakın .
mklement0

1
Kaç kişinin aramaya geri döndüğünü bulmaktan çok daha kolay.
Dana Woodman

1
Bu harika ama ya tarihin ilk taahhüdünü kaldırmak istersem? (işte bu yüzden buraya geldim: P)
Sterling Camden

76

Daha önce belirtildiği gibi git-rebase (1) arkadaşınızdır. Taahhütlerin şubenizde olduğunu varsayarsak master, şunları yaparsınız:

git rebase --onto master~3 master~2 master

Önce:

1---2---3---4---5  master

Sonra:

1---2---4'---5' master

Git-rebase'den (1):

Rebase ile bir dizi taahhüt de kaldırılabilir. Aşağıdaki durumumuz varsa:

E---F---G---H---I---J  topicA

sonra komut

git rebase --onto topicA~5 topicA~3 topicA

F ve G komisyonlarının kaldırılmasıyla sonuçlanır:

E---H'---I'---J'  topicA

Bu, F ve G bir şekilde kusurluysa veya A konusunun bir parçası değilse faydalıdır. --Onto ve parametresinin bağımsız değişkeninin geçerli herhangi bir kesinleştirme olabileceğini unutmayın.


3
bu olmamalı --onto master~3 master~1mı?
Matthias

3
Sadece son taahhüdü silmek istiyorsanız, bu --onto master ~ 1 master
MikeHoss

Bu solu taşımak istiyorum. ama MERGE CONFLICThatayı alıyorum. Stackoverflow.com/questions/2938301/remove-specific-commit içinde belirtilen senaryo kullandım ve bu örnekte 2. taahhüdü kaldıramıyorum.
maan81

22

Tek yapmanız gereken revizyon 3'te yapılan değişiklikleri kaldırmaksa git revert komutunu kullanmak isteyebilirsiniz.

Git revert, geri almakta olduğunuz revizyondaki tüm değişiklikleri geri alan değişikliklerle yeni bir revizyon oluşturur.

Bunun anlamı, hem istenmeyen taahhüt hem de bu değişiklikleri kaldıran taahhüt hakkında bilgi tutmanızdır.

Birisi deponuzdan birisinin bu süre zarfında çekmiş olması mümkünse, bu muhtemelen çok daha dostudur, çünkü geri dönüş temelde sadece standart bir taahhüttür.


4
Ne yazık ki benim için iyi bir çözüm değil çünkü birisi yanlışlıkla repoya 100MB bok işledi, boyutu havaya uçurdu ve web arayüzünü durgun hale getirdi.
Stephen Smith

18

Şimdiye kadar olan tüm cevaplar, takip eden endişeyi gidermiyor:

Silinecek olandan sonra yüzlerce düzeltme olduğunda etkili bir yöntem var mı?

Adımlar takip edilir, ancak referans için aşağıdaki geçmişi varsayalım:

[master] -> [hundreds-of-commits-including-merges] -> [C] -> [R] -> [B]

C : kaldırılacak taahhüdü takip eden taahhüt (temiz)

R : Kaldırılacak taahhüt

B : kaldırılacak taahhütten hemen önceki taahhüt (taban)

"Yüzlerce düzeltme" kısıtlaması nedeniyle, aşağıdaki ön koşulları varsayıyorum:

  1. hiç var olmamak istediğin utanç verici bir taahhüt var
  2. aslında bu utanç verici taahhüdüne bağlı olan SIFIR müteakip taahhütleri vardır (geri dönüşte sıfır çatışma)
  3. müdahale eden yüzlerce taahhüdün 'Committer' olarak listelenmesini umursamazsınız ('Yazar' korunacaktır)
  4. depoyu hiç paylaşmadın

Bu oldukça kısıtlayıcı bir dizi kısıtlamadır, ancak aslında bu köşe durumunda çalışan ilginç bir cevap var.

İşte adımlar:

  1. git branch base B
  2. git branch remove-me R
  3. git branch save
  4. git rebase --preserve-merges --onto base remove-me

Eğer gerçekten çatışma yoksa, bu daha fazla kesinti olmaksızın devam etmelidir. Çatışmalar varsa, bunları çözebilir verebase --continue veya utançla yaşamaya karar verebilirsiniz rebase --abort.

Şimdi, masterartık R'yi taahhüt etmemiş olmalısınız . saveDaha önce bulunduğunuz yere geri şube noktaları, eğer uzlaştırmak istiyorum.

Başkalarının yeni geçmişinize aktarımını nasıl düzenlemek istediğiniz size bağlıdır. Sen tanımak gerekir stash, reset --hardve cherry-pick. Ve silebilir base, remove-meve savedalları


Bunu 150000 kez nasıl beğenebilirim?
Gena Moroz

Birisinin 150mb dosyadan oluşan bir demet işlediği bir dalın tarihinin ortasından 3 taahhüdü sırayla kaldırmak için çalıştı.
Marcos

3

Ben de benzer bir duruma düştüm. Aşağıdaki komutu kullanarak etkileşimli rebase kullanın ve seçerken 3. kesinti bırakın.

git rebase -i remote/branch

2

İşte karşılaştığım senaryo ve bunu nasıl çözdüğüm.

[branch-a]

[Hundreds of commits] -> [R] -> [I]

işte Rkaldırılmam gereken taahhüt ve Ibundan sonra gelen tek bir taahhütR

Bir geri dönüş yaptım ve onları birlikte ezdim

git revert [commit id of R]
git rebase -i HEAD~3

Etkileşimli rebase squash sırasında son 2 taahhüt.


0

Rado ve kareem'in cevapları benim için hiçbir şey yapmaz (sadece "Şimdiki şube güncel." Mesajı görünür). Muhtemelen bu, '^' sembolü Windows konsolunda çalışmadığı için olur. Ancak, bu yoruma göre , '^' yerine '~ 1' kullanılması sorunu çözmektedir.

git rebase --onto <commit-id>^ <commit-id>
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.