Git'i kullanarak son X'imi bir araya getir


3588

Git'i kullanarak son X taahhüdümü nasıl tek bir taahhütte ezebilirim?




2
@matt TortoiseGit aracınızdır. Arka planda tüm adımları otomatik olarak çağıracak tek bir işlev "Tek bir işlemde birleştir" sağlar. Maalesef yalnızca Windows için kullanılabilir. Cevabımı aşağıda görebilirsiniz.
Matthias M

1
İlk taahhüdüne kadar
ezmek

1
post squash bir kuvvet yapmak gerekir itme stackoverflow.com/questions/10298291/…
vikramvi

Yanıtlar:


2092

git rebase -i <after-this-commit>İkinci ve sonraki işlemlerde "toplama" işlevini kullanın ve kılavuzda açıklandığı gibi "squash" veya "fixup" ile değiştirin .

Bu örnekte, <after-this-commit>SHA1 karması veya taahhütlerin rebase komutu için analiz edildiği geçerli dalın HEAD'ından göreli konumdur. Örneğin, kullanıcı geçmişte mevcut HEAD'den 5 taahhüt görüntülemek isterse komuttur git rebase -i HEAD~5.


260
Bu, sanırım, bu soruya biraz daha iyi cevap veriyor stackoverflow.com/a/5201642/295797
Roy Truelove

92
Ne anlama geliyor <after-this-commit>?
2540625

43
<after-this-commit>X + 1 taahhüdü, yani ezmek istediğiniz en eski taahhüdün ebeveyni.
joozek

339
Bu cevabı açık bir şekilde anlayamayacak kadar kısa buldum. Bir örnek yardımcı olabilirdi.
Ian Ollmann

54
Bu rebase -iyaklaşım ile reset --softolan arasındaki fark rebase -i, taahhüt yazarını reset --softkorumama izin verirken , tavsiye etmeme izin verir. Bazen çekme bilgilerinin taahhütlerini ezmek zorundayım, ancak yazar bilgilerini koruyorum. Bazen kendi taahhütlerimde yumuşak ayarları sıfırlamam gerekir. Her iki harika yanıta da oy verin.
zionyx

3828

Bunu, git rebaseveya olmadan oldukça kolay bir şekilde yapabilirsiniz git merge --squash. Bu örnekte, son 3 taahhüdü ezeceğiz.

Yeni taahhüt mesajını sıfırdan yazmak istiyorsanız, bu yeterli:

git reset --soft HEAD~3 &&
git commit

Yeni tamamlama mesajını mevcut tamamlama mesajlarının bir araya getirilmesiyle düzenlemeye başlamak istiyorsanız (örneğin, bir pick / squash / squash /… / squash git rebase -italimat listesinin size başlayacağı şeye benzer ), bu mesajları çıkarmanız ve geçmeniz gerekir onları git commit:

git reset --soft HEAD~3 && 
git commit --edit -m"$(git log --format=%B --reverse HEAD..HEAD@{1})"

Bu yöntemlerin her ikisi de son üç taahhüdü aynı şekilde yeni bir taahhütte ezmektedir. Yumuşak sıfırlama sadece HEAD'ı ezmek istemediğiniz son işleme yönlendirir. Ne indekse ne de çalışma ağacına yumuşak sıfırlama dokunulmaz, bu da indeksi yeni taahhüdünüz için istenen durumda bırakır (yani “atmak” üzere taahhütlerin tüm değişikliklerine zaten sahiptir).


163
Ha! Bu yöntemi seviyorum. Sorunun ruhuna kapanan odur. Çok fazla vudu gerektirmesi üzücü. Temel komutlardan birine böyle bir şey eklenmelidir. Muhtemelen git rebase --squash-recent, hatta git commit --amend-many.
Adrian Ratnapala

13
@ABB: Şubenizde “yukarı akış” kümesi varsa, branch@{upstream}(veya yalnızca @{upstream}geçerli dal için kullanabilirsiniz ; her iki durumda da, son bölüm kısaltılabilir @{u}; bkz. Gitrevisions ). Bu farklılık da “işlemek itilmiş son” (örneğin başkasının en son itme üstünde inşa edilmiş ve sonra da o getirilen o şey itilirse), ama yakın istediğinize olabilir gibi görünüyor.
Chris Johnsen

104
Bu tür sorta beni gerekli push -fama aksi takdirde çok güzeldi, teşekkürler.
2rs2ts

39
@ 2rs2ts git push -f sesi tehlikeli. Yalnızca yerel taahhütleri ezmeye özen gösterin. Asla itilen taahhütlere dokunmayın!
Matthias M

20
Daha git push --forcesonra kullanmam gerekiyor, böylece taahhüt gerekiyor
Zach Saucier

740

Bundan git merge --squashbiraz daha zarif olan bunun için kullanabilirsiniz git rebase -i. Usta olduğunuzu ve son 12 taahhüdü bir araya getirmek istediğinizi varsayalım.

UYARI: Öncelikle işinizi yaptığınızdan emin olun — git statustemiz olup olmadığını kontrol edin ( git reset --hardaşamalı ve düzenlenmemiş değişiklikleri atacağından)

Sonra:

# Reset the current branch to the commit just before the last 12:
git reset --hard HEAD~12

# HEAD@{1} is where the branch was just before the previous command.
# This command sets the state of the index to be as it would just
# after a merge from that commit:
git merge --squash HEAD@{1}

# Commit those squashed changes.  The commit message will be helpfully
# prepopulated with the commit messages of all the squashed commits:
git commit

Belgelerigit merge açıklar --squashdaha ayrıntılı olarak seçeneğini.


Güncelleme: Bu yöntemin git reset --soft HEAD~12 && git commitChris Johnsen tarafından cevabında önerilen daha basit olan tek avantajı, ezdiğiniz her taahhüt mesajıyla önceden doldurulmuş taahhüt mesajını almanızdır.


16
Bunun daha 'zarif' olduğunu söylüyorsunuz git rebase -i, ama bunun bir sebebi yok. Geçici olarak bunu -1'e çevirdi çünkü bana öyle geliyor ki tam tersi doğru ve bu bir hack; sadece özel olarak tasarlanmış git mergeşeylerden birini yapmaya zorlamak için gerekenden daha fazla komut yerine getirmiyor git rebasemusunuz?
Mark Amery

77
@ Mark Amery: Bunun daha zarif olduğunu söylememin çeşitli nedenleri var. Örneğin, bir düzenleyicinin gereksiz yere üretilmesini ve sonra "yapılacaklar" dosyasında bir dizenin aranmasını ve değiştirilmesini gerektirmez. Kullanımı git merge --squashda bir komut dosyası kullanmak daha kolaydır. Esasen, bunun mantığı, bunun için "etkileşime" hiç ihtiyaç duymamanızdı git rebase -i.
Mark Longair

12
Diğer bir avantaj ise git merge --squash, özellikle yerel bir şubeden birleşiyorsanız, yeniden baslamaya kıyasla hamle / silme / yeniden adlandırma karşısında birleştirme çakışmaları üretme olasılığının düşük olmasıdır. (tekzip: sadece bir deneyime dayanarak, bu genel durumda doğru değilse beni düzeltin!)
Cheezmeister

2
Sabit sıfırlama söz konusu olduğunda her zaman çok isteksizim - HEAD@{1}sadece güvenli tarafta olmak yerine geçici bir etiket kullanırdım, örneğin iş akışınız bir elektrik kesintisi vb. Tarafından bir saat boyunca kesildiğinde
Tobias Kienzler

8
@BT: Taahhüdünü yok ettin mi? :( Ne demek istediğinden emin değilim. Yaptığın herhangi bir şey git'in reflogundan kolayca geri dönebilirsin. geri içerikleri, bu daha fazla iş olacak olsa işinizi bile ancak ben yapılabilir biraz var korkarım, sahnelenen değildi; cevap diyor neden yukarı ön olduğunu. git statü temiz olduğundan emin "İlk onay (git reset --hard aşamalı ve düzenlenmemiş değişiklikleri atacağından beri) ".
Mark Longair

218

git resetMümkün olduğunca kaçınmanızı öneririm - özellikle Git acemiler için. Bir dizi taahhüde dayalı bir süreci gerçekten otomatikleştirmeniz gerekmedikçe , daha az egzotik bir yol var ...

  1. Ezilmeyi taahhüt edilenleri çalışan bir şubeye koy (eğer henüz yapılmamışsa) - bunun için gitk kullan
  2. Hedef dalı kontrol edin (örn. 'Master')
  3. git merge --squash (working branch name)
  4. git commit

Taahhüt mesajı squash'a göre önceden doldurulur.


4
Bu en güvenli yöntemdir: sıfırlama yumuşak / sert (!!) veya reflog kullanılmaz!
TeChn4K

14
(1) 'i genişletirseniz harika olur.
Adam

2
@Adam: Temel olarak, bu, ezmekte gitkolduğunuz kod satırını etiketlemek ve ayrıca üzerinde ezileceği tabanı etiketlemek için GUI arayüzünü kullanmak anlamına gelir . Normal durumda, bu etiketlerin her ikisi de zaten mevcut olacaktır, bu nedenle (1) adımı atlanabilir.
nobar

3
Bu yöntemin, çalışan dalı tam olarak birleştirildiğini işaretlemediğini, bu nedenle kaldırmanın zorla silinmesini gerektirdiğini unutmayın. :(
Kyrstellaine

2
(1) git branch your-feature && git reset --hard HEAD~Niçin en uygun yolu buldum . Bununla birlikte, bu cevabı önlemeye çalışan git reset'i tekrar içerir.
eis

132

Chris Johnsen'ın cevabına dayanarak ,

Bash'tan global bir "squash" takma adı ekleyin: (veya Windows'ta Git Bash)

git config --global alias.squash '!f(){ git reset --soft HEAD~${1} && git commit --edit -m"$(git log --format=%B --reverse HEAD..HEAD@{1})"; };f'

... veya Windows 'Komut İstemi'ni kullanarak:

git config --global alias.squash "!f(){ git reset --soft HEAD~${1} && git commit --edit -m\"$(git log --format=%B --reverse HEAD..HEAD@{1})\"; };f"


Sizin ~/.gitconfigşimdi bu takma adı içermelidir:

[alias]
    squash = "!f(){ git reset --soft HEAD~${1} && git commit --edit -m\"$(git log --format=%B --reverse HEAD..HEAD@{1})\"; };f"


Kullanımı:

git squash N

... Bu son Ntaahhütleri otomatik olarak bir araya getiriyor .

Not: Ortaya çıkan taahhüt mesajı, tüm ezilmiş taahhütlerin sırasıyla bir kombinasyonudur. Bundan memnun değilseniz, her zaman git commit --amendmanuel olarak değiştirebilirsiniz. (Veya takma adı zevkinize uyacak şekilde düzenleyin.)


6
İlginç, ancak ezilmiş taahhüt mesajını, benim için otomatik olarak girilmesinden çok, çoklu taahhütlerimin açıklayıcı bir özeti olarak kendim yazmayı tercih ederim. Bu yüzden git squash -m "New summary.", Notomatik olarak unpushed taahhütlerinin sayısını belirlemeyi tercih ederim .
Acumenus

1
@ABB, Bu ayrı bir soru gibi geliyor. (OP'nin tam olarak sorduğu şey olduğunu sanmıyorum; git squash iş akışımda buna hiç ihtiyaç
duymadım

3
Bu çok tatlı. Şahsen ben ezilmiş birlikte taahhüt ilk ilke mesajı kullanan bir versiyonu istiyorum. Boşluk tweaks gibi şeyler için iyi olurdu.
funroll

@funroll Kabul etti. Sadece son taahhüt mesajını bırakmak benim için çok yaygın bir ihtiyaç. Bunu tasarlayabilmeliyiz ...
Steve Clay

2
@ABB git commit --amend, iletiyi daha fazla değiştirmek için kullanabilirsiniz , ancak bu takma ad, yürütme iletisinde ne olması gerektiği konusunda iyi bir başlangıç ​​yapmanızı sağlar.
dashesy

131

Bu kullanışlı blog yazısı sayesinde , son 3 taahhüdü ezmek için bu komutu kullanabileceğinizi buldum:

git rebase -i HEAD~3

Bu, izleme bilgisi / uzaktan repo içermeyen yerel bir şubede olduğunuzda bile çalıştığı için kullanışlıdır.

Komut, etkileşimli rebase düzenleyicisini açacak ve daha sonra normal şekilde yeniden sıralamanıza, ezmenize, yeniden sarmanıza vb.


Etkileşimli rebase düzenleyicisini kullanarak:

Etkileşimli rebase editörü son üç taahhüdü gösterir. Bu kısıtlama, HEAD~3komut çalıştırılırken belirlendi git rebase -i HEAD~3.

En son işlem,, HEADilk satır 1'de görüntülenir. A ile başlayan satırlar #yorumlar / belgelerdir.

Görüntülenen belgeler oldukça açıktır. Herhangi bir satırda komutu istediğiniz komuttan değiştirebilirsiniz pick.

Komutu kullanmayı tercih ederim fixupBu yukarıdaki satırdaki komut satırındaki değişiklikleri "ezdiği" mesajını attığı .

1. satırdaki taahhüt, HEADçoğu durumda bunu olarak bırakırsınız pick. Sen kullanamaz squashveya fixupolmadığı için başka içine işlemek ezmek için taahhüt.

Taahhütlerin sırasını da değiştirebilirsiniz. Bu, kronolojik olarak bitişik olmayan komutları ezmenizi veya düzeltmenizi sağlar.

etkileşimli rebase editörü


Günlük pratik bir örnek

Son zamanlarda yeni bir özellik taahhüt ettim. O zamandan beri, iki hata düzeltmesi yaptım. Ama şimdi taahhüt ettiğim yeni özellikte bir hata (ya da sadece bir yazım hatası) keşfettim. Ne kadar can sıkıcı! Taahhüt tarihimi kirleten yeni bir taahhüt istemiyorum!

Yaptığım ilk şey hatayı düzeltmek ve yorumla yeni bir taahhütte bulunmaktır squash this into my new feature! .

Sonra çalıştırmak git logveya gitkve (bu durumda yeni özelliğin SHA taahhüt almak 1ff9460).

Sonra, etkileşimli rebase editörünü getiriyorum git rebase -i 1ff9460~. ~Tamamlamak sonra SHA editörü işlemek olduğunu eklemeyi editörü söyler.

Sonra, ben düzeltmeyi (içeren taahhüt hareket fe7f1e0özelliği işlemek ve değişim altından kadar) pickiçin fixup.

Düzenleyiciyi kapatırken, düzeltme özellik taahhüdüne dahil edilecek ve taahhüt geçmişim güzel ve temiz görünecek!

Tüm taahhütler yerel olduğunda iyi çalışır, ancak uzaktan kumandaya zaten itilmiş olan herhangi bir taahhüdü değiştirmeye çalışırsanız, aynı şubeyi kontrol eden diğer geliştiriciler için gerçekten sorunlara neden olabilirsiniz!

resim açıklamasını buraya girin


5
üstünü seçip gerisini ezmek zorunda mısın? Etkileşimli rebase editörünü nasıl daha ayrıntılı olarak açıklayacağınızı açıklamak için cevabınızı düzenlemelisiniz
Kolob Canyon

2
Evet, picksatır 1'de bırakın . Satır 1'de squashveya fixupsatırda kesinleştirme seçeneğini belirlerseniz git, "hata: önceki işlem olmadan 'düzeltilemez' 'mesajını gösterir. Sonra size düzeltme seçeneği verecektir: "Bunu 'git rebase --edit-todo' ile düzeltebilir ve sonra 'git rebase --continue' komutunu çalıştırabilirsiniz." ya da sadece iptal edip baştan başlayabilirsiniz: "Ya da 'git rebase --abort' ile rebase'i iptal edebilirsiniz.".
br3nt

56

TortoiseGit kullanıyorsanız, işlevi yapabilirsiniz Combine to one commit:

  1. TortoiseGit içerik menüsünü aç
  2. seçmek Show Log
  3. Günlük görünümünde ilgili taahhütleri işaretleme
  4. Seç Combine to one commitbağlam menüsünden

Komiteleri birleştir

Bu işlev tüm gerekli tek git adımlarını otomatik olarak yürütür. Ne yazık ki sadece Windows için kullanılabilir.


Bildiğim kadarıyla, bu birleştirme taahhütlerinde işe yaramayacak.
Thorkil Holm-Jacobsen

1
Başkaları tarafından yorumlanmasa da, bu HEAD'de olmayan taahhütler için bile çalışır. Örneğin, ihtiyacım, itmeden önce yaptığım bazı WIP taahhütlerini daha aklı başında bir açıklama ile ezmekti. Güzel çalıştı. Tabii ki, umarım bunu komutlarla nasıl yapacağımı öğrenebilirim.
Charles Roberto Canato

55

Bunu yapmak için aşağıdaki git komutunu kullanabilirsiniz.

 git rebase -i HEAD~n

n (= 4 burada) son işlem sayısıdır. Sonra aşağıdaki seçeneklere sahipsiniz,

pick 01d1124 Message....
pick 6340aaa Message....
pick ebfd367 Message....
pick 30e0ccb Message....

Aşağıdaki picktaahhütlerden birini ve squashdiğerlerini de en son sürümüne güncelleyin ,

p 01d1124 Message....
s 6340aaa Message....
s ebfd367 Message....
s 30e0ccb Message....

Detaylar için tıklayın Bağlantı


48

Bu makaleye dayanarak bu yöntemi kullanıcı tabanım için daha kolay buldum.

'Dev' şubem 96 komisyon tarafından 'origin / dev' in önünde yer aldı (bu yüzden bu komisyonlar henüz uzaktan kumandaya gönderilmedi).

Değişimi zorlamadan önce bu taahhütleri ezberlemek istedim. Şube 'orijin / dev' durumuna sıfırlamayı tercih ediyorum (bu, 96 taahhütten tüm değişiklikleri bırakacak) ve daha sonra değişiklikleri bir kerede gerçekleştirecek:

git reset origin/dev
git add --all
git commit -m 'my commit message'

1
Tam ihtiyacım olan şey. Squash aşağı özellik şubemden taahhüt eder ve daha sonra ustasıma karar verdim.
David Victor

1
Bu önceki taahhütleri ezmez!
IgorGanapolsky

@igorGanapolsky'yi biraz daha detaylandırabilir misiniz?
trudolf

3
@trudolf Bu gerçekten ezici değil (ezmek için bireysel taahhütleri seçmek). Bu, tüm değişikliklerinizi aynı anda gerçekleştirmektir.
IgorGanapolsky

15
Evet, bu yüzden tüm taahhütlerinizi tek bir yerde toplar. tebrikler!
trudolf

45

Şubede taahhütleri birleştirmek istediğinizde çalıştırın:

git rebase -i HEAD~(n number of commits back to review)

misal:

git rebase -i HEAD~1

Bu, metin düzenleyicisini açacaktır ve bu taahhütlerin bir araya getirilmesini istiyorsanız, her bir taahhüdün önündeki 'seçim'i' squash 'ile değiştirmeniz gerekir. Belgelerden:

p, pick = kullanma taahhüdü

s, squash = taahhüt kullan, ancak önceki taahhüde gir

Örneğin, tüm taahhütleri bir araya getirmek istiyorsanız, 'seçim' yaptığınız ilk taahhüttür ve gelecekteki tüm (ilkin altına yerleştirilen) 'squash' olarak ayarlanmalıdır. Vim kullanıyorsanız , düzenleyiciyi kaydedip çıkmak için : x ekle modunda kullanın.

Sonra davanın devamı için:

git rebase --continue

İşlem geçmişinizi yeniden yazmanın bu ve diğer yolları hakkında daha fazla bilgi için bu yararlı gönderiye bakın


2
Lütfen --continueve vim'in ne yaptığını da açıklayın :x.
not2qubit

Rebase, git addkullandığınız dosyalarınızda doğru yapılandırmanın ardından şubenizdeki taahhütlerden geçerken bloklar halinde gerçekleşecektirgit rebase --continue sonraki işleme geçip birleşmeye başlarsınız. :xbkz vim kullanırken dosyanın değişiklikleri kaydeder bir komut bu
aabiro

32

Anomies cevabı iyi, ama bu konuda güvensiz hissettim, bu yüzden birkaç ekran görüntüsü eklemeye karar verdim.

Adım 0: Git Log

Nerede olduğunuzu görün git log. En önemlisi, öncelikle taahhüt karmasını taahhüt bulmak yok kabak istiyorum. Yani sadece:

resim açıklamasını buraya girin

Adım 1: Git Rebase

Yürütme git rebase -i [your hash]benim durumumda,:

$ git rebase -i 2d23ea524936e612fae1ac63c95b705db44d937d

2.Adım: İstediğinizi seçin / ezin

Benim durumumda, taahhütte ilk kez olan her şeyi ezmek istiyorum. Sıralama ilkinden sonuncuya kadar, tam olarak olduğu gibi git log. Benim durumumda istiyorum:

resim açıklamasını buraya girin

3. Adım: Mesajları ayarlayın

Yalnızca bir taahhüt seçtiyseniz ve geri kalanını ezdiyseniz, bir taahhüt mesajını ayarlayabilirsiniz:

resim açıklamasını buraya girin

Bu kadar. Bunu ( :wq) kaydettikten sonra işiniz bitti. Şuna bir bakgit log .


2
nihai sonucu görmek güzel olurdu, örneğin,git log
Timothy LJ Stewart

2
Hayır teşekkürler. Taahhütlerimi aynen böyle seviyorum.
Axalix

@Axalix Tüm hatlarınızı kaldırdınız mı? Taahhütlerinizi böyle kaybedersiniz.
a3y3

31

Prosedür 1

1) Taahhüt kısa karmasını tanımlayın

# git log --pretty=oneline --abbrev-commit
abcd1234 Update to Fix for issue B
cdababcd Fix issue B
deab3412 Fix issue A
....

Burada bile git log --oneline kısa karma elde etmek için kullanılabilir.

2) Son iki işi ezmek (birleştirmek) istiyorsanız

# git rebase -i deab3412 

3) Bu nanobirleştirme için bir editör açar . Ve aşağıdaki gibi görünüyor

....
pick cdababcd Fix issue B
pick abcd1234 Update to Fix for issue B
....

4) kelimesi yeniden adlandır pickiçin squashdaha önce mevcut olan abcd1234. Yeniden adlandırdıktan sonra aşağıdaki gibi olmalıdır.

....
pick cdababcd Fix issue B
squash abcd1234 Update to Fix for issue B
....

5) Şimdi nanoeditörü kaydedin ve kapatın . Kaydetmek için ctrl + otuşuna basın Enter. Ve sonractrl + x editörden çıkmak için .

6) Sonra nano editör yorumları güncellemek için tekrar açılır, gerekirse güncelleyin.

7) Şimdi başarıyla ezildi, günlükleri kontrol ederek doğrulayabilirsiniz.

# git log --pretty=oneline --abbrev-commit
1122abcd Fix issue B
deab3412 Fix issue A
....

8) Şimdi repo yapmak için bastırın. +Şube adından önce işaret eklemek için not edin. Bu, zorla itme anlamına gelir.

# git push origin +master

Not: Bu ubuntukabuk üzerinde git kullanımına dayanır . Farklı os ( Windowsveya Mac) kullanıyorsanız, yukarıdaki komutlar editör hariç aynıdır. Farklı bir editör alabilirsiniz.

Prosedür 2

  1. Önce kesinleştirmek için gerekli dosyaları ekleyin
git add <files>
  1. Sonra --fixupseçeneği kullanarak taahhüt ve OLDCOMMITbu taahhüdü birleştirmek (squash) gerekir.
git commit --fixup=OLDCOMMIT

Şimdi bu, HEAD'ın üstünde yeni bir taahhüt yaratıyor fixup1 <OLDCOMMIT_MSG>.

  1. Ardından, yeni taahhüdü birleştirmek (ezmek) için aşağıdaki komutu yürütün OLDCOMMIT.
git rebase --interactive --autosquash OLDCOMMIT^

İşte ^önceki taahhüt anlamına gelir OLDCOMMIT. Bu rebasekomut, bir editörde (vim veya nano) etkileşimli pencereyi açar, sadece kaydetmekten ve herhangi bir şey yapmamıza gerek yoktur. Çünkü buna geçilen seçenek otomatik olarak son taahhüdü eski taahhüdün yanına taşır ve işlemifixup (squash'a eşdeğer). Sonra rebase devam eder ve biter.

Prosedür 3

  1. Gerekirse son değişikliklere yeni değişiklikler eklenerek --amendkullanılabilir git-commit.
    # git log --pretty=oneline --abbrev-commit
    cdababcd Fix issue B
    deab3412 Fix issue A
    ....
    # git add <files> # New changes
    # git commit --amend
    # git log --pretty=oneline --abbrev-commit
    1d4ab2e1 Fix issue B
    deab3412 Fix issue A
    ....  

Burada --amendson değişiklikleri son değişiklikleri birleştirir cdababcdve yeni taahhüt kimliği oluşturur1d4ab2e1

Sonuç

  • 1. prosedürün avantajı, birden fazla taahhüdü ezmek ve yeniden sıralamaktır. Ancak, çok eski taahhütlere yönelik bir düzeltmeyi birleştirmemiz gerekiyorsa, bu prosedür zor olacaktır.
  • Böylece 2. prosedür, taahhüdü çok eski taahhütle birleştirmeye yardımcı olur.
  • Ve 3. prosedür, son taahhütte yeni bir değişikliği ezmek için yararlıdır.

Sadece son iki taahhüdü günceller, hatta bir taahhüdüne sıfırladım 6. son taahhüdüne id, nedenini bilmiyorum
Carlos Liu

Taahhüt sırasını bile yeniden düzenleyebilirsiniz. İyi çalışıyor.
rashok

29

Son 10 taahhüdü 1 tek taahhütte ezmek için:

git reset --soft HEAD~10 && git commit -m "squashed commit"

Ayrıca uzak dalı ezilmiş komutla güncellemek istiyorsanız:

git push -f

- yerel kopyanızla körü körüne güncelleme yaptığı için, paylaşılan bir dalda birden fazla kişi çalışırken zorlama tehlikelidir. - en son getirdiğinizden beri uzaktan kumandanın başkalarından hiçbir taahhütte bulunmamasını sağladığından, kiralama ile zorlama daha iyi olabilirdi.
bharath

27

feature-branchBir Altın Deposundan ( golden_repo_name) klonlanmış uzak bir dalda (denir ), işte taahhütlerinizi bir araya getirme tekniği:

  1. Altın Repoyu Satın Alın

    git checkout golden_repo_name
    
  2. Aşağıdaki gibi yeni bir dal (altın repo) oluşturun

    git checkout -b dev-branch
    
  3. Zaten sahip olduğunuz yerel şubenizle kabak birleştirin

    git merge --squash feature-branch
    
  4. Değişikliklerinizi yapın (bu, dev-şubesine giren tek taahhüt olacaktır)

    git commit -m "My feature complete"
    
  5. Şubeyi yerel deponuza aktarın

    git push origin dev-branch
    

Ben sadece ~ 100 taahhüt ezmek beri (svn dalları git-svn üzerinden senkronize etmek için), bu etkileşimli yeniden basma çok daha hızlı!
adaçayı

1
Aşağı okurken, @ Chris'in yorumunu görüyorum, eskiden yaptığım şey (rebase --soft ...) - yığın akışının artık yüzlerce upvotes ile cevabı koymaması çok kötü ...
adaçayı

1
@sage ile aynı fikirde, umarız gelecekte yapabilirler
Sandesh Kumar

Bu doğru yol. Rebase yaklaşımı iyidir, ancak sadece son çare çözümü olarak squash için kullanılmalıdır.
Axalix

20

Gerçekten uygun olan ne olabilir:
Üstünde ezmek istediğiniz taahhüt karmasını bulun, diyelim d43e15.

Şimdi kullanın

git reset d43e15
git commit -am 'new commit name'

2
Bu. Neden daha fazla insan bunu kullanmıyor? Bireysel taahhütleri yeniden basmak ve ezmekten çok daha hızlıdır.
a3y3

17

Bu süper kudretli kludgy, ama bir tür havalı şekilde, bu yüzden sadece halkaya atacağım:

GIT_EDITOR='f() { if [ "$(basename $1)" = "git-rebase-todo" ]; then sed -i "2,\$s/pick/squash/" $1; else vim $1; fi }; f' git rebase -i foo~5 foo

Çeviri: git için yeni bir "editör" sağlayın, eğer düzenlenecek dosya adı git-rebase-todo(etkileşimli rebase istemi) ilk "seçim" dışındaki her şeyi "squash" olarak değiştirir ve aksi takdirde vim'i doğurur. ezilmiş taahhüt mesajını düzenlemek için vim alırsınız. (Ve açıkçası şube foo'unda son beş taahhüdü eziyordum, ancak istediğiniz gibi değiştirebilirsiniz.)

Muhtemelen Mark Longair'in önerdiğini yapardım .


7
+1: Bu eğlenceli ve öğretici, çünkü GIT_EDITOR ortam değişkenindeki bir programın adından daha karmaşık bir şey koyabileceğiniz hiç de açık değildi.
Mark Longair

16

Her bir taahhüdü tek bir taahhütte ezmek istiyorsanız (örneğin, bir projeyi ilk kez halka açarken) deneyin:

git checkout --orphan <new-branch>
git commit

15

2020 Rebase olmadan basit çözüm:

git reset --soft HEAD~2

git commit -m "new commit message"

git push --force

2, son iki işlemin ezileceği anlamına gelir. Herhangi bir sayı ile değiştirebilirsiniz


14

Bunu yapmanın en kolay yolunun, yeni bir daldan master yapmak ve özellik dalının bir birleşimini yapmaktır.

git checkout master
git checkout -b feature_branch_squashed
git merge --squash feature_branch

Sonra tüm değişiklikleri yapmaya hazırsınız.


12

Şu anda ezmek istediğiniz dalda olduğunuz göz önüne alındığında, her zaman çalışan basit bir astar, usta kaynaklandığı daldır ve en son taahhüt, kullanmak istediğiniz taahhüt mesajını ve yazarı içerir:

git reset --soft $(git merge-base HEAD master) && git commit --reuse-message=HEAD@{1}

4
Sıkıştırma taahhütleri ve ne kadar aptalca karmaşık olduğu konusunda kesinlikle hayal kırıklığına uğradım - sadece son mesajı kullanmak ve hepsini tek bir taahhütte ezmek! Neden bu kadar zor ???? Bu astar benim için bunu yapıyor. Kızgın kalbimin derinliklerinden teşekkür ederim.
Locane

12

örneğin, son 3 taahhüdü bir şubede (uzak depo) tek bir işlemde ezmek istiyorsanız, örneğin: https://bitbucket.org

Yaptığım şey

  1. git reset --soft Başkanı ~ 3 &&
  2. git taahhüt
  3. git push başlangıcı (branch_name) --force

3
Sadece dikkatli ol, çünkü kuvvet kullanırsan, onu kaldırdığından beri önceki taahhütleri almanın bir yolu yok
Albert Ruelan

12

⚠️ UYARI: "Son X işlemim" belirsiz olabilir.

  (MASTER)  
Fleetwood Mac            Fritz
      ║                    ║
  Add Danny  Lindsey     Stevie       
    Kirwan  Buckingham    Nicks                                              
      ║         ╚═══╦══════╝     
Add Christine       ║          
   Perfect      Buckingham
      ║           Nicks            
    LA1974══════════╝                                    
      ║                  
      ║                  
    Bill <══════ YOU ARE EDITING HERE
  Clinton        (CHECKED OUT, CURRENT WORKING DIRECTORY)              

Https://github.com/fleetwood-mac/band-history deposunun bu çok kısaltılmış tarihinde , Bill Clinton taahhüdünü orijinal ( MASTER) Fleetwood Mac taahhüdüne birleştirmek için bir çekme isteği açtınız.

Bir çekme isteği açtınız ve GitHub'da şunu görüyorsunuz:

Dört işlem:

  • Danny Kirwan Ekle
  • Christine Perfect ekleyin
  • LA1974
  • Bill Clinton

Hiç kimsenin depo tarihinin tamamını okumayı umursamayacağını düşünerek. (Aslında bir depo var, yukarıdaki bağlantıyı tıklayın!) Bu taahhütleri ezmeye karar verdiniz. Yani git ve kaç git reset --soft HEAD~4 && git commit. O zaman sengit push --force PR'nizi temizlemek için GitHub'a gidin.

Peki ne olacak? Fritz'den Bill Clinton'a giden tek bir taahhüt yaptın. Çünkü dün bu projenin Buckingham Nicks versiyonu üzerinde çalıştığını unuttun. Vegit log GitHub'da gördüklerinizle eşleşmiyor.

🐻 HİKAYENİN MORALI

  1. Eğer almak istediğiniz tam dosyaları bulun etmek vegit checkout onları
  2. Tarihte tutmak istediğiniz önceki kesin taahhüdü bulun ve git reset --soft o
  3. Bir Make git commitdoğrudan o çözgü gelen etmek için

1
Bu% 100 bunu yapmanın en kolay yoludur. Mevcut BAŞ ise ise istediğiniz doğru devlet, o zaman 1. atlayabilirsiniz.
Stan

İlk işlem geçmişini yeniden yazmayı sağlayan tek yol budur.
Vadorequest

9

Arasındaki taahhütlerin taahhüt mesajlarını önemsemiyorsanız,

git reset --mixed <commit-hash-into-which-you-want-to-squash>
git commit -a --amend

7

GitLab ile çalışıyorsanız, Birleştirme İsteği'ndeki Squash seçeneğini tıklamanız yeterlidir. Tamamlama mesajı, Birleştirme İsteğinin başlığı olacaktır.

resim açıklamasını buraya girin


6
git rebase -i HEAD^^

^ 'nin sayısı X

(bu durumda, son iki komutu ezin)


6

Diğer mükemmel cevaplara ek olarak, git rebase -ibeni her zaman taahhüt emriyle nasıl karıştırdığını eklemek isterim - yeni olandan daha yaşlı veya tam tersi? Bu benim iş akışım:

  1. git rebase -i HEAD~[N], burada N, en sonuncusundan başlayarak katılmak istediğim taahhütlerin sayısıdır . Yani git rebase -i HEAD~5"son 5 taahhüdü yenisine sıkıştır" anlamına gelir;
  2. editör açılır, birleştirmek istediğim taahhütlerin listesini gösterir. Şimdi ters sırada görüntülenirler : eski işlem en üstte. Orada işaretle "squash" veya "s" gibi tüm kaydedilmesini ilk / yaşlı biri hariç : başlangıç ​​noktası olarak kullanılacaktır. Düzenleyiciyi kaydedin ve kapatın;
  3. editör yeni taahhüt için varsayılan bir mesajla tekrar açılır: ihtiyaçlarınıza göre değiştirin, kaydedin ve kapatın. Squash tamamlandı!

Kaynaklar ve ek kaynaklar: # 1 , # 2 .


6

Peki böyle bir iş akışıyla ilgili soruya verilen cevap ne olacak?

  1. birçok yerel taahhüt, birden fazla FROM ustası ile karışık ,
  2. Sonunda uzaktan kumanda
  3. Halkla İlişkiler ve inceleme uzmanı tarafından birleştirmek . (Evet, geliştiricinin merge --squashHalkla İlişkiler sonrasında yapması daha kolay olurdu , ancak ekip bunun süreci yavaşlatacağını düşündü.)

Bu sayfada böyle bir iş akışı görmedim. (Bu benim gözlerim olabilir.) rebaseDoğru anlarsam, çoklu birleştirme çoklu çatışma çözümlerini gerektirir . Bunu düşünmek bile istemiyorum!

Bu bizim için işe yarıyor gibi görünüyor.

  1. git pull master
  2. git checkout -b new-branch
  3. git checkout -b new-branch-temp
  4. yerel olarak çok düzenleyin ve taahhüt edin, ustayı düzenli olarak birleştirin
  5. git checkout new-branch
  6. git merge --squash new-branch-temp // tüm değişiklikleri sahneye koyar
  7. git commit 'one message to rule them all'
  8. git push
  9. Hakem PR yapar ve master ile birleşir.

Birçok görüşten yaklaşımınızı seviyorum. Çok rahat ve hızlı
Artem Solovev

5

Ben daha genel bir çözüm 'N' taahhüt belirtmek değil, yerine ezmek istediğiniz şube / commit-id belirtmek olduğunu bulmak. Bu, belirli bir taahhüde kadar olan taahhütleri saymaktan daha az hataya açıktır - sadece etiketi doğrudan belirtin veya gerçekten saymak istiyorsanız HEAD ~ N'yi belirleyebilirsiniz.

İş akışımda bir şubeye başlıyorum ve bu daldaki ilk taahhüdüm hedefi özetliyor (yani, genellikle kamu deposuna özellik için 'son' mesaj olarak iteceğim şey). Bu yüzden bittiğinde, hepsi Yapmak istiyorum git squash master ilk mesaja geri döndüm ve sonra itmeye hazırım.

Takma adı kullanıyorum:

squash = !EDITOR="\"_() { sed -n 's/^pick //p' \"\\$1\"; sed -i .tmp '2,\\$s/^pick/f/' \"\\$1\"; }; _\"" git rebase -i

Bu, tarihin ezilmeden önce dökülmesini sağlar - bu, geri dönmek isterseniz, eski bir taahhüt kimliğini konsoldan alarak kurtarma şansı verir. (Solaris kullanıcıları GNU sed -iseçeneğini kullandığını , Mac ve Linux kullanıcılarının bu konuda iyi olması gerektiğini belirtti.)


Takma adı denedim ama sed yerlerinin herhangi bir etkisi olup olmadığından emin değilim. Ne yapmalılar?
raine

İlk sed, tarihi konsola döküyor. İkinci sed, tüm 'pick'i' f '(fixup) ile değiştirir ve editör dosyasını yerinde yeniden yazar (-i seçeneği). Böylece ikincisi tüm işi yapar.
Ethan

Haklısınız, belirli taahhütlerin N sayısını saymak hataya açıktır. Beni birkaç kez berbat etti ve rebase'i geri almaya çalışırken saatlerce boşa harcadım.
IgorGanapolsky

Merhaba Ethan, bu iş akışının birleşmede olası çatışmaları gizleyip gizlemeyeceğini bilmek istiyorum. Bu yüzden iki dalınız varsa usta ve köle düşünün. Köle efendiyle bir çatışmaya sahipse ve köle git squash masterkontrol edildiğinde kullanırız . ne olacak çatışmayı gizleyecek miyiz?
Sergio Bilello

@Sergio Bu bir yeniden yazma tarihidir, bu yüzden zaten itilmiş olan taahhütleri ezerseniz ve daha sonra ezilmiş sürümü geri birleştirmeye / yeniden birleştirmeye çalıştığınızda muhtemelen çakışmalar yaşayacaksınız. (Bazı önemsiz durumlar bundan kurtulabilir.)
Ethan

5

Söz konusu "son" ile kastedilen belirsiz olabilir.

örneğin git log --graphaşağıdakileri çıktılar (basitleştirilmiş):

* commit H0
|
* merge
|\
| * commit B0
| |
| * commit B1
| | 
* | commit H1
| |
* | commit H2
|/
|

Sonra zamana göre son taahhütler H0, birleştirme, B0. Onları ezmek için birleştirilmiş şubenizi H1 taahhüdünde yeniden birleştirmeniz gerekecek.

Sorun, H0'ın H1 ve H2 içermesidir (ve genellikle birleştirmeden önce ve dallandıktan sonra daha fazla taahhütte bulunurken) B0 içermez. Bu yüzden en azından H0, birleştirme, H1, H2, B0'daki değişiklikleri yönetmelisiniz.

Rebase kullanmak mümkündür, ancak diğerlerinden daha farklı bir şekilde belirtilen cevaplarda:

rebase -i HEAD~2

Bu size seçim seçeneklerini gösterecektir (diğer cevaplarda belirtildiği gibi):

pick B1
pick B0
pick H0

H0 yerine pick yerine squash koyun:

pick B1
pick B0
s H0

Kaydet ve çık sonra rebase H1 sonra sırayla taahhüt uygular. Bu, sizden tekrar çatışmaları çözmenizi isteyeceği anlamına gelir (HEAD başlangıçta H1 olacak ve daha sonra uygulandıkça taahhütleri biriktirecektir).

Rebase bittikten sonra ezilmiş H0 ve B0 için mesaj seçebilirsiniz:

* commit squashed H0 and B0
|
* commit B1
| 
* commit H1
|
* commit H2
|

PS Sadece BO olarak sıfırlarsanız: (örneğin, bunu kullanarak reset --mixeddaha ayrıntılı olarak burada açıklanır https://stackoverflow.com/a/18690845/2405850 ):

git reset --mixed hash_of_commit_B0
git add .
git commit -m 'some commit message'

daha sonra H0, H1, H2'nin B0 değişikliklerine girersiniz (kaybetmek, dallanma ve birleştirme öncesi değişiklikler için tamamen taahhüt eder.


4

1) git reset --soft KAFA ~ n

n - Taahhüt sayısı, ezilmeye ihtiyaç var

2) git commit -m "yeni taahhüt mesajı"

3) git push orijini branch_name --force

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.