Başarılı bir "git kiraz toplama" nasıl geri alınır?


108

Yerel bir depoda, git cherry-pick SHAherhangi bir çatışma veya problem olmadan idam ettim . Daha sonra yaptığım şeyi yapmak istemediğimi fark ettim. Bunu hiçbir yere itmedim.

Sadece bu kiraz kıracağı nasıl çıkarabilirim?

Bunu yapmanın bir yolu olup olmadığını bilmek isterim:

  • başka yerel değişikliklerim olduğunda
  • başka yerel değişikliğim olmadığında

Mümkünse her iki durum için de tercihen bir komutla.

Yanıtlar:


148

Bir kiraz toplama, temelde bir işlemdir, bu nedenle, eğer onu geri almak istiyorsanız, sadece taahhüdü geri alırsınız.

başka yerel değişikliklerim olduğunda

Kaydetmeyi sıfırladıktan sonra bunları yeniden uygulayabilmek için mevcut değişikliklerinizi saklayın.

$ git stash
$ git reset --hard HEAD^
$ git stash pop  # or `git stash apply`, if you want to keep the changeset in the stash

başka yerel değişikliğim olmadığında

$ git reset --hard HEAD^

6
Sadece soruya ve cevaba ek olarak, neyi seçtiğinden emin değilseniz, her zaman 'SHA'yı seçebilirsin - kesinleştirme yok' ve sadece kolayca kontrol edilebilecek değişiklikler olmayacak , bu kısmi kiraz toplama için kullanışlıdır
kuskmen

3
windows: git reset --hard "HEAD ^"
ince

26

Son taahhüdünüzü geri almak için yapmanız yeterlidir git reset --hard HEAD~.

Düzenleme : Bu cevap, yerel değişikliklerin korunmasından bahsetmeyen, sorunun önceki bir sürümü için geçerliydi; Tim'in kabul ettiği cevap gerçekten de doğrudur. Qwertzguy'a uyarılar için teşekkürler.


2
Bu HEAD ^ veya HEAD ~ 1 olmalıdır
Andreas Wederbrand

Her ikisi de HEAD ~ ile eşdeğerdir (ve bu konuda HEAD ^ 1)
David Deutsch

1
@DavidDeutsch Bu doğru (sadece Git'in daha yeni sürümlerinde olsa da), ancak büyük harf ( HEAD) daha sağlam: headmevcut bir referansın adının olduğu talihsiz durumu düşünün .
jub0bs

1
@Jubobs - iyi nokta; Cevabımda kasayı değiştirdim.
David Deutsch

1
@qwertzguy, iyi yakalama; Bu cevabı :) yayınlanmıştır sonra zaman damgaları bakarak, yerel değişiklikler hakkında biraz soru bir dakika eklendi
David Deutsch

9

Mümkünse, sert sıfırlamalardan kaçının. Sert sıfırlamalar, git'teki çok az sayıda yıkıcı işlemden biridir. Neyse ki, sıfırlama yapmadan bir kiraz seçmeyi geri alabilir ve yıkıcı herhangi bir şeyden kaçınabilirsiniz.

Geri almak istediğiniz kiraz seçmenin karmasını not edin, öyle diyelim ${bad_cherrypick}. Bir git revert ${bad_cherrypick}. Şimdi, çalışma ağacınızın içeriği, kötü kiraz toplamanızdan önceki gibidir.

Tekrarlayın git cherry-pick ${wanted_commit}ve yeni kiraz toplama işleminden memnun olduğunuzda bir git rebase -i ${bad_cherrypick}~1. Yeniden temelleme sırasında, her ikisini ${bad_cherrypick}ve karşılık gelen geri dönüşünü silin .

Üzerinde çalıştığınız dal sadece iyi bir kiraz toplayıcısına sahip olacaktır. Sıfırlamaya gerek yok!


7

git reflog kurtarmaya gelebilir.

Konsolunuza yazın ve SHA-1 ile birlikte onları temsil eden git geçmişinizin bir listesini alacaksınız.

Geri dönmek istediğiniz herhangi bir SHA-1'i kontrol edin


Cevap vermeden önce, bunun ne olduğunu açıklayan biraz arka plan ekleyelim HEAD.

First of all what is HEAD?

HEADsadece geçerli şubedeki mevcut commit (en son) için bir referanstır. Herhangi bir zamanda
yalnızca bir single olabilir HEAD. (hariç git worktree)

Öğesinin içeriği içinde HEADsaklanır .git/HEADve geçerli kaydetmenin 40 baytlık SHA-1'ini içerir.


detached HEAD

Eğer en son commit'de değilseniz - yani HEADtarihteki önceki bir taahhüdü işaret ediyor demektir detached HEAD.

görüntü açıklamasını buraya girin

Komut satırında, HEADşu anki dalın ucuna işaret etmediği için dal adı yerine SHA-1 gibi görünecektir.

görüntü açıklamasını buraya girin

görüntü açıklamasını buraya girin

Ayrılmış bir HEAD'den nasıl kurtarılacağına dair birkaç seçenek:


git checkout

git checkout <commit_id>
git checkout -b <new branch> <commit_id>
git checkout HEAD~X // x is the number of commits t go back

Bu, istenen kaydı işaret eden yeni şubeyi teslim alacaktır.
Bu komut, belirli bir commit için çıkış yapacaktır.
Bu noktada bir şube oluşturabilir ve bu noktadan itibaren çalışmaya başlayabilirsiniz.

# Checkout a given commit. 
# Doing so will result in a `detached HEAD` which mean that the `HEAD`
# is not pointing to the latest so you will need to checkout branch
# in order to be able to update the code.
git checkout <commit-id>

# create a new branch forked to the given commit
git checkout -b <branch name>

git reflog

Daima kullanabilirsiniz reflog. istenen reflog girişini
git refloggüncelleyen HEADve kontrol eden herhangi bir değişikliği HEADbu commit için geri döndürecektir.

HEAD her değiştirildiğinde, yeni bir giriş olacaktır. reflog

git reflog
git checkout HEAD@{...}

Bu sizi istediğiniz taahhüdünüze geri götürecektir

görüntü açıklamasını buraya girin


git reset --hard <commit_id>

HEAD'inizi istenen işleme geri "taşıyın".

# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32

# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts if you've modified things which were
# changed since the commit you reset to.
  • Not: ( Git 2.7 yana )
    ayrıca kullanabilirsiniz git rebase --no-autostashsıra.

git revert <sha-1>

Verilen kaydetme veya kaydetme aralığını "geri alın".
Reset komutu, verilen işlemde yapılan değişiklikleri "geri alır".
Geri alma yamasıyla yeni bir taahhütte bulunulacak ve orijinal kesinleştirme de geçmişte kalacaktır.

# add new commit with the undo of the original one.
# the <sha-1> can be any commit(s) or commit range
git revert <sha-1>

Bu şema, hangi komutun ne yaptığını gösterir.
Orada gördüğünüz gibi reset && checkoutdeğiştirin HEAD.

görüntü açıklamasını buraya girin


belki ekleyingit reset --hard
wyx

4

Aynı sorunla karşılaştığımda, başarılı kiraz toplama işleminizden bu yana taahhütte bulunduysanız ve / veya uzağa ittiyseniz ve onu kaldırmak istiyorsanız, kirazlı toplayıcının SHA'sını şu şekilde bulabileceğinizi keşfettim:

git log --graph --decorate --oneline

Ardından, ( :wqgünlükten çıkmak için kullandıktan sonra ) kirazlı toplayıcıyı

git rebase -p --onto YOUR_SHA_HERE^ YOUR_SHA_HERE

burada YOUR_SHA_HEREkirazla seçilmiş kaydetmenin 40 veya kısaltılmış 7 karakterli SHA'sına eşittir.

İlk başta, değişikliklerinizi zorlayamazsınız çünkü uzak deponuz ve yerel deponuz farklı taahhüt geçmişlerine sahip olacaktır. Yerel taahhütlerinizi kullanarak uzaktan kumandanızdakileri değiştirmeye zorlayabilirsiniz.

git push --force origin YOUR_REPO_NAME

(Bu çözümü Seth Robertson'dan uyarladım : Bkz. "Bir tamamlamanın tamamını kaldırma".)


1

Bir komuta ve yok değil yıkıcı kullanmak git resetkomutu:

GIT_SEQUENCE_EDITOR="sed -i 's/pick/d/'" git rebase -i HEAD~ --autostash

Yerel değişiklikleriniz olsa bile, taahhüdü kaldırır ve sizi kiraz toplama işleminden önceki duruma geri getirir.


Basitçe taahhüdü bırakır. sence ne git reset HEAD^yapar?
Tim

@TimCastelijns git reset, hiçbir değişikliği düşürmeden commit işlemini geri alır. Git-scm.com/docs/git-reset okumanızı tavsiye ederim . OP'nin sorusu, bir seçmeyi geri almaktır. Her iki komutu da dene, benimki seni seçmeden önceki haline geri getirecek. git resetkiraz toplanan değişiklikleri bıraktığı ve önceden var olan yerel değişikliklerinizden ayırt edilemez hale geldiği için çalışma ağacınızı alt üst eder.
qwertzguy

evet, özür dilerim, demek istedim reset --hard. Değişiklik
Tim

1
@TimCastelijns git reset --hard, ilgisiz yerel değişiklikleri de kaldıracak ve bunu kurtarılamaz bir şekilde yapacak yıkıcı bir komuttur! Yani OP'nin istediği bu değil.
qwertzguy

2
Bu sedkomutun ne yaptığını, manuel olarak yapmaktan ne kadar farklı olduğunu ve ne yaptığını açıklarsanız, bu cevap çok daha yararlı olacaktır --autostash.
Chris Sayfa
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.