Jak cofnąć udany „git cherry-pick”?


104

Po prostu wykonałem w lokalnym repozytorium git cherry-pick SHAbez żadnych konfliktów i problemów. Wtedy zdałem sobie sprawę, że nie chcę robić tego, co właśnie zrobiłem. Nigdzie tego nie pchałem.

Jak mogę usunąć tylko ten kilof?

Chciałbym wiedzieć, czy jest na to sposób:

  • kiedy mam inne lokalne zmiany
  • kiedy nie mam innych lokalnych zmian

Najlepiej z jednym poleceniem dla obu przypadków, jeśli to możliwe.

Odpowiedzi:


142

Wybór opcji jest w zasadzie zatwierdzeniem, więc jeśli chcesz to cofnąć, po prostu cofnij zatwierdzenie.

kiedy mam inne lokalne zmiany

Przechowuj swoje bieżące zmiany, aby móc je ponownie zastosować po zresetowaniu zatwierdzenia.

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

kiedy nie mam innych lokalnych zmian

$ git reset --hard HEAD^

6
Oprócz pytania i odpowiedzi, jeśli nie jesteś pewien, co wybierasz, zawsze możesz `` wybrać SHA - no-commit '' i nie będzie żadnych zmian zatwierdzających, które można łatwo sprawdzić , jest to przydatne do częściowego zbierania wiśni
kuskmen

2
windows: reset git --hard "HEAD ^"
slim

25

Aby cofnąć ostatnie zatwierdzenie, po prostu zrób git reset --hard HEAD~.

Edycja : ta odpowiedź dotyczy wcześniejszej wersji pytania, w której nie wspomniano o zachowaniu lokalnych zmian; przyjęta odpowiedź Tima jest rzeczywiście poprawna. Dzięki qwertzguy za heads up.


2
To powinno być HEAD ^ lub HEAD ~ 1
Andreas Wederbrand

Oba są równoważne HEAD ~ (i HEAD ^ 1, jeśli o to chodzi)
David Deutsch

1
@DavidDeutsch To prawda (choć tylko w nowszych wersjach Gita), ale wielkie litery ( HEAD) są bardziej niezawodne: rozważ niefortunny przypadek, w którym headjest nazwa istniejącego odniesienia.
jub0bs

1
@Jubobs - słuszna uwaga; W odpowiedzi zmieniłem obudowę.
David Deutsch

1
@qwertzguy, dobry chwyt; patrząc na sygnatury czasowe, chwilę po tym, jak zamieściłem tę odpowiedź, do pytania dodano fragment dotyczący lokalnych zmian :)
David Deutsch

9

Jeśli to możliwe, unikaj twardego resetu. Twardy reset to jedna z niewielu destrukcyjnych operacji w git. Na szczęście możesz cofnąć wybór bez resetowania i uniknąć niczego destrukcyjnego.

Zanotuj skrót wiśniowego wyboru, który chcesz cofnąć, powiedz, że tak ${bad_cherrypick}. Zrób git revert ${bad_cherrypick}. Teraz zawartość twojego drzewa roboczego jest taka, jaka była przed twoim złym wyborem wiśni.

Powtórz git cherry-pick ${wanted_commit}, a kiedy będziesz zadowolony z nowego wyboru, zrób git rebase -i ${bad_cherrypick}~1. Podczas rebase usuń oba ${bad_cherrypick}i odpowiadające im przywrócenia.

Gałąź, nad którą pracujesz, będzie miała tylko dobry wybór. Brak konieczności resetowania!


7

git reflog może przyjść ci na ratunek.

Wpisz go w konsoli, a otrzymasz listę swojej historii git wraz z reprezentującym ją SHA-1.

Po prostu sprawdź dowolny SHA-1, do którego chcesz powrócić


Zanim odpowiemy, dodajmy trochę tła, wyjaśniając, co to jest HEAD.

First of all what is HEAD?

HEADjest po prostu odniesieniem do aktualnego zatwierdzenia (ostatniego) w bieżącej gałęzi.
W HEADdanym momencie może istnieć tylko jeden . (wyłączając git worktree)

Zawartość HEADjest przechowywana wewnątrz .git/HEADi zawiera 40 bajtów SHA-1 aktualnego zatwierdzenia.


detached HEAD

Jeśli nie jesteś na najnowszym zatwierdzeniu - co oznacza, że HEADwskazuje na wcześniejsze zatwierdzenie w historii, jego wywołanie detached HEAD.

wprowadź opis obrazu tutaj

W linii poleceń będzie wyglądać następująco - SHA-1 zamiast nazwy gałęzi, ponieważ HEADnie wskazuje końca bieżącej gałęzi

wprowadź opis obrazu tutaj

wprowadź opis obrazu tutaj

Kilka opcji odzyskiwania po odłączonej GŁOWIE:


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

Spowoduje to pobranie nowej gałęzi wskazującej na żądane zatwierdzenie.
To polecenie spowoduje pobranie do podanego zatwierdzenia.
W tym momencie możesz utworzyć gałąź i zacząć od tego momentu.

# 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

Zawsze możesz też użyć reflog.
git reflogwyświetli każdą zmianę, która zaktualizowała, HEADa sprawdzenie żądanego wpisu reflog spowoduje HEADpowrót do tego zatwierdzenia.

Za każdym razem, gdy HEAD zostanie zmodyfikowany, pojawi się nowy wpis w reflog

git reflog
git checkout HEAD@{...}

Spowoduje to powrót do pożądanego zobowiązania

wprowadź opis obrazu tutaj


git reset --hard <commit_id>

„Przenieś” swoją HEAD z powrotem do pożądanego zatwierdzenia.

# 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.
  • Uwaga: ( od Git 2.7 )
    możesz również użyć git rebase --no-autostash.

git revert <sha-1>

„Cofnij” podany zatwierdzenie lub zakres zatwierdzenia.
Polecenie reset "cofnie" wszelkie zmiany wprowadzone w danym zatwierdzeniu.
Nowe zatwierdzenie z cofniętą łatką zostanie zatwierdzone, podczas gdy oryginalne zatwierdzenie pozostanie również w historii.

# 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>

Ten schemat ilustruje, które polecenie robi co.
Jak widać, reset && checkoutzmodyfikuj plik HEAD.

wprowadź opis obrazu tutaj


być może dodajgit reset --hard
wyx

4

W obliczu tego samego problemu odkryłem, że jeśli popełniłeś i / lub odepchnąłeś się na odległość od swojego udanego wyboru i chcesz go usunąć, możesz znaleźć SHA wiśniowego wyboru, uruchamiając:

git log --graph --decorate --oneline

Następnie (po użyciu, :wqaby wyjść z dziennika) możesz usunąć kilof za pomocą

git rebase -p --onto YOUR_SHA_HERE^ YOUR_SHA_HERE

gdzie YOUR_SHA_HERErówna się 40- lub skróconemu 7-znakowemu SHA zatwierdzonego wyboru.

Na początku nie będziesz w stanie przesłać zmian, ponieważ zdalne repozytorium i lokalne repozytorium będą miały różne historie zatwierdzania. Możesz zmusić lokalne zatwierdzenia do zastąpienia tego, co jest na twoim pilocie, używając

git push --force origin YOUR_REPO_NAME

(Zaadaptowałem to rozwiązanie od Setha Robertsona : zobacz „Usuwanie całego zatwierdzenia”).


1

Jedno polecenie i nie używa git resetpolecenia niszczącego :

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

Po prostu odrzuca zatwierdzenie, przywracając dokładnie stan sprzed wyboru, nawet jeśli nastąpiły lokalne zmiany.


Po prostu odrzuca zatwierdzenie. jak myślisz, co git reset HEAD^robi?
Tim

@TimCastelijns git resetcofa zatwierdzenie bez porzucania jakichkolwiek zmian. Polecam przeczytanie git-scm.com/docs/git-reset . Pytanie od OP to cofnięcie najlepszego wyboru. Wypróbuj oba polecenia, moje przywrócą ci dokładnie taki stan, w jakim byłeś przed wybiciem. git resetzepsuje twoje drzewo robocze, ponieważ pozostawi wybrane zmiany i staną się one nie do odróżnienia od wcześniej istniejących lokalnych zmian.
qwertzguy

tak, przepraszam, miałem na myśli reset --hard. Nie pozostawia żadnych zmian
Tim

1
@TimCastelijns git reset --hardto destrukcyjne polecenie, które usunie również niepowiązane zmiany lokalne i zrobi to w nieodwracalny sposób! Więc nie o to prosił PO.
qwertzguy

2
Ta odpowiedź byłaby znacznie bardziej przydatna, gdybyś wyjaśnił, co sedrobi to polecenie, czym różni się od wykonywania go ręcznie i co --autostashrobi.
Chris Page
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.