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?

Lakshman Prasad
źródło
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.

mgalgs
źródło
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
trójnik
źródło
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
VonC
źródło
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ć.

Dan Moulding
źródło
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.

Forrest
źródło
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.

Bharath TS
źródło
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
Imran Sahil
źródło
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 :)

Gabeeka
źródło