Değiştirilmiş taahhüdü uzak Git deposuna nasıl gönderebilirim?


662

Kaynak kodumla biraz çalıştığımda, her zamanki işimi yaptım ve sonra uzak bir depoya ittim. Ama sonra ithalat kodumu kaynak kodunda düzenlemeyi unuttuğumu fark ettim. Bu yüzden önceki taahhüdü değiştirmek için değişiklik komutunu yapmak:

> git commit --amend

Ne yazık ki taahhüt depoya geri itilemez. Bu şekilde reddedilir:

> git push origin
To //my.remote.repo.com/stuff.git/
 ! [rejected]        master -> master (non-fast forward)
error: failed to push some refs to '//my.remote.repo.com/stuff.git/'

Ne yapmalıyım? (Uzak depoya erişebilirim.)


--Amendim yalnızca taahhüt mesajını değiştirmek olsaydı? Zaten uzaktan kumandaya gönderildiyse, yalnızca son taahhüt mesajını düzenlemenin herhangi bir yolu var mı? Bunu Github'da yaptım ve aynı iletiyi hızlı ilerlememe konusunda aldım. Sonra aşağıda bir çözüm uyguladım ama birleştirme sadece üstüne daha fazla taahhüt mesajları ekledi ..

7
@ faB: Bence bu bir SSS. Bir tamamlama mesajı çok chaning, tamamlama ile birlikte karılır bu revid (karma) değiştirir. Eğer net değilse: hayır yapamazsınız. IIRC bant dışı bilgileri notlarda saklayabilir (böylece mevcut taahhütleri değiştirmeden açıklama ekleyebilirsiniz). Belirli taahhütleri etiketlemek için etiketleri kullanın
Mart'ta

1
Yakında (git1.8.5, 4. Çeyrek 2013) daha dikkatli bir git push -forceşekilde yapabileceksiniz .
VonC

3
İşte kovboy tarzı. Daha fazla öğrenmeyin veya önceki git değişikliğini geri almanın yollarını aramayın. Sadece bazı yer tutucu kodu ekleyin, yani, Yorum ekle, biraz kod temizleme veya sadece birkaç tire çizgi çizgi ekledi .... Şimdi gerçek bir taahhüt yapmak ve uzaktan itin. Yapıldı!
nehem

@ user58777 -İşleminiz yalnızca taahhüt mesajını değiştirmek istiyorsa ve o zamandan bu yana başka yerel taahhütte bulunmadıysanız, yerel mesajınızı, taahhüt mesajını değiştirmeden önce ittiğiniz uzaktan aktarmaya sıfırlayabilirsiniz.
Scott Ahten

Yanıtlar:


504

Aslında bir kez ittim --forceve .gitdepo ve Linus BIG TIME tarafından azarlandım . Genel olarak bu, diğer insanlar için birçok sorun yaratacaktır. Basit bir cevap "Yapma".

Görüyorum ki diğerleri zaten bunu yapmak için reçete verdi, bu yüzden burada tekrar etmeyeceğim. Ancak , --force (veya + master) ile değiştirilmiş taahhüdü çıkardıktan sonra durumdan kurtulmak için bir ipucu .

  1. git reflogDeğiştirdiğiniz eski taahhüdü bulmak için kullanın (arayın oldve biz değiştirerek oluşturduğunuz yeni taahhüdü çağırırız new).
  2. İle arasında bir birleşim oluşturun oldve newağacı newgibi kaydedin git checkout new && git merge -s ours old.
  3. Bunu master'ınızla birleştirin git merge master
  4. Master'ınızı sonuçla güncelleyin git push . HEAD:master
  5. Sonucu dışarı itin.

Eğer değişiklik yapan ve nihai birleştirme lehine olduğu göreceksiniz göreceksiniz bir itme zorlayarak ortadan işlemek üzerinde Sonra talihsiz yeterince olan insanların işlerini dayalı olması newüzerine old. Daha sonraki birleşmeleri, sizin değişikliğinizden kaynaklanan oldve newbunun sonucunda ortaya çıkan çatışmaları görmeyecek , bu yüzden acı çekmek zorunda değiller.


17
Değiştirilmiş bir taahhüdü zorlamaya zorladığınızda ne olduğunu çok iyi biliyorum (tarihi yok ederek). Neyse ki, uzaktan repo bir ağ sürücüsünde olan projedeki tek geliştiriciydim, bu yüzden büyük bir anlaşma değildi. Bir değişiklik taahhüdünü birleştirmeyi hiç düşünmedim, bu yüzden bunu onaylayacağım.
12'de Spoike

61
Şirketimizde, bireyler tarafından geliştirilen özellik dallarına ... düzenli olarak zorlamaktayız.
Ondra Žižka

2
Linus'un azarlaması, tarihi zorlama seçeneği ile sildiğiniz için yapmamalısınız değil. GabrielleV'nin çözümü iyi çalışıyor, çünkü tarihini değiştirmiyor.
user411279

2
Lütfen, bu cevabın yazarı (gitster) artık var olmadığı için, 1 numaralı maddeyi açıklığa kavuşturmaya yardımcı olabilir: eski taahhüdü bul. Yedeğiniz yoksa, onu nerede bulabilirdiniz? Düzeltme ve zorla itme yok olmaz mı? Belki de hala ağaçta olan bir arkadaştan / işbirlikçiden almaya atıfta bulunuyor?
Dr Beco

2
Dr Breco git reflogbulmak için kullanabilirsiniz
Simon Zyx

269

Git güvenlik özelliği görüyorsunuz. Git, uzak dalı şubenizle güncellemeyi reddeder, çünkü şubenizin baş taahhüdü, itmekte olduğunuz şubenin geçerli baş taahhüdünün doğrudan soyundan gelmez.

Eğer durum böyle olmasaydı, o zaman aynı depoya aynı anda iten iki kişi aynı anda yeni bir taahhüt olduğunu ve en son kim iterse, önceki iticinin işini kaybetmeden bilemezdi. bunu fark ettiler.

Tek iten kişi olduğunuzu biliyorsanız ve değiştirilmiş bir taahhüdü zorlamak veya dalı geri saran bir taahhüdü zorlamak istiyorsanız, Git'i -fanahtarı kullanarak uzak dalı güncellemeye zorlayabilirsiniz .

git push -f origin master

Git, uzak depoların yapılandırma değişkenini kullanarak uzak uçtaki ileriye doğru itmeleri reddetmesine izin verdiğinden bu bile çalışmayabilir receive.denynonfastforwards. Bu durumda ret nedeni şöyle görünecektir ('uzaktan reddedilen' bölümüne dikkat edin):

 ! [remote rejected] master -> master (non-fast forward)

Bu sorunu aşmak için, uzak deponun yapılandırmasını değiştirmeniz gerekir veya kirli bir kesmek olarak dalı silerek yeniden oluşturabilirsiniz:

git push origin :master
git push origin master

Genel olarak git pushformatı kullanan son parametre <local_ref>:<remote_ref>, burada local_refyerel depodaki remote_refdalın adı ve uzak depodaki dalın adıdır. Bu komut çifti iki kısayol kullanır. :masternull local_ref değerine sahiptir; bu, uzak tarafa boş bir dal itme master, yani uzak dalın silinmesi anlamına gelir . Hiçbir :yolu olmayan bir şube adı , verilen ada sahip yerel dalı aynı ada sahip uzak şubeye iletir. masterbu durumda kısadır master:master.


2
bu github ile çalışmadı, bana şu mesajı verdi: [uzaktan reddedildi] usta (mevcut dalın silinmesi yasak)
vedang

Zorlamayı zorlamak istemedim (ki bu sorunu çözeceğini biliyordum), ama şimdi sanırım başka seçeneğim yok.
vedang

1
Assembly'le ev sahipliği yaptığım repo için çalışan tek çözüm bu.
Justin

1
Uzak ana dalın silinmesi, uzak depodaki alanı boşaltır mı?
29_12

1
@Mr_and_Mrs_D: Hemen değil, ancak bir git gckez sonra reflogların süresi dolmuş eski nesneler budanır. Depoyu klonlayan hiç kimse, şube güncellendiğinde artık erişilemeyen nesneleri alamaz.
CB Bailey

211

Hızlı rant: Kimsenin basit cevabı burada göndermemesi, Git CLI tarafından sergilenen umutsuz kullanıcı düşmanlığını gösteriyor.

Her neyse, zorlamayı denemediğinizi varsayarsak, bunu yapmanın "açık" yolu, önce çekmektir. Bu, değiştirdiğiniz (ve artık sahip olmadığınız) değişikliği yeniden çeker.

Herhangi bir çakışmayı çözdükten sonra tekrar itebilirsiniz.

Yani:

git pull

Çekme hataları alırsanız, yerel depo yapılandırmanızda bir şeyler yanlış olabilir (.git / config şube bölümünde yanlış bir referans aldım).

Ve sonra

git push

Belki de konu ile ilgili olarak "Önemsiz birleşme" hakkında daha fazla bilgi edineceksiniz.


2
Evet, bunun hakkında yazdım, bkz. Stackoverflow.com/questions/253055/… ;)
Spoike

10
Bu gerçekten beklediğim gibi çalışmıyor. İki yeni taahhüt yaratır. Biri eskisinin bir kopyası, ama değiştirilmiş değişikliklerle. Ve bir birleşme boş bir farkla işlemektedir. Hala eski taahhüdü değişmeden bırakarak değiştirmeye çalıştığım muhtemelen hassas verileri ortaya koyuyorum. Buraya gitmenin tek yolu olduğuna inanıyorum git push -fya git resetda inanıyorum .
thnee

40
Soruna teknik olarak cevap verirken, sorunu gerçekten ele almıyor. Söylediğiniz gibi, bu ekstra bir taahhüt oluşturacaktır, ancak insanların bir taahhüdü değiştirmesinin ana nedeni yeni bir tane oluşturmaktan kaçınmaktır. Eğer poster talimatlarınızı takip edecek olsaydı, istenen sonucu alamazdı. Taahhüdü ilk etapta değiştirmemek çok mantıklı olurdu.
Dan Jones

102

Kısa cevap: Değiştirilmiş taahhütleri halka açık bir repoya itmeyin.

Uzun cevap: Bazı Git komutları, git commit --amendve git rebaseaslında, geçmiş grafiğini yeniden yazar. Bu, değişikliklerinizi yayınlamadığınız sürece iyidir, ancak bir kez yaptıktan sonra gerçekten tarihle uğraşmamalısınız, çünkü birisi değişikliklerinizi zaten aldıysa, tekrar çekmeye çalıştıklarında başarısız olabilir . Bir taahhüdü değiştirmek yerine, sadece değişikliklerle yeni bir taahhütte bulunmalısınız.

Ancak, gerçekten, gerçekten değiştirilmiş bir taahhüdü zorlamak istiyorsanız, bunu şu şekilde yapabilirsiniz:

$ git push origin +master:master

Baştaki +işaret, "hızlı ileri sarma" taahhüdü ile sonuçlanmasa bile, baskının gerçekleşmesini zorlar. (Hızlı bir taahhüt, ittiğiniz değişiklikler, kamuoyu deposundaki değişikliklerin doğrudan torunu olduğunda gerçekleşir.)


5
Bu git push -f'den nasıl daha iyi (daha iyi veya daha kötü)? Teşekkürler!
bentford

11
@bentford: Temel olarak aynı şey git push -f.
mipadi

54

Zaten bir değişiklik yaptıktan sonra değişikliklerinizi zorlamanın çok basit ve temiz bir yolu commit --amend:

git reset --soft HEAD^
git stash
git push -f origin master
git stash pop
git commit -a
git push origin master

Aşağıdakileri yapar:

  • Şube başlığını ebeveyn taahhüdüne sıfırlayın.
  • Bu son işi sakla.
  • Uzaktan kumandayı zorla itin. Uzaktan kumanda artık son taahhüde sahip değil.
  • Zulanýzý patlat.
  • Temiz bir şekilde çalışın.
  • Uzaktan kumandaya itin.

Bunu farklı bir şubeye veya uzaktan kumandaya uygularsanız, "başlangıç" ve "ana" öğelerini değiştirmeyi unutmayın.


3
2 açıklama: - Eğer başka bir üzerinde çalışıyorsanız şube adını değiştirdiğinizden emin olun - Değişiklikleri git adddahil etmek için benim taahhüt önce kullanmak zorunda kaldı .
SylvainB

1
, Windows CMD, ilk komut kaçtı edilmelidir: git reset --soft "HEAD^". Gerisi iyi çalışıyor.
BayMister

2
"çok basit ve temiz bir yol .." cit. Bu prosedür zorla itmeyi içerir. Yukarıdaki Cevaplardaki tüm eleştirilerin ışığında bu prosedürün gerçekten temiz olup olmadığından emin değilim.
Na13-c

24

Yerel değişiklik taahhüdümü atarak ve yeni değişiklikleri ekleyerek çözdüm:

# Rewind to commit before conflicting
git reset --soft HEAD~1

# Pull the remote version
git pull

# Add the new commit on top
git add ...
git commit
git push

2
Bu en basit sürüm!
mknaf

Başka bir 'değişiklik' taahhüdü eklemek, yeniden yazma geçmişiyle uğraşmaktan daha iyidir. Katılıyorum mknaf
sdkks

8

Ben de aynı problemi yaşadım.

  • Zaten itilmiş olan son taahhüdü yanlışlıkla değiştirdi
  • Yerel olarak birçok değişiklik yapıldı, beş kez işlendi
  • Aktarmaya çalıştı, bir hata aldı, panikledi, uzaktan birleşti, dosyalarımın bir sürü var, itti, başarısız oldu vb.

Git-newbie olarak bunun tam FUBAR olduğunu düşündüm .

Çözüm: @bara gibi + bir yerel yedekleme dalı oluşturdu

# Rewind to commit just before the pushed-and-amended one.
# Replace <hash> with the needed hash.
# --soft means: leave all the changes there, so nothing is lost.
git reset --soft <hash>

# Create new branch, just for a backup, still having all changes in it.
# The branch was feature/1234, new one - feature/1234-gone-bad
git checkout -b feature/1234-gone-bad

# Commit all the changes (all the mess) not to lose it & not to carry around
git commit -a -m "feature/1234 backup"

# Switch back to the original branch
git checkout feature/1234

# Pull the from remote (named 'origin'), thus 'repairing' our main problem
git pull origin/feature/1234

# Now you have a clean-and-non-diverged branch and a backup of the local changes.
# Check the needed files from the backup branch
git checkout feature/1234-gone-bad -- the/path/to/file.php

Belki hızlı ve temiz bir çözüm değil ve tarihimi kaybettim (5 yerine 1 taahhüt), ama bir günlük işten tasarruf ettim.


6

Kodu uzak şubenize (GitHub / Bitbucket) göndermediyseniz, komut satırındaki yürütme iletisini aşağıdaki gibi değiştirebilirsiniz.

 git commit --amend -m "Your new message"

Belirli bir dal üzerinde çalışıyorsanız, bunu yapın:

git commit --amend -m "BRANCH-NAME: new message"

Kodu zaten yanlış bir mesajla ittiyseniz, mesajı değiştirirken dikkatli olmanız gerekir. tamamlama mesajını değiştirip tekrar göndermeyi denedikten sonra sorun yaşarsınız. Düzgünleştirmek için aşağıdaki adımları izleyin.

Lütfen cevaplamadan önce cevabın tamamını okuyun

git commit --amend -m "BRANCH-NAME : your new message"

git push -f origin BRANCH-NAME                # Not a best practice. Read below why?

Önemli not: Force Push'u doğrudan kullandığınızda, diğer geliştiricilerin aynı dalda çalıştığı kod sorunlarıyla karşılaşabilirsiniz. Bu nedenle, bu çatışmalardan kaçınmak için, zorlamayı zorlamadan önce kodu şubenizden almanız gerekir :

 git commit --amend -m "BRANCH-NAME : your new message"
 git pull origin BRANCH-NAME
 git push -f origin BRANCH-NAME

Bu, önceden iletilmişse, tamamlama mesajını değiştirirken en iyi uygulamadır.


1
Son örneğinizdeki taahhüdü başarılı bir şekilde geri aldıysanız, neden zorlamayı zorlamanız gerekiyor? Standart bir itme yeterli olmaz mı? Teşekkürler
Thomas

Thomas tarafından sorulan soru aslında çok geçerli. Çekimi takiben kendimi zorlamaya gerek duymadım.
Na13-c

Lütfen "en iyi uygulama" olarak adlandırmayın, çünkü etrafta çalışmanın bir yolu vardır, --forcekabul edilen cevaba bakın
Farid

5

Hiç kimsenin değiştirilmemiş taahhüdünüzü çekmediğini biliyorsanız, --force-with-leaseseçeneğini kullanın git push.

TortoiseGit'te, "Push ..." seçenekleri "Zorla: Silme" ve "bilinen değişiklikleri" kontrol altında da aynı işlemi yapabilirsiniz.

Zorla (Bilinen değişiklikleri atabilir) uzak deponun daha hızlı ve hızlı ileri sarılmayı kabul etmesini sağlar. Bu, uzak deponun taahhütlerini kaybetmesine neden olabilir; dikkatli kullanın. Bu, uzaktan kumandadaki diğer kişilerin bilinmeyen değişikliklerini kaybetmesini önleyebilir. Sunucu şubesinin uzaktan izleme şubesiyle aynı taahhüdü gösterip göstermediğini kontrol eder (bilinen değişiklikler). Evet ise, bir kuvvet zorlaması yapılır. Aksi takdirde reddedilecektir. Git'in uzaktan izleme etiketleri olmadığından, bu seçenek kullanılarak etiketlerin üzerine yazılamaz.


4

Git uzaktan kumandasında bu taahhüt dosyaları zaten bulunduğundan bu hatayı alıyorsunuz. Bunun çalışması için dalı itmek zorundasınız:

git push -f origin branch_name

Ayrıca, ekibinizdeki bir başkası aynı şubeye göndermiş olabileceği için kodu uzaktan kumandadan aldığınızdan emin olun.

git pull origin branch_name

Bu, taahhüdü uzaktan kumandayı zorlamaya zorlamamız gereken durumlardan biridir.


Bu cevap neden önceki cevaplarda dile getirilen önemli yorumları açıklamıyor?
Na13-c

2

Zaten bir git add "your files"ve yaptıktan sonra değişikliklerinizi zorlamanın çok basit ve temiz bir yolu git commit --amend:

git push origin master -f

veya:

git push origin master --force

Bunun kötü olduğunu duydum ve eminim. Git'in varsayılan olarak başarısız olması için (iyi) bir neden var (ve --force gerektirir), eminim.
Rolf

1

Bu sorunu uzaktan repodan çekerek ve ortaya çıkan, işlenen ve sonra iten birleşme çatışmalarıyla başa çıkmak zorunda kaldım. Ama daha iyi bir yol varmış gibi hissediyorum.


Pek sayılmaz. Sorun, uzak kopyadan yerel kopyanızı güncellememeniz olabilir. Git buna zorlamayacaktır, çünkü birleştirmelerle elle uğraşmanız gerekebilir. Diğer cevabımda, bir zorlamayı zorlayacak bir komut (ve açıklama) var - ancak uzaktan kumandadaki değişiklikleri silebilir.
mipadi

1

Git'in bana yapmamı söylediklerini yapmaya devam ettim. Yani:

  • Değiştirilmiş taahhüt nedeniyle itemiyorum.
  • Önerildiği gibi çekiyorum.
  • Birleştirme başarısız. bu yüzden elle düzeltirim.
  • Yeni bir taahhüt oluşturun ("birleştirme" etiketli) ve itin.
  • İşe yarıyor gibi görünüyor!

Not: Değiştirilen taahhüt sonuncuydu.


1
Eğer daha fazla itibar puanım olsaydı, aşağı inerdim, bu yüzden burada kibarca, kimin acı çektiğini soracağım. Değiştiren mi? Değiştirilmiş taahhüt ile bir şube çekip üzerinde çalışan kişi? Değişiklikten önce mi, sonra mı? Her değişikliğimi temizledim çünkü seni yanlış anladım ... Neyse ki fazla bir şey yoktu ...
Bartis Áron

1

Aşağıdakiler, bir taahhüdün Yazarını ve Taahhüdünü değiştirirken benim için çalıştı.

git push -f origin master

Git, bunların yalnızca meta bilgi bölümünde farklılık gösteren özdeş deltaların taahhütleri olduğunu anlayacak kadar zekiydi.

Hem yerel hem de uzak başkanlar söz konusu taahhütlere dikkat çekti.



0

Burada, önceki bir taahhütte bir düzenlemeyi nasıl düzelttim:

  1. Çalışmanızı şimdiye kadar kaydedin.
  2. Yapıldıysa değişikliklerinizi şimdilik saklayın: git stash şimdilik saklayın Artık çalışma kopyanız son işleminizin yapıldığı durumda temiz.
  3. Düzenlemeleri ve düzeltmeleri yapın.
  4. " Değişiklik " modundaki değişiklikleri uygulayın :git commit --all --amend
  5. Düzenleyiciniz bir günlük mesajı (varsayılan olarak eski günlük mesajı) ister. Mutlu olduğunuzda editörü kaydedin ve çıkın.

    Yeni değişiklikler eski taahhüde eklenir. Kendinizle görün git logvegit diff HEAD^

  6. Yapılmışsa saklı değişikliklerinizi yeniden uygulayın: git stash apply

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.