Pracowałem z przyjacielem nad projektem, a on edytował kilka plików, których nie powinno się edytować. W jakiś sposób połączyłem jego prace z moimi, albo kiedy je wyciągnąłem, albo gdy próbowałem po prostu wybrać konkretne pliki, które chciałem. Od dłuższego czasu szukam i gram, próbując wymyślić, jak usunąć zatwierdzenia zawierające edycje tych plików, wydaje się, że jest to podrzucenie między revert i rebase, i nie ma prostych przykładów, a Dokumenty zakładają, że wiem więcej niż ja.
Oto uproszczona wersja pytania:
Biorąc pod uwagę następujący scenariusz, jak usunąć commit 2?
$ mkdir git_revert_test && cd git_revert_test
$ git init
Initialized empty Git repository in /Users/josh/deleteme/git_revert_test/.git/
$ echo "line 1" > myfile
$ git add -A
$ git commit -m "commit 1"
[master (root-commit) 8230fa3] commit 1
1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 myfile
$ echo "line 2" >> myfile
$ git commit -am "commit 2"
[master 342f9bb] commit 2
1 files changed, 1 insertions(+), 0 deletions(-)
$ echo "line 3" >> myfile
$ git commit -am "commit 3"
[master 1bcb872] commit 3
1 files changed, 1 insertions(+), 0 deletions(-)
Oczekiwany wynik to
$ cat myfile
line 1
line 3
Oto przykład tego, jak próbowałem przywrócić
$ git revert 342f9bb
Automatic revert failed. After resolving the conflicts,
mark the corrected paths with 'git add <paths>' or 'git rm <paths>'
and commit the result.
git
commit
revert
cherry-pick
Joshua Cheek
źródło
źródło
Odpowiedzi:
Algorytm używany przez Git podczas obliczania różnic, które mają zostać cofnięte, wymaga tego
Definicja „sąsiadującego” opiera się na domyślnej liczbie linii z różnic kontekstowych, która wynosi 3. Więc jeśli „mój plik” został skonstruowany w ten sposób:
Wtedy wszystko działa zgodnie z oczekiwaniami.
Druga odpowiedź była bardzo interesująca. Istnieje funkcja, która nie została jeszcze oficjalnie wydana (chociaż jest dostępna w Git v1.7.2-rc2) o nazwie Revert Strategy. Możesz wywołać git w ten sposób:
i powinna lepiej zrozumieć, o co ci chodziło. Nie wiem, jaka jest lista dostępnych strategii, ani nie znam definicji żadnej strategii.
źródło
perl -p
jest przydatny do pisania bardzo krótkich programów (jedna linia), które zapętlają i przekazują dane wejściowe do wyjścia, podobnie jak sed.perl -i
służy do edycji plików w miejscu .perl -e
jest jak przesłać kod do oceny .Można to zrobić na cztery sposoby:
Czysty sposób, cofanie, ale zaloguj się cofnij:
Ostry sposób, usuń w całości tylko ostatni zatwierdzenie:
Uwaga: Unikaj,
git reset --hard
ponieważ spowoduje także odrzucenie wszystkich zmian w plikach od ostatniego zatwierdzenia. Jeśli--soft
nie działa, spróbuj--mixed
lub--keep
.Rebase (pokaż dziennik ostatnich 5 zatwierdzeń i usuń wiersze, których nie chcesz, lub zmień kolejność, lub zmiksuj wiele zatwierdzeń w jednym lub zrób cokolwiek innego, jest to bardzo wszechstronne narzędzie):
A jeśli popełnisz błąd:
Szybki rebase: usuń tylko określony zatwierdzenie, używając jego identyfikatora:
Alternatywy: możesz także spróbować:
Jeszcze jedna alternatywa:
W ostateczności, jeśli potrzebujesz pełnej swobody edytowania historii (np. Ponieważ git nie pozwala ci edytować tego, co chcesz), możesz użyć tej bardzo szybkiej aplikacji typu open source: reposurgeon .
Uwaga: oczywiście wszystkie te zmiany są wprowadzane lokalnie, należy
git push
następnie zastosować zmiany do pilota. A jeśli twoje repozytorium nie chce usunąć zatwierdzenia („niedozwolone szybkie przewijanie do przodu”, co dzieje się, gdy chcesz usunąć zatwierdzenie, które już wypchnąłeś), możesz użyćgit push -f
wymuszania wypchnięcia zmian.Uwaga 2: jeśli pracujesz nad gałęzią i musisz wymusić wypychanie, powinieneś absolutnie tego unikać,
git push --force
ponieważ może to zastąpić inne gałęzie (jeśli dokonałeś w nich zmian, nawet jeśli bieżąca kasa znajduje się w innej gałęzi). Wolą zawsze określić zdalną gałąź, kiedy wymusić Push :git push --force origin your_branch
.źródło
git rebase -i HEAD~5
pracował dla mnie. Następnie usunąłem zatwierdzenia, których nie potrzebowałem i mogłem rozwiązać problem w mniej niż 30 sekund. Dziękuję Ci.Oto proste rozwiązanie:
(Uwaga:
x
jest liczbą zatwierdzeń)po uruchomieniu plik notatnika otworzy się. Wpisz
drop
oprócz zatwierdzenia.Jeśli nie znasz Vima, po prostu kliknij każde słowo, które chcesz edytować, a następnie naciśnij klawisz „I” (dla trybu wstawiania). Po zakończeniu pisania naciśnij klawisz „esc”, aby wyjść z trybu wstawiania.
i to wszystko, gotowe! Zsynchronizuj pulpit git, a zmiany zostaną przekazane zdalnie.
Jeśli upuszczone zatwierdzenie znajdowało się już na pilocie, będziesz musiał wymusić push. Ponieważ --force jest uważane za szkodliwe , użyj
git push --force-with-lease
.źródło
Twój wybór jest pomiędzy
Powinieneś wybrać (1), jeśli błędna zmiana została wykryta przez kogoś innego, i (2), jeśli błąd jest ograniczony do prywatnego nieprzesuniętego oddziału.
Git revert to zautomatyzowane narzędzie do zrobienia (1), tworzy nowe zatwierdzenie cofając niektóre poprzednie zatwierdzenia. Zobaczysz błąd i usunięcie w historii projektu, ale ludzie, którzy ściągną z twojego repozytorium, nie będą mieli problemów podczas aktualizacji. W twoim przykładzie nie działa to w sposób zautomatyzowany, więc musisz edytować „mój plik” (aby usunąć wiersz 2), zrobić
git add myfile
igit commit
rozwiązać konflikt. Skończysz wtedy z czterema zatwierdzeniami w historii, z zatwierdzeniem 4 cofającym zatwierdzenie 2.Jeśli nikogo nie obchodzi, że twoja historia się zmienia, możesz ją przepisać i usunąć zatwierdzenie 2 (wybór 2). Najłatwiejszym sposobem na to jest użycie
git rebase -i 8230fa3
. Spowoduje to przeniesienie Cię do edytora i możesz zdecydować, aby nie dołączać błędnego zatwierdzenia, usuwając zatwierdzenie (i zaznaczając opcję „wybierz” obok innych komunikatów zatwierdzenia. Przeczytaj o konsekwencjach takiego działania) .źródło
Appproch 1
Najpierw pobierz skrót zatwierdzenia (np. 1406cd61), który musisz przywrócić. prosta poprawka będzie poniżej polecenia,
jeśli masz więcej zmian związanych z plikami 1406cd61 po 1406cd61, powyższe proste polecenie nie będzie działać. Następnie musisz wykonać poniższe kroki, czyli zbieranie wiśni.
Około 2
Wykonaj poniższe czynności, ponieważ używamy --force, aby to zrobić, musisz mieć uprawnienia administratora do repozytorium git.
Krok 1: Znajdź zatwierdzenie przed zatwierdzeniem, które chcesz usunąć
git log
Krok 2: Sprawdź to zatwierdzenie
git checkout <commit hash>
Krok 3: Utwórz nowy oddział przy użyciu bieżącego zatwierdzenia transakcji
git checkout -b <new branch>
Krok 4: Teraz musisz dodać zatwierdzenie po usuniętym zatwierdzeniu
git cherry-pick <commit hash>
Krok 5: Teraz powtórz krok 4 dla wszystkich innych zatwierdzeń, które chcesz zachować.
Krok 6: Po dodaniu wszystkich zatwierdzeń do nowego oddziału i zatwierdzeniu. Sprawdź, czy wszystko jest we właściwym stanie i działa zgodnie z przeznaczeniem. Dokładnie sprawdź, czy wszystko zostało zatwierdzone:
git status
Krok 7: Przejdź do zepsutej gałęzi
git checkout <broken branch>
Krok 8: Teraz wykonaj twardy reset uszkodzonej gałęzi w celu zatwierdzenia przed tą, którą chcesz usunąć
git reset --hard <commit hash>
Krok 9: Scal swoją stałą gałąź w tę gałąź
git merge <branch name>
Krok 10: Przekaż scalone zmiany z powrotem do źródła. OSTRZEŻENIE: Zastąpi to zdalne repozytorium!
git push --force origin <branch name>
Możesz wykonać ten proces bez tworzenia nowego oddziału, zastępując krok 2 i 3 krokiem 8, a następnie nie przeprowadzać kroków 7 i 9.
źródło
Możesz usunąć niechciane zatwierdzenia za pomocą
git rebase
. Załóżmy, że włączyłeś do swojej gałęzi tematów kilka gałęzi tematów współpracownika, ale później zdecydujesz, że nie chcesz tych zmian.W tym momencie edytor tekstu otworzy interaktywny widok bazy. Na przykład
Jeśli zmiana bazy nie powiodła się, usuń gałąź tymczasową i wypróbuj inną strategię. W przeciwnym razie postępuj zgodnie z następującymi instrukcjami.
Jeśli przekazujesz gałąź tematu do pilota, może być konieczne wymuszenie wypychania, ponieważ historia zmian uległa zmianie. Jeśli inni pracują nad tym samym oddziałem, daj im znać.
źródło
Z innych odpowiedzi tutaj byłem trochę zdezorientowany, jak
git rebase -i
można go użyć do usunięcia zatwierdzenia, więc mam nadzieję, że zapisanie mojego testu tutaj jest tutaj (bardzo podobne do OP).Oto
bash
skrypt, który możesz wkleić, aby utworzyć repozytorium testowe w/tmp
folderze:W tym momencie mamy
file.txt
z tymi treściami:W tym momencie HEAD jest na 5. zatwierdzeniu, HEAD ~ 1 będzie na 4. - a HEAD ~ 4 będzie na 1. zatwierdzeniu (więc HEAD ~ 5 nie istnieje). Powiedzmy, że chcemy usunąć 3. zatwierdzenie - możemy wydać to polecenie w
myrepo_git
katalogu:( Zauważ, że
git rebase -i HEAD~5
wyniki z „fatal: Potrzebowałem jednej wersji; niepoprawny HEAD ~ 5”. ) Otworzy się edytor tekstu (patrz zrzut ekranu w odpowiedzi @Dennis ) z następującymi treściami:Otrzymujemy więc wszystkie zatwierdzenia od (ale nie wliczając ) naszej żądanej GŁOWICY ~ 4. Usuń linię
pick 448c212 3rd git commit
i zapisz plik; otrzymasz tę odpowiedź odgit rebase
:W tym momencie otwórz myrepo_git /
folder/file.txt
w edytorze tekstu; zobaczysz, że został zmodyfikowany:Zasadniczo
git
widzi, że kiedy HEAD dotarł do drugiego zatwierdzenia, pojawiła się treśćaaaa
+bbbb
; a następnie ma łatkę dodanącccc
+,dddd
której nie wie, jak dołączyć do istniejącej zawartości.Więc tutaj
git
nie możesz zdecydować za Ciebie - to ty musisz podjąć decyzję: usuwając 3. zatwierdzenie, albo zachowujesz wprowadzone przez niego zmiany (tutaj wierszcccc
) - albo nie. Jeśli nie, po prostu usuń dodatkowe wiersze - w tymcccc
- przyfolder/file.txt
użyciu edytora tekstu, aby wyglądało to tak:... a następnie zapisz
folder/file.txt
. Teraz możesz wydać następujące polecenia wmyrepo_git
katalogu:Ach - tak aby zaznaczyć, że mamy rozwiązać konflikt, my musi , przed wykonaniem :
git add
folder/file.txt
git rebase --continue
Tutaj ponownie otwiera się edytor tekstowy, pokazujący wiersz
4th git commit
- tutaj mamy szansę zmienić komunikat zatwierdzenia (który w tym przypadku można znacznie zmienić na4th (and removed 3rd) commit
lub podobny). Powiedzmy, że nie chcesz - więc po prostu wyjdź z edytora tekstu bez zapisywania; gdy to zrobisz, otrzymasz:W tym momencie masz teraz taką historię (którą możesz również sprawdzić za pomocą powiedz
gitk .
lub innymi narzędziami) zawartościfolder/file.txt
(z pozornie niezmienionymi znacznikami czasu oryginalnych zatwierdzeń):A jeśli wcześniej postanowiliśmy zachować linię
cccc
(zawartość trzeciego git commit, którą usunęliśmy), mielibyśmy:Cóż, tego rodzaju lekturę miałem nadzieję znaleźć, żeby zacząć się zastanawiać, jak
git rebase
działa usuwanie skryptu ; więc mam nadzieję, że może to również pomóc innym ...źródło
Wygląda więc na to, że złe zatwierdzenie zostało w pewnym momencie włączone do zatwierdzenia scalania. Czy zatwierdzenie scalania zostało już wycofane? Jeśli tak, to będziesz chciał użyć
git revert
; będziesz musiał zacisnąć zęby i przejść przez konflikty. Jeśli nie, to możesz albo zmienić bazę, albo cofnąć, ale możesz to zrobić przed zatwierdzeniem scalania, a następnie powtórz scalenie.Naprawdę niewiele możemy ci pomóc w pierwszym przypadku. Po wypróbowaniu przywracania i stwierdzeniu, że automatyczny nie powiódł się, musisz zbadać konflikty i odpowiednio je naprawić. Jest to dokładnie ten sam proces, co naprawianie konfliktów scalania; możesz użyć,
git status
aby sprawdzić, gdzie znajdują się konflikty, edytować niepołączone pliki, znaleźć konfliktowe porcje, dowiedzieć się, jak je rozwiązać, dodać skonfliktowane pliki i wreszcie zatwierdzić. Jeśli używaszgit commit
samego (nie-m <message>
), komunikat, który pojawia się w twoim edytorze, powinien być szablonowym komunikatem utworzonym przezgit revert
; możesz dodać notatkę o tym, jak naprawiłeś konflikty, a następnie zapisać i wyjść z zatwierdzenia.W drugim przypadku, rozwiązującym problem przed scaleniem, istnieją dwie podklasy, w zależności od tego, czy wykonałeś więcej pracy od scalenia. Jeśli tego nie zrobisz, możesz po prostu
git reset --hard HEAD^
przerwać scalanie, cofnąć, a następnie powtórzyć scalanie. Ale zgaduję, że masz. Więc skończysz robić coś takiego:git rebase -i <something before the bad commit> <temporary branch>
aby usunąć zły zatwierdzenie)git rebase --onto <temporary branch> <old merge commit> <real branch>
źródło
Więc wykonałeś trochę pracy i przeforsowałeś je, nazwijmy je zobowiązaniami A i B. Twój współpracownik również wykonał trochę pracy, zobowiązuje się C i D. Połączyłeś pracę swoich współpracowników z twoimi (scalanie zatwierdzenia E), a następnie kontynuowałeś pracę, popełniłem to, też (popełnij F) i odkryłeś, że twój współpracownik zmienił pewne rzeczy, których nie powinien.
Twoja historia zmian wygląda następująco:
Naprawdę chcesz pozbyć się C, D i D '. Ponieważ mówisz, że połączyłeś pracę swoich współpracowników z twoimi, te zatwierdzenia są już „tam”, więc usunięcie zatwierdzeń przy użyciu np. Git rebase jest nie-nie. Uwierz mi, próbowałem.
Teraz widzę dwa wyjścia:
jeśli jeszcze nie wypchnąłeś E i F do swojego współpracownika lub kogokolwiek innego (zazwyczaj do twojego serwera „pochodzenia”), możesz na razie usunąć je z historii. To jest twoja praca, którą chcesz zapisać. Można to zrobić za pomocą
(zamień D 'na rzeczywisty skrót zatwierdzenia, który możesz uzyskać z
git log
W tym momencie zatwierdzenia E i F zniknęły, a zmiany są ponownie niezatwierdzonymi zmianami w lokalnym obszarze roboczym. W tym momencie przeniosę je do gałęzi lub zamienię w łatkę i zachowam na później. Teraz cofnij pracę współpracownika, albo automatycznie,
git revert
albo ręcznie. Gdy to zrobisz, powtórz swoją pracę nad tym. Możesz mieć konflikty scalania, ale przynajmniej będą one w kodzie, który napisałeś, zamiast kodu współpracownika.Jeśli już wykonałeś pracę po popełnieniu przez współpracownika, nadal możesz spróbować uzyskać „odwrotną łatkę” ręcznie lub przy użyciu
git revert
, ale ponieważ twoja praca jest „na drodze”, więc tak powiem, prawdopodobnie dostaniesz więcej konfliktów scalania i bardziej zagmatwanych. Wygląda na to, że skończyłeś w ...źródło
git revert - strategia rozwiązać, jeśli zatwierdzenie jest scaleniem: użyj git revert - strategia rozwiązać -m 1
źródło