git selektywnie przywraca lokalne zmiany z pliku

149

W moim repozytorium git, które śledzi repozytorium svn, dokonałem wielu zmian w jednym pliku.

Teraz chcę cofnąć te zmiany (jak przywracanie svn), ale tylko części pliku.

Chcę mieć możliwość przeglądania różnic w pliku, odrzucania (cofania) zmian, których nie chcę i zachować zmiany, których chcę.

the

git add -i 

Wydaje się, że polecenie ma opcję zrobienia tego, ale nie chcę jeszcze tego robić.

Pradeep
źródło

Odpowiedzi:

91

Możesz to zrobić bezpośrednio z git checkout -p. Zobacz odpowiedź Daniela Stutzbacha poniżej.


Stara odpowiedź (wcześniej checkout -pzostała wprowadzona):

Możesz to zrobić w ten sposób:

git add -i

(wybierz porcje, które chcesz zatrzymać)

git commit -m "tmp"

Teraz masz zatwierdzenie zawierające tylko te zmiany, które chcesz zachować, a reszta nie jest umieszczona na scenie.

git reset --hard HEAD

W tym momencie niezatwierdzone zmiany zostały odrzucone, więc masz czysty katalog roboczy, ze zmianami, które chcesz zachować na wierzchu.

git reset --mixed HEAD^

Spowoduje to usunięcie ostatniego zatwierdzenia („tmp”), ale zachowa modyfikacje w katalogu roboczym bez umieszczenia na scenie.

EDYCJA: zastąpione --softprzez --mixed, aby wyczyścić obszar przemieszczania.

Paolo Capriotti
źródło
to spowoduje zmiany, które chcę zachować, prawda? Nie chcę jeszcze dokonywać tych zmian. mm może zbyt poważnie podchodzę do zobowiązań. Może powinienem teraz się zrelaksować, ponieważ wszystko jest w lokalnym repozytorium. btw co robi reset git - soft HEAD ^?
Pradeep,
"git reset --soft HEAD ^" cofa zatwierdzenie w tym sensie, że zachowuje katalog roboczy i indeks tak, jak było, i przenosi bieżącą gałąź o jedno zatwierdzenie z powrotem.
Jakub Narębski
Dzięki Jakub. Paolo, dlaczego tu potrzebny byłby miękki reset do głowy - 1? częściowe zatwierdzenie i twardy reset nie powinny wystarczyć, czy nie jest to zachowanie niektórych zmian i odrzucenie innych?
Pradeep,
1
Poniższa odpowiedź Daniela jest bardzo prosta i wygląda na właściwy sposób, aby to zrobić.
Umang,
309

Uważam, że najprościej można to zrobić za pomocą:

git checkout -p <optional filename(s)>

Ze strony podręcznika:

   −p, −−patch
       Interactively select hunks in the difference between the <tree−ish>
       (or the index, if unspecified) and the working tree. The chosen
       hunks are then applied in reverse to the working tree (and if a
       <tree−ish> was specified, the index).
       This means that you can use git checkout −p to selectively discard
       edits from your current working tree.
Daniel Stutzbach
źródło
1
Ponadto, jeśli nie chcesz robić tego wybiórczo, możesz użyć polecenia „git checkout - <file> ...”, aby odrzucić zmiany.
db42,
Czy dotyczy katalogów?
bbum
1
Wydaje mi się, że bardzo mi się to nie udaje, gdy odrzucam zmiany („błąd: poprawka nie powiodła się <plik>”, „błąd: <plik> poprawka nie ma zastosowania”). O dziwo, otrzymam te błędy, gdy używam aopcji w trybie łatki do odrzucenia całego pliku, ale git checkout -- <file>działa zgodnie z oczekiwaniami. Czy ktoś wie, dlaczego?
chrnola
Miałem ten błąd kilka razy, jeśli plik został już załatany, więc interaktywna łatka była nieaktualna z łatkami zastosowanymi w bieżącym pliku. Zdarzyło się to podczas korzystania z narzędzia gui, takiego jak drzewo źródłowe, gdy dwukrotnie przypadkowo wyrzuciłem porcję. Za drugim razem ten błąd.
phyatt,
3

Możesz uruchomić git diffplik, zapisać wynikowy różnicę, edytować go, aby usunąć zmiany, które chcesz zapisać, a następnie uruchomić go, patch -Raby cofnąć pozostałe różnice.

git diff file.txt> patch.tmp
# edytuj patch.tmp, aby usunąć porcje, które chcesz zachować
patch -R <patch.tmp
Greg Hewgill
źródło
Miałem 2 porcje w moim pliku łatki i usunąłem jedną. Nie jestem pewien, jaki jest powód, ale łatka -R jest przez to odrzucana.
Pradeep,
2
Wspomniałeś w innym komentarzu, który git diffpokazuje cały plik jako zmieniony. Zwykle dzieje się tak, gdy plik został zapisany z różnymi zakończeniami linii niż poprzednio. Spowodowałoby to również patchodrzucenie pliku poprawki. Czy to brzmi jak to, co mogło się stać?
Greg Hewgill,
masz rację. końce linii są przełączane za każdym razem, gdy używam polecenia patch. Jestem na oknach i używam cream / vim. Myślę, że najpierw trzeba to rozwiązać.
Pradeep,
Nie udało mi się rozwiązać problemu z poprawką w systemie Windows. Chociaż jestem pewien, że to działa, wolę skorzystać z przepisu Paolo. Z miłości do tych interaktywnych poleceń do pracy z różnicami za pomocą git add -i.
Pradeep
3

Wygląda na to, że chcesz

 git revert --no-commit $REVSISON 

Następnie możesz użyć

 git diff --cached

aby zobaczyć, jaka zmiana zostanie wprowadzona przed zatwierdzeniem (ponieważ cofanie jest po prostu zatwierdzeniem w kierunku do przodu, które replikuje odwrotność zmiany w przeszłości)

Jeśli korzystasz z czystego repozytorium Git, możesz ewentualnie, w zależności od swoich celów, użyć interaktywnej rebase ( git rebase -i), aby wrócić do zatwierdzenia, którego nie lubiłeś i edytować zatwierdzenie wstecz, aby zmiany, których nie lubisz, nigdy nie miały miejsca , ale to generalnie tylko wtedy, gdy WIESZ, że już nigdy nie będziesz chciał tego oglądać.

Kent Fredric
źródło
Cofnąłem się, jak wspomniałeś, do poprzedniej wersji (czy to prawda?), A teraz git diff po prostu pokazuje cały plik jako zmieniony. Ma pokazywać wprowadzone przeze mnie zmiany?
Pradeep,
1

Czytając ponownie pytanie, wygląda na to, że chcesz cofnąć zmiany, które są w twoim drzewie roboczym, a nie zmiany, które zostały wcześniej wprowadzone, ale niektóre inne odpowiedzi sprawiają, że brzmi to tak, jakby moje czytanie mogło być błędne. Możesz wyjaśnić?

Jeśli zmiany znajdują się tylko w kopii roboczej, najłatwiejszym sposobem na to jest przygotowanie zmian, które chcesz zachować:

git add -i <file>

Następnie wyrzuć zmiany, których nie chcesz zachować, sprawdzając wersję indeksu:

git checkout -- <file>

Następnie wycofaj zmiany, jeśli nie chcesz ich jeszcze wystawiać:

git reset -- <file>

Ta reguła przywraca tylko wybrane zmiany w pliku (lub plikach, które określisz) i nie tworzy żadnego tymczasowego zatwierdzenia, które następnie wymaga cofnięcia.

Jeśli chcesz selektywnie zastosować tylko niektóre zmiany dokonane w poprzednich zatwierdzeniach, możesz najpierw zresetować plik do poprzedniego stanu zatwierdzonego:

git reset <commit_before_first_unwanted_change> -- <file>

Następnie możesz postępować zgodnie z poprzednim przepisem, git add -i <file>aby wprowadzić zmiany, które chcesz zachować, git checkout -- <file>wyrzucić niechciane zmiany i git reset -- <file>„cofnąć” zmiany.

CB Bailey
źródło
0

Opcje wiersza poleceń opisane w odpowiedziach tutaj są przydatne, gdy plik znajduje się na serwerze, do którego mam dostęp przez terminal ssh. Jednak gdy plik znajduje się na moim komputerze lokalnym, wolę następujący sposób:

Otwórz plik w edytorze netbeans (który jest wyposażony w obsługę git). Netbeans umieszcza czerwone / zielone / niebieskie znaki na numerach wierszy, aby wskazać, gdzie elementy zostały usunięte / dodane / zmodyfikowane (odpowiednio).

Kliknięcie dowolnego z tych znaków prawym przyciskiem myszy daje możliwość cofnięcia tej zmiany. Ponadto możesz kliknąć prawym przyciskiem myszy czerwone i niebieskie znaki, aby zobaczyć starą wersję w wyskakującym okienku.

Abhishek Anand
źródło