Daha önce rebase'e başlamışsam iki taahhüdü nasıl birleştirebilirim?


1157

2 taahhüdü 1 ile birleştirmeye çalışıyorum, bu yüzden git ready'dan “rebase ile ezme taahhütlerini” takip ettim .

Koştum

git rebase --interactive HEAD~2

Ortaya çıkan editör, ben değiştirmek pickiçin squashve sonra kaydetme-bırakmasına rağmen, Rebase hata ile başarısız

Önceki bir taahhüt olmadan 'ezilemez'

Artık iş ağacım bu duruma ulaştığına göre, iyileşmekte zorlanıyorum.

Komut git rebase --interactive HEAD~2şununla başarısız:

Etkileşimli rebase zaten başladı

ve git rebase --continuebaşarısız olur

Önceki bir taahhüt olmadan 'ezilemez'


22
Ben de vurdum. Benim hatam git rebase -i taahhütleri git log ters sırada listeler gerçeğinden kaynaklandı; son taahhüt en altta!
lmsurprenant


Yanıtlar:


1732

özet

Hata mesajı

Önceki bir taahhüt olmadan 'ezilemez'

"aşağı doğru sıkıştırmaya" çalıştığınız anlamına gelir. Git , etkileşimli rebase yapılacaklar listesinde görüldüğü gibi eski bir taahhüdün veya “yukarı” nın daha yeni bir taahhüdünü ezer, yani önceki satırdaki bir taahhüttür. Yapılacaklar listenizdeki ilk satırdaki komutu değiştirmek, squashher zaman bu hatayı üretecektir, çünkü ilk işlemin ezilmesi için hiçbir şey yoktur.

Çözüm

Önce başladığınız yere geri dönün

$ git rebase --abort

Geçmişin olduğunu söyle

$ git log --pretty=oneline
a931ac7c808e2471b22b5bd20f0cad046b1c5d0d c
b76d157d507e819d7511132bdb5a80dd421d854f b
df239176e1a2ffac927d8b496ea00d5488481db5 a

Yani, ilk taahhüt, sonra b ve nihayet c. C'yi taahhüt ettikten sonra b ve c'yi birlikte ezmeye karar veririz:

(Not: Çalıştırıldığında git log, çıkışı lessçoğu platformda varsayılan olarak bir çağrı cihazına bağlanır . Çağrı cihazından çıkmak ve komut isteminize geri dönmek için tuşuna basın q.)

Koşu git rebase --interactive HEAD~2size bir editör verir

pick b76d157 b
pick a931ac7 c

# Rebase df23917..a931ac7 onto df23917
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

(Bu yapılacaklar listesinin çıktısıyla karşılaştırıldığında ters sırada olduğuna dikkat edin git log.)

B en Değişen pickiçin squashGördüğün hataya yol, ancak b içine c ezme yerine eğer olacaktır (daha yeni içine işlemek eski veya “yukarı ezmek”) için yapılacaklar listesini değiştirerek

pick   b76d157 b
squash a931ac7 c

ve editörünüzden çıktığınızda, içeriği olan başka bir düzenleyici edineceksiniz

# This is a combination of 2 commits.
# The first commit's message is:

b

# This is the 2nd commit message:

c

Kaydettiğinizde ve çıktığınızda, düzenlenen dosyanın içeriği yeni birleştirilmiş taahhüdün taahhüt mesajı haline gelir:

$ git log --pretty=oneline
18fd73d3ce748f2a58d1b566c03dd9dafe0b6b4f b and c
df239176e1a2ffac927d8b496ea00d5488481db5 a

Yeniden Yazma Geçmişi Hakkında Not

Etkileşimli rebase tarihi yeniden yazar. Eski geçmişi içeren bir uzaktan kumandaya aktarma girişimi, hızlı ileri sarmadığı için başarısız olacaktır.

Yeniden bastığınız şube , kendi başınıza çalıştığınız bir konu veya özellik dalıysa, önemli değil. Başka bir depoya göndermek için --forceseçenek gerekir, ya da alternatif olarak, uzak deponun izinlerine bağlı olarak, önce eski dalı silebilir ve sonra yeniden basan sürümü itebilirsiniz. Potansiyel olarak işi yok edecek komutlara örnekler bu cevabın kapsamı dışındadır.

Zaten yayınlanmış bir geçmişi, şifre sızdırma veya diğer hassas ayrıntılar gibi çok iyi bir sebep olmadan başkalarıyla birlikte çalıştığınız bir dalda yeniden yazmak, ortak çalışanlarınız üzerinde çalışmaya zorlar ve antisosyaltir ve diğer geliştiricileri rahatsız eder. İçinde “kurtarma bir Memba Rebase itibaren” bölümü git rebasebelgelerine ilave vurgu ile açıklıyor.

Diğerlerinin üzerinde çalıştığı bir şubeyi yeniden adlandırmak (veya başka bir yeniden yazma biçimi) kötü bir fikirdir: akış aşağısındaki herkes geçmişini manuel olarak düzeltmek zorunda kalır. Bu bölümde, düzeltmenin aşağı akım bakış açısından nasıl yapılacağı açıklanmaktadır. Ancak asıl düzeltme, yukarı yönde akıntıya tekrar basmaktan kaçınmak olacaktır. ...


Bir taahhüdü ezmek için rebase kullanırsam, iki değişiklik kümesini içeren yeni bir "birleşik" yürütme oluşturulur, ancak karma farklıdır. orijinal taahhütler git tarafından korunuyor mu?
fabsenet

@fabsenet Evet ve hayır. Orijinal taahhütlere hala erişilebilir, ancak artık herhangi bir ref'den (geçmişinizin ayrıntılarına bağlı olarak) erişilemez. Referanslandırılmamış taahhütler sonunda çöp toplama işlemi ile silinir.
Greg Bacon

sadece etrafta oynuyordum ... yaptım git log hashoftheoldcommitve işe yaradı, ama git log --graphtüm bu ulaşılamayan taahhütlerin
biriyle

bu kabak itmeden önce taahhütleri organize etmek için iyi bir araçtır, ancak taahhütlerden birini itersem, ezemez miyim? git diyor: HEAD başarıyla yenilendi ve güncellendi.
Sérgio

İkinci aşamada editör alamıyorum, git bash, bazı süreçlere dondurulmuş görünüyor. Ne yapalım?

411

Birden fazla işlem varsa, git rebase -iiki işlemin birini birleştirmek için kullanabilirsiniz.

Birleştirmek istediğiniz yalnızca iki taahhüt varsa ve bunlar "en son ikisi" ise, iki komutu bir arada birleştirmek için aşağıdaki komutlar kullanılabilir:

git reset --soft "HEAD^"
git commit --amend

6
Rebase ile karşılaştırıldığında olumsuz olan nedir? Kullanımı çok daha basit buluyorum.
Guillaume86

17
Rasgele sırada katılamazsınız - sadece son iki taahhüt .
dr0i

50
@ dr0i Son X taahhütleri olduğu sürece , ortada bir yerde değil , istediğiniz kadar taahhüt birleştirebilirsiniz . Sadece koş git reset --soft HEAD~10, burada 10 birleştirmek istediğin taahhütlerin sayısı.
fregante

2
Bu, uzak bir başlangıç ​​noktanız yoksa ve yalnızca iki işleminiz varsa kullanılabilir.
atedja

8
Ayrıca , taahhüdün SHA1 kimliğini nerede HEADkullanarak kullanarak kaç tane olduğunu saymak istemiyorsanız, belirli bir işleme sıfırlayabilirsiniz . git reset --soft 47b5c5...47b5c5...
dguay

112

Rebase: Buna ihtiyacın olmayacak:

En sık karşılaşılan senaryo için daha basit bir yol.

Çoğu durumda:

Aslında istediğiniz tek şey birkaç yeni taahhüdü bir araya getirmekdrop , ancak gerekmiyorsa rewordve diğer rebase çalışmaları.

basitçe şunları yapabilirsiniz:

git reset --soft "HEAD~n"
  • Varsayarsak ~niçin kaydedilmesini sayısıdır usulca un-taahhüt (yani ~1, ~2...)

Ardından, yürütme iletisini değiştirmek için aşağıdaki komutu kullanın.

git commit --amend

ki bu da uzun squashve bir menzil ile hemen hemen aynı pick.

Ve n cevap için çalışır, ancak yukarıdaki cevap istendiği gibi sadece iki taahhüt için geçerli değildir.


3
Bu, sadece 1 taahhüdü ortadan kaldırmak veya bir kod satırını değiştirmek gibi sadece taahhütleri ezmenin yanı sıra bazı ek temizlik yapmak istiyorsanız güzel.
styfle

1
Varsayarsak ~nusulca un-taahhüt (yani için kaydedilmesini sayısıdır ~1, ~2...)
Ray

1
Ya nson taahhütleri değil n, ortadaki taahhütleri birleştirmek istersem ? Bunu kolayca yapabilir miyim?
chumakoff

1
O zaman iş git rebase -iyapmanız gereken şey budur squash. @chumakoff
pambda

3
Yani, nen son taahhütleri bir, ilk kullanım git reset --soft @~m, katılmak için neredem = n - 1
Łukasz Rajchel

55

İlk önce kaç tane taahhüdünüz olduğunu kontrol etmelisiniz:

git log

İki durum vardır:

Birincisi, sadece iki taahhüt vardır:

Örneğin:

commit A
commit B

(Bu durumda, git rebase'i yapmak için kullanamazsınız) aşağıdakileri yapmanız gerekir.

$ git reset --soft HEAD^1

$ git commit --amend

Diğeri ise ikiden fazla taahhüt olması; C ve D komutlarını birleştirmek istiyorsunuz.

Örneğin:

commit A
commit B
commit C
commit D

(bu koşul altında git rebase'i kullanabilirsiniz)

git rebase -i B

Ve yapmak için "squash" kullanın. Kalan inciler çok kolaydır. Hala bilmiyorsanız, lütfen http://zerodie.github.io/blog/2012/01/19/git-rebase-i/ adresini okuyun.


Reset --soft ve commit --amend, halihazırda devam etmekte olan bir tabanınız varsa işe yarar (ve bu işlem için 'squash' yerine 'düzenle' yi seçtiyseniz) tek yoldur. +1
Jacek Lach

1
Bir depoda ilk ve sadece iki taahhüdü birleştiriyorum, tam benim durumum :-)
Chris Huang-Leaver

1
Lütfen git push -f origin mastergerekli olabilecekleri ekleyin .
Rishabh Agrahari

33

Kendi konu dalında olduğunuzu varsayarsak. Son 2 taahhüdü bir araya getirmek ve bir kahraman gibi görünmek istiyorsanız, son iki taahhüdü vermeden hemen önce taahhüdü kesin.

git checkout -b temp_branch HEAD^2

Sonra squash bu yeni branştaki diğer şubeyi taahhüt etti:

git merge branch_with_two_commits --squash

Bu, değişiklikleri getirecek, fakat onları taahhüt etmeyecektir. Bu yüzden sadece taahhüt edin ve işiniz bitti.

git commit -m "my message"

Artık bu yeni konu dalını tekrar ana dalınıza birleştirebilirsiniz.


5
Bu aslında benim için en yararlı cevaptı, çünkü manuel yeniden bastırma gerektirmedi, ancak bunun yerine tüm bir dalın tüm taahhütlerini tek bir taahhütte eziyor. Çok hoş.
Robert

Bunun için teşekkürler! Gitimi kafamda ezme resim yapmayı nasıl yapacağım budur!
Marjan Venema

inanılmaz cevap, alternatiflerden çok daha basit

Görünüşe göre, bu cevap ne zaman birleştirilmeli ave cgerektiği gibi tutulması gereken durum için uygun değildir b.
Talha Ashraf

2
Git'in son sürümlerinde bir şey değişti mi? git checkout -b combine-last-two-commits "HEAD^2"Git 2.17 sürümünde ilk komutu ( ) denediğimde bir hata alıyorum:fatal: 'HEAD^2' is not a commit and a branch 'combine-last-two-commits' cannot be created from it
mhucka

23

ile temeli iptal edebilirsiniz

git rebase --abort

ve etkileşimli rebase komutunu tekrar çalıştırdığınızda 'squash; Taahhüt, listedeki seçme taahhüdünün altında olmalıdır


16

Sıklıkla git reset --mixed'i birleştirmek istediğiniz birden fazla işlemden önce bir temel sürümü geri döndürmek için kullanıyorum, sonra yeni bir taahhütte bulunuyorum, bu şekilde taahhüdünüzü en yeni hale getirebilir, sunucuya ittikten sonra sürümünüzün KAFA olduğundan emin olabilirsiniz.

commit ac72a4308ba70cc42aace47509a5e
Author: <me@me.com>
Date:   Tue Jun 11 10:23:07 2013 +0500

    Added algorithms for Cosine-similarity

commit 77df2a40e53136c7a2d58fd847372
Author: <me@me.com>
Date:   Tue Jun 11 13:02:14 2013 -0700

    Set stage for similar objects

commit 249cf9392da197573a17c8426c282
Author: Ralph <ralph@me.com>
Date:   Thu Jun 13 16:44:12 2013 -0700

    Fixed a bug in space world automation

Kafa iki taahhüdünü bire birleştirmek istiyorsam, önce şunu kullanırım:

git reset --mixed 249cf9392da197573a17c8426c282

"249cf9392da197573a17c8426c282" üçüncü sürümdü, ayrıca birleştirmeden önce temel sürümünüz, bundan sonra yeni bir taahhütte bulunuyorum:

git add .
git commit -m 'some commit message'

Hepsi bu, umut herkes için başka bir yol.

Bilginize git reset --help:

 --mixed
     Resets the index but not the working tree (i.e., the changed files are
     preserved but not marked for commit) and reports what has not been
     updated. This is the default action.

'--Mixed' için belgeleri okumadım ama eminim diğer insanlar gönderiyi okudular ve aynı şeyi merak ettiler: --mixed kullanmanın avantajı nedir? Kılavuz sayfasının snippet'ini eklemek için yayınınızı iyileştirebilir.
funroll

@funroll Bilmiyordum - bu cevabı yazmadan önce çok karıştı , kendi tecrübeme göre, karışık işlem depo HEAD sürümü olarak argüman olarak geçtiğim sürümü belirleyecek ve bu sürümden sonra hiçbir şey kaybedilemez, bu yüzden bu değişiklikleri hala halledebiliriz.
VinceStyling

14

$ git rebase --abort

Git rebase'ini geri almak istiyorsanız bu kodu istediğiniz zaman çalıştırın

$ git rebase -i HEAD~2

Son iki taahhüdü tekrar uygulamak. Yukarıdaki komut bir kod düzenleyici açacaktır

  • [ En son taahhüt en altta olacak ]. Squash (lar) ın son taahhüdünü değiştirin. Squash önceki taahhütle kaynaşacağından.
  • Sonra esc tuşuna basın ve kaydetmek ve kapatmak için wq yazın.

Sonra: wq aktif rebase modunda olacaksın

Not : Hiçbir uyarı / hata mesajı yoksa başka bir editör alırsınız, Bir hata veya uyarı başka bir editör gösterilmezse,$ git rebase --abortbir hata görürseniz veya başka bir uyarı görürsenizçalışmayı durdurabilirsiniz. $ git rebase --continue

2 taahhüt mesajınızı göreceksiniz. Birini seçin veya kendi taahhüt mesajınızı yazın, kaydedin ve çıkın [: wq]

Not 2: rebase komutunu çalıştırırsanız, değişikliklerinizi uzak repo'ya zorlamanız gerekebilir

$ git push -f

$ git push -f origin master


1
Not 2: git push -f origin/masterDiğer cevaplar eksiktir. +1
Rishabh Agrahari

2

git cherry-pickHemen hemen her şey için kullandığım için, burada bile bunu yapmak doğaldır.

Ben var olduğu göz önüne alındığında branchXkontrol ve ben bir içeriklerini birleştirerek kesinleştirme oluşturmak istediğiniz ait bunun ucunda iki kaydedilmesini vardır, bunu yapın:

git checkout HEAD^ // Checkout the privious commit
git cherry-pick --no-commit branchX // Cherry pick the content of the second commit
git commit --amend // Create a new commit with their combined content

Ben de güncellemek istiyorsanız branchX(ve bu bu yöntemin aşağı tarafı olduğunu varsayalım) Ayrıca:

git checkout branchX
git reset --hard <the_new_commit>

1

Ana dalınız git logaşağıdaki gibi görünüyorsa:

commit ac72a4308ba70cc42aace47509a5e
Author: <me@me.com>
Date:   Tue Jun 11 10:23:07 2013 +0500

    Added algorithms for Cosine-similarity

commit 77df2a40e53136c7a2d58fd847372
Author: <me@me.com>
Date:   Tue Jun 11 13:02:14 2013 -0700

    Set stage for similar objects

commit 249cf9392da197573a17c8426c282
Author: Ralph <ralph@me.com>
Date:   Thu Jun 13 16:44:12 2013 -0700

    Fixed a bug in space world automation

üstteki iki taahhüdü birleştirmek istiyorsanız aşağıdaki kolay adımları uygulayın:

  1. İlk önce güvenli bir çıkışta olmak, ikinci bir ayrı dalda son taahhüt. Şubeye her şeyi adlandırabilirsiniz.git checkout 77df2a40e53136c7a2d58fd847372 -b merged-commits
  2. Şimdi, son adresinin değişiklikler bu yeni şube içine işlemek kiraz almak: git cherry-pick -n -x ac72a4308ba70cc42aace47509a5e. (Varsa çatışmaları giderin)
  3. Şimdi, son taahhütteki değişiklikleriniz ikinci son taahhüdünüzde var. Ama yine de taahhütte bulunmalısın, bu yüzden önce sadece kiraz seçtiğin değişiklikleri ekleyip yürüt git commit --amend.

Bu kadar. İsterseniz bu birleştirilmiş sürümü "birleştirilmiş-bağlı" dalında itebilirsiniz.

Ayrıca, ana dalınızdaki arka arkaya iki taahhüdü şimdi atabilirsiniz. Ana dalınızı şu şekilde güncelleyin:

git checkout master
git reset --hard origin/master (CAUTION: This command will remove any local changes to your master branch)
git pull

0

En son iki taahhüdü birleştirmek ve sadece eski taahhüdün mesajını kullanmak istiyorsanız, işlemi kullanarak otomatikleştirebilirsiniz expect.

Sanırım:

  • Vi'yi editör olarak kullanıyorsun
  • Taahhütleriniz her biri bir satır

İle test ettim git version 2.14.3 (Apple Git-98).


#!/usr/bin/env expect
spawn git rebase -i HEAD~2

# change the second "pick" to "squash"
# down, delete word, insert 's' (for squash), Escape, save and quit
send "jdwis \033:wq\r"

expect "# This is a"

# skip past first commit message (assumed to be one line), delete rest of file
# down 4, delete remaining lines, save and quit
send "4jdG\r:wq\r"

interact

Senaryonuzun ne yaptığı belli değil.
buhtz

@buhtz Biraz daha yorum ekledim. Hala kafa karıştırıcı bulursanız bana bildirin ve eğer öyleyse hangi kısmı.
erwaman

Scrapitinizin ne yaptığı hala belli değil. Ayrıca expecttarif edilmemiştir.
buhtz

@buhtz hangi kısım belirsiz? Daha fazla dokümantasyon içeren bir sayfaya bağlantı verdim expect.
erwaman

Komut dosyasının genel açıklaması eksik. Ne yaptığı belli değil. Bir kısım net değil. Senaryonun niyeti belirsizdir.
buhtz
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.