Cofnij zmiany w pliku w zatwierdzeniu


126

Chcę cofnąć zmiany wprowadzone przez określone zatwierdzenie tylko w danym pliku.

Czy mogę użyć do tego polecenia git revert?

Czy jest jakiś inny prosty sposób?


Duplikat
pliku

Dziwne ... skąd ta zmiana po tych wszystkich latach?
VonC,

Odpowiedzi:


222

Najczystszy sposób, w jaki widziałem, jest opisany tutaj

git show some_commit_sha1 -- some_file.c | git apply -R

Podobny do odpowiedzi VonC, ale używający git showi git apply.


10
Ładnie wykonane. Rozwiązanie skryptowe to przesada. Dlaczego nie może istnieć po prostu nazwa pliku przywracania sha-1 przez git?
Mark Edington

16
Działa to na moim Macu, ale na Windowsie (pod Cygwinem) daje mi:fatal: unrecognized input
Kedar Mhaswade

1
@MerhawiFissehaye: Myślę, że git checkout tylko cofnie zmiany, aby powrócić do stanu, który był w zatwierdzeniu. Zrobiłem „git add nazwa pliku; git commit --amend ', aby usunąć plik z zatwierdzenia.
ViFI

3
Tylko wskazówka, prawie zawsze muszę dodać -3flagę, aby git ubiegał się o trójdrożne scalanie, gdy łatka się nie powiedzie, ponieważ zwykle poprawiam zmianę nieco wstecz.
angularsen

2
Może to oczywiste dla większości, ale upewnij się, że some_file.czawiera ścieżkę do pliku, jeśli istnieje, w przeciwnym razie po cichu niczego nie
poprawisz

35

Zakładając, że zmiana historii zmian jest w porządku, oto przepływ pracy umożliwiający cofnięcie zmian w pojedynczym pliku we wcześniejszym zatwierdzeniu:

Na przykład chcesz cofnąć zmiany w 1 pliku ( badfile.txt) w zatwierdzeniu aaa222:

aaa333 Good commit
aaa222 Problem commit containing badfile.txt
aaa111 Base commit

Ponownie wykonaj podstawowe zatwierdzenie, popraw zatwierdzenie problemu i kontynuuj.

1) Uruchom interaktywną rebase:

git rebase -i aaa111

2) Zaznacz zatwierdzenie problemu do edycji w edytorze, zmieniając pickna e(do edycji):

e aaa222
pick aaa333

3) Przywróć zmiany w złym pliku:

git show -- badfile.txt | git apply -R

4) Dodaj zmiany i popraw zatwierdzenie:

git add badfile.txt
git commit --amend

5) Zakończ rebase:

git rebase --continue

Chcę tylko zaznaczyć, że zakłada to, że możesz edytować historię git. Niektóre powyższe odpowiedzi tworzą nowe zatwierdzenie, które odwraca określoną zmianę bez edytowania historii, co nie zawsze jest możliwe / dozwolone.
angularsen

Fantastyczny. To było dokładnie to, czego szukałem. Miałem już ten pomysł, ale pomyliłem się podczas wykonywania interaktywnej rebase, że pliki podczas wykonywania editnie były wyświetlane jako zmienione. Ale git show -- badfile.txt | git apply -Rudzielili odpowiedzi, której potrzebowałem <3
mraxus

jeśli rozumiem to git Apply -R usuwa zatwierdzenie w tym pliku, przywracając pierwotny zmieniony stan?
DaImTo

19

git revert dotyczy całej zawartości pliku w zatwierdzeniach.

W przypadku pojedynczego pliku możesz go skryptu :

#!/bin/bash

function output_help {
    echo "usage: git-revert-single-file <sha1> <file>"
}

sha1=$1
file=$2

if [[ $sha1 ]]; then
git diff $sha1..$sha1^ -- $file | patch -p1
else
output_help
fi

(Z narzędzi git-shell-scripts od smtlaissezfaire )


Uwaga:

inny sposób jest opisany tutaj, jeśli jeszcze nie zatwierdziłeś swojej bieżącej modyfikacji.

git checkout -- filename

git checkout ma kilka opcji dla pliku, modyfikując plik z HEAD, nadpisując zmiany.


Dropped.on.Caprica wspomina w komentarzach :

Możesz dodać alias do git, aby móc to zrobić git revert-file <hash> <file-loc>i przywrócić ten konkretny plik.
Zobacz to sedno .

[alias]
  revert-file = !sh /home/some-user/git-file-revert.sh

Aby dodać do dyskusji tutaj, możesz dodać alias do git, aby móc to zrobić git revert-file <hash> <file-loc>i przywrócić ten konkretny plik. Podniosłem się z tej odpowiedzi (chociaż musiałem wprowadzić kilka zmian, aby działać poprawnie). Możesz znaleźć kopię mojego .gitconfigi zredagowanego skryptu tutaj: gist.github.com/droppedoncaprica/5b67ec0021371a0ad438
AlbertEngelB

@ Dropped.on.Caprica dobra uwaga. Zawarłem to w odpowiedzi dla większej widoczności.
VonC

12

Po prostu skorzystałbym z --no-commitopcji, git-reverta następnie usunąłbym pliki, których nie chcesz przywrócić z indeksu, zanim ostatecznie go zatwierdzę. Oto przykład pokazujący, jak łatwo przywrócić tylko zmiany w foo.c w drugim ostatnim zatwierdzeniu:

$ git revert --no-commit HEAD~1
$ git reset HEAD
$ git add foo.c
$ git commit -m "Reverting recent change to foo.c"
$ git reset --hard HEAD

Najpierw git-reset„usuwa ze sceny” wszystkie pliki, abyśmy mogli dodać z powrotem tylko jeden plik, który chcemy przywrócić. Finał git-reset --hardpozbywa się pozostałych plików, których nie chcemy zachować.


9

O wiele prostsze:

git reset HEAD^ path/to/file/to/revert

następnie

git commit --amend   

i wtedy

git push -f

plik zniknął i zatwierdzenie skrótu, komunikatu itp. jest takie samo.


Czy potrzebujesz git checkout -- path/to/file/to/revertkroku , aby uzyskać kompletność ? Nie jest też prawdą, że potem hasz jest taki sam, prawda? Ostatnie zdanie mogłoby być lepsze jako coś w rodzaju: „W rezultacie ostatnie zatwierdzenie jest zastępowane nowym, różniącym się tylko tym, że nie zawiera zmian w przywróconym pliku”.
Kevin

@Kevin prawdopodobnie masz rację. Będę musiał dwukrotnie sprawdzić ostatnią linię, ale patrząc wstecz na to sprzed kilku lat, zdziwiłbym się, gdyby wartość skrótu zatwierdzenia pozostała niezmieniona.
Forrest

6
git reset HEAD^ path/to/file/to/revert/in/commit

Powyższe polecenie usunie plik z zatwierdzenia, ale zostanie odzwierciedlone w git status.

git checkout path/to/file/to/revert/in/commit

Powyższe polecenie cofnie zmiany (w rezultacie otrzymasz plik taki sam jak HEAD).

git commit

(Przejdź --amenddo zmiany zatwierdzenia).

git push

Dzięki temu plik, który jest już w zatwierdzeniu, jest usuwany i przywracany.

Powyższe kroki należy wykonać z gałęzi, w której dokonywane jest zatwierdzenie.


5

Możesz wykonać tę procedurę:

  1. git revert -n <*commit*>( -ncofnij wszystkie zmiany, ale ich nie zatwierdzi)
  2. git add <*filename*> (nazwa pliku / plików, które chcesz przywrócić i zatwierdzić)
  3. git commit -m 'reverted message' (dodaj wiadomość do przywrócenia)
  4. po zatwierdzeniu odrzuć zmiany w innych plikach, aby były one aktualizowane zgodnie ze zmianami wprowadzonymi przed przywróceniem

1

Jeśli chcesz zresetować zmiany w pliku z ostatniego zatwierdzenia, tego zwykle używam. Myślę, że to najprostsze rozwiązanie.

Zwróć uwagę, że plik zostanie dodany do obszaru przemieszczania.

git checkout <prev_commit_hash> -- <path_to_your_file>

Mam nadzieję, że to pomoże :)

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.