Jak cofnąć polecenie „git commit --amend” zrobione zamiast „git commit”

1294

Przypadkowo zmieniłem poprzednie zatwierdzenie. Zatwierdzenie powinno być osobne, aby zachować historię zmian, które wprowadziłem w określonym pliku.

Czy istnieje sposób na cofnięcie tego ostatniego zatwierdzenia? Jeśli zrobię coś podobnego git reset --hard HEAD^, pierwsze zatwierdzenie również zostanie cofnięte.

(Nie wysłałem jeszcze żadnych zdalnych katalogów)

Jesper Rønn-Jensen
źródło

Odpowiedzi:

2288

To, co musisz zrobić, to utworzyć nowe zatwierdzenie z tymi samymi szczegółami, co bieżące HEADzatwierdzenie, ale z nadrzędnym jak poprzednia wersja HEAD. git reset --softprzesunie wskaźnik gałęzi, tak aby następne zatwierdzenie miało miejsce na innym zatwierdzeniu niż w miejscu, w którym znajduje się obecnie nagłówek gałęzi.

# Move the current head so that it's pointing at the old commit
# Leave the index intact for redoing the commit.
# HEAD@{1} gives you "the commit that HEAD pointed at before 
# it was moved to where it currently points at". Note that this is
# different from HEAD~1, which gives you "the commit that is the
# parent node of the commit that HEAD is currently pointing to."
git reset --soft HEAD@{1}

# commit the current tree using the commit details of the previous
# HEAD commit. (Note that HEAD@{1} is pointing somewhere different from the
# previous command. It's now pointing at the erroneously amended commit.)
git commit -C HEAD@{1}
CB Bailey
źródło
33
Bardzo fajnie, +1. Zrobiłem to nawet z widokiem ostatniej poprawki w git reflogcelu znalezienia poprawnego numeru np {2}.
JJD
178
Żeby było jasne, pierwsze polecenie to prawdziwe „cofnięcie”. Tworzy HEAD, katalog roboczy (niezmieniony) i stan indeksu przed git commit --amend. Drugi to „przeróbka” na nowy zatwierdzenie. Działa to dla każdego git commit, nie tylko --amend.
cdunn2001
60
Więc jeśli nie zmieniłeś nowego komunikatu zatwierdzenia, który musisz uratować, druga część może być po prostu regularna git commit.
Matt Montag
18
Z jakiegoś powodu, ja otrzymuję błąd podczas uruchamiania git reset --soft HEAD@{1}: fatal: ambiguous argument 'HEAD@1': unknown revision or path not in the working tree. Use '--' to separate paths from revisions. Kiedy zastąpiłem HEAD@{1}odpowiednikiem skrótu zatwierdzenia pokazanego w git reflog(dzięki JJD!), Ta odpowiedź zadziałała cudownie!
Tim Camber
20
@ TimArnold w zależności od powłoki, może być konieczne wstawienie pojedynczych lub podwójnych cudzysłowów HEAD@{1}. Jeśli echo HEAD@{1}na przykład uruchomię w tcsh, wynik jest taki, HEAD@1że nawiasy klamrowe zostały zinterpretowane przez tcsh. Jeśli użyję pojedynczych cudzysłowów, nawiasy klamrowe zostaną zachowane.
Kelvin
136

użyj dziennika ref :

git branch fixing-things HEAD@{1}
git reset fixing-things

powinieneś mieć wszystkie wcześniej zmienione zmiany tylko w kopii roboczej i możesz je ponownie zatwierdzić

aby zobaczyć pełną listę poprzednich typów indeksów git reflog

knittl
źródło
7
Wymazuje to także indeks - nadal przydatny, ale wykracza poza zwykłe „cofnięcie”.
cdunn2001,
3
czy jest jakaś różnica między HEAD@{1}i HEAD~1?
neaumusic
15
@neaumusic: tak! HEAD~1jest dokładnie taki sam jak HEAD^i identyfikuje element nadrzędny bieżącego zatwierdzenia. HEAD@{1}z drugiej strony odnosi się do zatwierdzenia, na które HEAD wskazywał przed tym, tzn. oznacza różne zatwierdzenia, kiedy kasujesz inny oddział lub zmieniasz zatwierdzenie.
knittl
@knittl ah nic dziwnego, że nie sądziłem, że to było możliwe przed, dzięki jeszcze raz, dobra informacja
neaumusic
9
pierwszy krok jest zbędny. Proste git reset HEAD@{1}wystarczy.
dwelle
79

Znajdź swoje zmienione zobowiązania przez:

git log --reflog

Uwaga: Możesz dodać, --patchaby zobaczyć treść zatwierdzeń dla przejrzystości. Tak samo jak git reflog.

następnie zresetuj HEAD do dowolnego poprzedniego zatwierdzenia w punkcie, w którym było w porządku przez:

git reset SHA1 --hard

Uwaga: Zamień SHA1 na swój prawdziwy hash zatwierdzenia. Pamiętaj też, że to polecenie spowoduje utratę wszelkich niezatwierdzonych zmian, więc możesz je wcześniej ukryć. Możesz też użyć --softzamiast tego, aby zachować najnowsze zmiany, a następnie zatwierdzić je.

Następnie wybierz inne zatwierdzenie, które potrzebujesz na nim:

git cherry-pick SHA1
kenorb
źródło
26
Jeśli to zrobisz git reset SHA1 --soft, możesz zachować najnowsze zmiany, a następnie je zatwierdzić.
pravj
24

Zawsze możesz podzielić zatwierdzenie, z instrukcji

  • Uruchom interaktywny rebase za pomocą git rebase -i commit ^, gdzie zatwierdzenie to zatwierdzenie, które chcesz podzielić. W rzeczywistości każdy zakres zatwierdzeń będzie działał, o ile będzie zawierał to zatwierdzenie.
  • Zaznacz zatwierdzenie, które chcesz podzielić, poprzez akcję „edytuj”.
  • Jeśli chodzi o edycję tego zatwierdzenia, wykonaj git reset HEAD ^. W rezultacie HEAD jest przewijany o jeden, a indeks podąża za nim. Jednak działające drzewo pozostaje takie samo.
  • Teraz dodaj zmiany do indeksu, który chcesz mieć przy pierwszym zatwierdzeniu. Aby to zrobić, możesz użyć git add (ewentualnie interaktywnie) lub git-gui (lub obu).
  • Zatwierdź bieżący indeks z dowolnym komunikatem zatwierdzenia, który jest teraz odpowiedni.
  • Powtarzaj dwa ostatnie kroki, aż drzewo robocze będzie czyste.
  • Kontynuuj rebase za pomocą git rebase - kontynuuj.
Arkaitz Jimenez
źródło
26
zbyt skomplikowane. git reflogto wszystko, czego potrzebujesz
Knittl
2
Wiele kroków tak, ale każdy krok jest nieskomplikowany i łatwy do zrobienia. To działało dla mnie i dostaje mój głos.
OzBandit
5
dodatkowo ta odpowiedź pozwala wybiórczo wybierać zmiany, które przypadkowo „poprawiono”, zapewniając dodatkową wartość git reset - miękkie podejście HEAD @ {1} (które rozwiązało mój problem BTW)
Wiebe Tijsma
2
Możesz także selektywnie wybierać zmiany za pomocą metody reflog. Po prostu zrób git resetzamiast git reset --soft, a następnie zrób git add --patch.
geekofalltrades
1
To wciąż przepisuje historię i wymaga użycia siły. W zależności od twojej sytuacji może to stanowić problem.
Pajn
20

Być może warto zauważyć, że jeśli nadal jesteś w edytorze z komunikatem zatwierdzenia, możesz usunąć komunikat zatwierdzenia, a to przerwie git commit --amendpolecenie.

Justin Schulz
źródło
To jest jeden.
atilkan
Zapisałem mój, ale ^^
inżynierskie
14

Może można użyć, git reflogaby uzyskać dwa zatwierdzenia przed poprawką i po zmianie.

Następnie użyj, git diff before_commit_id after_commit_id > d.diffaby uzyskać różnicę między przed i po zmianie.

Następnie użyj, git checkout before_commit_idaby cofnąć się przed zatwierdzeniem

I ostatnie użycie, git apply d.diffaby zastosować prawdziwą zmianę, którą zrobiłeś.

To rozwiązuje mój problem.

utzcoz
źródło
11

Jeśli wypchnąłeś zatwierdzenie na zdalne, a następnie błędnie poprawiono zmiany w tym zatwierdzeniu, rozwiąże to problem. Wydaj a, git logaby znaleźć SHA przed zatwierdzeniem. (zakłada to, że pilot ma nazwę pochodzenia). Teraz wydaj te polecenia za pomocą tego SHA.

git reset --soft <SHA BEFORE THE AMMEND>
#you now see all the changes in the commit and the amend undone

#save ALL the changes to the stash
git stash

git pull origin <your-branch> --ff-only
#if you issue git log you can see that you have the commit you didn't want to amend

git stash pop
#git status reveals only the changes you incorrectly amended

#now you can create your new unamended commit
David Sopko
źródło
3
Jest to szczególny przypadek bardziej ogólnego pytania, ale dokładnie zaspokoił moją pilną potrzebę.
dmckee --- były moderator kociak
8

Możesz zrobić poniżej, aby cofnąć swoje git commit —amend

  1. git reset --soft HEAD^
  2. git checkout files_from_old_commit_on_branch
  3. git pull origin your_branch_name

====================================

Teraz twoje zmiany są takie, jak poprzednio. Skończyłeś cofaniegit commit —amend

Teraz możesz zrobić git push origin <your_branch_name>, aby przejść do oddziału.

Pratik
źródło
3

Prawie 9 lat spóźniło się z tym, ale nie zauważyłem, by wspomniana odmiana osiągnęła to samo (to rodzaj połączenia kilku z nich, podobnie jak najlepsza odpowiedź ( https://stackoverflow.com/a/1459264/4642530 ) .

Przeszukaj wszystkie odłączone głowy na gałęzi

git reflog show origin/BRANCH_NAME --date=relative

Następnie znajdź skrót SHA1

Zresetuj do starego SHA1

git reset --hard SHA1

Następnie popchnij go z powrotem.

git push origin BRANCH_NAME

Gotowy.

Spowoduje to całkowite przywrócenie starego zatwierdzenia.

(W tym data wcześniejszego zastąpienia odłączonej głowy zatwierdzenia)

garrettmac
źródło
Tak, ale zazwyczaj chcę zresetować, --softaby zachować zmiany. Chcę tylko, żeby zostało popełnione osobno
Juan Mendes
2
  1. Kasa do tymczasowego oddziału z ostatnim zatwierdzeniem

    git branch temp HEAD@{1}

  2. Zresetuj ostatnie zatwierdzenie

    git reset temp

  3. Teraz będziesz mieć wszystkie pliki swojego zatwierdzenia, a także poprzednie zatwierdzenie. Sprawdź status wszystkich plików.

    git status

  4. Zresetuj swoje pliki zatwierdzania od etapu git.

    git reset myfile1.js (wkrótce)

  5. Ponownie podłącz to zatwierdzenie

    git commit -C HEAD@{1}

  6. Dodaj i zatwierdź swoje pliki do nowego zatwierdzenia.

Priyanshu Chauhan
źródło