Czy mogę dokonać częściowego przywrócenia w GIT


156

Czy można cofnąć tylko jeden plik lub pewne zmiany w pliku przy zatwierdzaniu wielu plików?

Cała historia Popełniłem kilka plików. Kilka zatwierdzeń później ktoś, kto pozostanie bezimienny (JACK !!!), skopiował plik do swojego repozytorium i zatwierdził kilka plików, nadpisując niektóre ze zmian, które zrobiłem. Chcę przywrócić jeden plik, który został zbity lub jeszcze lepiej, wejść i cofnąć dwie zmiany w tym pliku. Będzie to musiało być oddzielnym zatwierdzeniem przywrócenia, ponieważ zostało wyciągnięte i wypchnięte.


Brian doprowadził mnie do właściwej drogi. Skończyło się na tym, że użyłem git add --patch, a następnie użyłem funkcji edycji w patchu, aby uzyskać to, czego chciałem.
— Sprzęgło

2
Jestem dość spóźniony do gry, ale myślę, że znalazłem „właściwą” odpowiedź .
— ntc2

@ ntc2 Dziwne, zaakceptowana odpowiedź zadziałała dla mnie znacznie lepiej niż ta, którą połączyłeś - stworzyła konflikty scalania, które musiałem rozwiązać, zamiast po prostu nie stosować poprawek.
— Iiridayn

@liridayn Czy przeczytałeś całą moją odpowiedź? W sekcji „Odmiany” twierdzę, że dodanie --3waypowoduje konflikty scalania zamiast niepowodzenia w zastosowaniu poprawek.
— ntc2

Odpowiedzi:


204

Możesz cofnąć zatwierdzenie bez tworzenia nowego, dodając opcję „--no-commit”. Spowoduje to pozostawienie wszystkich przywróconych plików w obszarze przemieszczania. Stamtąd wykonałem miękki reset i dodałem zmiany, których naprawdę chciałem. Przykładowy przepływ pracy:

git revert <sha-of-bad-commit> --no-commit
git reset   // This gets them out of the staging area
<edit bad file to look like it should, if necessary>
git add <bad-file>
git checkout . // This wipes all the undesired reverts still hanging around in the working copy
git commit

42
Po miękkim resecie możesz również git add -prozpocząć interaktywną sesję, która pozwala selektywnie dodawać fragmenty plików zamiast całych plików. (Istnieje również git reset -pmożliwość wybiórczego wycofywania zmian. Dobrze wiedzieć, ale prawdopodobnie nie to, co chcesz w tym scenariuszu.)
— Stéphan Kochen

1
Właśnie tego szukałem: Przywróć kopię roboczą, wybierz interaktywnie porcje, zatwierdź. Zasługujesz za to na wielkiego, słonego faceta: *
— das_weezul

Innym rozwiązaniem zainspirowany tym jednym byłoby revert, reset, stash -p(zapas „anuluje, że nie chcę, aby właściwie make”), addreszta,commit
— Cyril chapon

82

Możesz interaktywnie zastosować starą wersję pliku za pomocą checkoutpolecenia.

Na przykład, jeśli wiesz, COMMITgdzie kod do dodania został usunięty, możesz uruchomić następujące polecenie:

git checkout -p COMMIT^ -- FILE_TO_REVERT

Git poprosi cię o dodanie porcji, których brakuje w bieżącej wersji pliku. Możesz użyć, eaby utworzyć łatkę zmiany przed jej ponownym zastosowaniem.


Bardzo przydatne, jeśli chcesz przywrócić tylko część pliku! Zasadniczo, żeby dostać kawałki z głowy,git checkout -p path/to/file
— falstaff

40

Możesz po prostu ręcznie sprawdzić starą, dobrą zawartość plików, które chcesz przywrócić git checkout. Na przykład, jeśli chcesz powrócić my-important-filedo wersji, która była w wersji abc123, możesz to zrobić

git checkout abc123 -- my-important-file

Teraz masz starą zawartość z my-important-filepowrotem i możesz ją nawet edytować, jeśli masz na to ochotę, i zatwierdzić jak zwykle, aby dokonać zatwierdzenia, które przywróci zmiany, które wprowadził. Jeśli są tylko niektóre części jego zatwierdzenia, które chcesz cofnąć, użyj, git add -paby wybrać tylko kilka porcji z poprawki, którą zatwierdzasz.


19
To nie jest plik revert, po prostu przywracasz starą wersję pliku. Właściwy revertusunie złe zmiany w pliku, nawet jeśli był modyfikowany kilka razy od tego złego zatwierdzenia, a nie chcesz stracić tych modyfikacji.
— Totor

2
Totor, zobacz moją odpowiedź. Możesz użyć '-p', aby zapisać modyfikacje. Odpowiedź jest właściwie bardzo bliska tej.
— cmcginty

1
Lub możesz połączyć to w git checkout -p.
— Léo Lam

31

Znalazłem sposób na zrobienie tego na liście mailingowej Git:

git show <commit> -- <path> | git apply --reverse

Źródło: http://git.661346.n2.nabble.com/Revert-a-single-commit-in-a-single-file-td6064050.html#a6064406

Wariacje

To polecenie kończy się niepowodzeniem (nie powodując żadnych zmian), jeśli łatka nie działa prawidłowo, ale --3wayzamiast tego pojawiają się konflikty, które można następnie rozwiązać ręcznie (w tym przypadku odpowiedź Casey może być bardziej praktyczna):

git show <commit> -- <path> | git apply --reverse --3way

Możesz również użyć tego do częściowego cofnięcia wielu zatwierdzeń, np .:

git log -S<string> --patch | git apply --reverse

aby przywrócić pliki ze zmianami pasującymi <string>do dowolnego zatwierdzenia. To jest dokładnie to, czego potrzebowałem w moim przypadku użycia (kilka oddzielnych zatwierdzeń wprowadziło podobne zmiany w różnych plikach, a także zmiany innych plików w niepowiązany sposób, którego nie chciałem cofać).

Jeśli diff.noprefix=trueustawiłeś w swoim ~/.gitconfigto musisz dodać -p0do git applypolecenia np

git show <commit> -- <path> | git apply -p0 --reverse

Ta odpowiedź jest znacznie lepsza niż zaakceptowana: „jeszcze lepiej, wejdź i cofnij dwie zmiany w tym pliku”.
— przepisano

Chciałem cofnąć tylko część zatwierdzenia, więc zrobiłem: (1) git show ... > foo.txt (2) edytując, foo.txtaby usunąć różnice, których nie chciałem cofać (3), git apply --reverse foo.txt aby przywrócić różnice wciąż wymienione w foo.txt.
— cxw

Dodanie --binary --full-index do części git show może być również przydatną odmianą
— Laurynas Biveinis
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.