Jak odzyskać pojedynczy plik z określonej wersji w Git?


831

Mam repozytorium Git i chciałbym zobaczyć, jak wyglądały niektóre pliki kilka miesięcy temu. Znalazłem rewizję w tym dniu; to jest 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8. Muszę zobaczyć, jak wygląda jeden plik, a także zapisać go jako („nowy”) plik.

Udało mi się zobaczyć plik przy użyciu gitk, ale nie ma opcji, aby go zapisać. Próbowałem z narzędziami wiersza poleceń, najbliższe było:

git-show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8 my_file.txt

To polecenie pokazuje jednak różnicę, a nie zawartość pliku. Wiem, że mogę później użyć czegoś takiego PAGER=cati przekierować dane wyjściowe do pliku, ale nie wiem, jak uzyskać dostęp do rzeczywistej zawartości pliku.

Zasadniczo szukam czegoś takiego jak svn cat .


73
Klucz tutaj: git show(nieprzydatnie) używa innej składni z dwukropkiem. git show 2c7cf:my_file.txt
Steve Bennett

4
W celu dalszego wyjaśnienia powyższe polecenie prosi git o pokazanie dwóch oddzielnych obiektów, wersji i pliku. Przyjęta poniżej odpowiedź, która używa dwukropka między tymi dwoma elementami, prosi o określony plik przy konkretnej wersji.
jhclark

2
W * nix nie potrzebujesz PAGERA, wystarczy przekierowanie wyjścia powłoki za pomocą>
Konstantin Pelepelin


Checat ma ważny komentarz dla tych, którzy chcą wyeksportować zawartość do jakiegoś pliku. Potrzebujesz czegoś takiego: git show {sha}: my_file.txt> old_my_file.txt
ormurin

Odpowiedzi:


743

Aby uzupełnić własną odpowiedź, składnia jest rzeczywiście

git show object
git show $REV:$FILE
git show somebranch:from/the/root/myfile.txt
git show HEAD^^^:test/test.py

Polecenie przyjmuje zwykły styl zmiany, co oznacza, że ​​możesz użyć dowolnej z następujących opcji:

  1. Nazwa oddziału (jako sugerowane przez popiół )
  2. HEAD+ x liczba ^znaków
  3. Skrót SHA1 danej wersji
  4. Kilka pierwszych (może 5) znaków danego skrótu SHA1

Wskazówka Ważne jest, aby pamiętać, że używając „ git show”, zawsze określ ścieżkę z katalogu głównego repozytorium , a nie bieżącą pozycję katalogu.

(Chociaż Mike Morearty wspomina, że ​​przynajmniej w git 1.7.5.4 można określić ścieżkę względną, umieszczając „ ./” na początku ścieżki - na przykład:

git show HEAD^^:./test.py

)


W Git 2.23+ (sierpień 2019 r.) Możesz także użyć, git restore który zastępuje mylące git checkoutpolecenie

git restore -s <SHA1>     -- afile
git restore -s somebranch -- afile

Spowodowałoby to przywrócenie w działającym drzewie tylko pliku obecnego w zatwierdzeniu SHA1 lub gałęzi „source” ( -s)somebranch .
Aby przywrócić również indeks:

git restore -s <SHA1> -SW -- afile

( -SW: skrót od --staged --worktree)


Przed git1.5.x zrobiono to z pewną instalacją:

git ls-tree <rev>
pokaż listę jednego lub więcej obiektów „obiektów blob” w zatwierdzeniu

git cat-file blob <file-SHA1>
cat plik, ponieważ został zatwierdzony w ramach określonej wersji (podobnie jak svn cat). użyj git ls-tree, aby pobrać wartość danego pliku-sha1

git cat-file -p $(git-ls-tree $REV $file | cut -d " " -f 3 | cut -f 1)::

git-ls-tree wyświetla identyfikator obiektu dla pliku $ w wersji $ REV, jest on wycinany z danych wyjściowych i używany jako argument do pliku git-cat, który tak naprawdę powinien być nazwany git-cat-object, i po prostu zrzuca ten obiekt na standardowe wyjście.


Uwaga: od wersji Git 2.11 (IV kwartał 2016 r.) Można zastosować filtr zawartości do danych git cat-filewyjściowych!

Zobacz zatwierdzenie 3214594 , zatwierdzenie 7bcf341 (09 września 2016 r.), Zatwierdzenie 7bcf341 (09 września 2016 r.) I zatwierdzenie b9e62f6 , zatwierdzenie 16dcc29 (24 sierpnia 2016 r.) Przez Johannesa Schindelina ( dscho) .
(Połączone przez Junio ​​C Hamano - gitster- w commit 7889ed2 , 21 września 2016)

cat-file: wsparcie --textconv/ --filtersw trybie wsadowym

Chociaż „ git hash-objects”, które jest narzędziem do pobierania strumienia danych z systemu plików i umieszczania go w magazynie obiektów Git, pozwoliło na konwersję „poza światem do Git” (np. Konwersje i aplikacja na końcu linii z czystym filtrem) i miał on domyślnie włączoną funkcję od bardzo wczesnych dni, jej odwrotna operacja „ git cat-file”, która pobiera obiekt ze składnicy obiektów Git i przekazuje na zewnątrz do konsumpcji przez świat zewnętrzny, nie posiadała mechanizmu równoważnego z uruchom „Git-to-outside-world”

git config diff.txt.textconv "tr A-Za-z N-ZA-Mn-za-m <"
git cat-file --textconv --batch

Uwaga: „ git cat-file --textconv” zaczął segfaulting niedawno (2017), co zostało poprawione w Git 2.15 (IV kwartał 2017)

Zobacz commit cc0ea7c (21 września 2017 r.) Autor: Jeff King ( peff) .
(Połączone przez Junio ​​C Hamano - gitster- in commit bfbc2fc , 28 września 2017)


Pamiętaj, że aby zastąpić / zastąpić plik z zawartością z przeszłości, nie powinieneś już używać mylącego git checkoutpolecenia , ale git restore(Git 2.23+, sierpień 2019)

git restore -s <SHA1> -- afile

Spowodowałoby to przywrócenie w działającym drzewie tylko pliku obecnego w -szatwierdzeniu SHA1 „source” ( ).
Aby przywrócić również indeks:

git restore -s <SHA1> -SW -- afile

( -SW: skrót od --staged --worktree)


6
@Oscar, ponieważ git showzasadniczo zrzut zawartości na stdout(standardowe wyjście), możesz po prostu przekierować to wyjście do dowolnego pliku, który chcesz ( tldp.org/LDP/abs/html/io-redirection.html ).
VonC

8
git checkout [branch | revision] filepathto właściwe polecenie
Gaui

12
@Gaui ale git checkoutby zastąpić plik o innej wersji, w przeciwieństwie do git show, który pozwala zapisać go pod inną nazwą, aby można dostać i zobaczyć zarówno (aktualną wersję i starą wersję). Pytanie, czy OP chce zastąpić obecną wersję starą, nie jest jasne .
VCC,

9
Chciałbym zauważyć, że ^^^mogą być również bardziej ogólnie jako pisemnej ~~~lub lepiej ~3. Korzystanie z tyldy ma tę zaletę, że nie wyzwala dopasowywania nazw plików niektórych powłok (na przykład zsh).
Eric O Lebigot,

2
Nie mam wystarczająco starego gita do sprawdzenia: czy wersja wcześniejsza niż 1.5.x git rev-parseobsługuje rev:pathskładnię? (W nowszym git możesz git cat-file -p $REV:path. Jednak git showdziała również dla ścieżek katalogów, więc nie jest tylko krótszy, zwykle jest bliżej tego, czego się chce.)
torek

510

Jeśli chcesz zastąpić / zastąpić zawartość pliku w bieżącej gałęzi zawartością pliku z poprzedniego zatwierdzenia lub innej gałęzi, możesz to zrobić za pomocą następujących poleceń:

git checkout 08618129e66127921fbfcbc205a06153c92622fe path/to/file.txt

lub

git checkout mybranchname path/to/file.txt

Będziesz musiał zatwierdzić te zmiany, aby były skuteczne w bieżącym oddziale.


4
najprostsze rozwiązanie i do tego właśnie służy git-checkout - określenie nazwy ścieżki oznacza, że ​​pobierany jest tylko pasujący plik. Ze strony
podręcznika

1
Jak zatem powrócić do poprzedniego stanu przed uruchomieniem tego polecenia?
Flint

@ Flint, jeśli wychodzisz ze stanu HEAD, byłoby to tak proste jak git checkout HEAD - [pełna ścieżka].
Tiago Espinha,

72
Zauważ, że to zastępuje istniejący plik w tej ścieżce, podczas gdy git show SHA1:PATHrozwiązanie drukuje tylko na standardowe wyjście.
Flimm

Miły! Nie byłbym w stanie tego zrozumieć, patrząc na git help checkout. Musiałem sprawdzić podkatalog od określonej daty i stosując to podejście, mogłem uruchomić tę składnię:git checkout @{YYYY-MM-DD} sub-dir
haridsv

150

Musisz podać pełną ścieżkę do pliku:

git show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8:full/repo/path/to/my_file.txt

7
nie musi być pełną ścieżką. Ścieżka z katalogu głównego git (ci, którzy weszli git show --name-only, też wystarczą
Mohsen

7
Eee, pełna ścieżka z katalogu głównego repozytorium. Przyjrzyj się lepiej podanemu przeze mnie przykładowi. Nie ma wiodącego ukośnika przed „pełnym”.
Milan Babuškov

7
Do Twojej wiadomości, jeśli jesteś w podkatalogu, możesz również z powodzeniem użyć pliku ./filename.ext.
Podróżnik

Myślę, że chodzi o to, że jeśli jesteś w środku full/repo/path/toi spróbujesz: git show 27cf8e84:my_file.txtotrzymasz nagrodę w postaci: fatal: ścieżka „pełna / repo / ścieżka / do / mój_plik.txt” istnieje, ale nie „mój_plik.txt” . Miałeś na myśli „27cf8e84: full / repo / path / to / my_file.txt” aka „27cf8e84: ./ my_file.txt”? To tak, jakby Git mógł pomóc bezpośrednio, ale postanowił być pedantyczny.
Ed Randall

101

Najprostszym sposobem jest napisać:

git show HASH:file/path/name.ext > some_new_name.ext

gdzie:

  • HASH to numer skrótu SHA-1 w wersji Git
  • file / path / name.ext to nazwa szukanego pliku
  • some_new_name.ext to ścieżka i nazwa, w której powinien zostać zapisany stary plik

Przykład

git show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8:my_file.txt > my_file.txt.OLD

Spowoduje to zapisanie my_file.txt z wersji 27cf8e jako nowego pliku o nazwie my_file.txt.OLD

Został przetestowany z Git 2.4.5.

Jeśli chcesz odzyskać usunięty plik, możesz go użyć HASH~1(jeden zatwierdzenie przed określonym HASH).

PRZYKŁAD:

git show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8~1:deleted_file.txt > deleted_file.txt

1
Informacje dodatkowe: Możesz uzyskać HASH np. Z git log
xotix

@xotix Thanks. Mam całą historię HASH dla konkretnego pliku przy użyciugit log file/path/name.ext
Sriram Kannan

11

W systemie Windows za pomocą Git Bash:

  • w swoim obszarze roboczym zmień katalog na folder, w którym znajduje się plik
  • git show cab485c83b53d56846eb883babaaf4dff2f2cc46:./your_file.ext > old.ext

8

Aby ładnie zrzucić go do pliku (przynajmniej w systemie Windows) - Git Bash:

$ echo "`git show 60d8bdfc:src/services/LocationMonitor.java`" >> LM_60d8bdfc.java

Że "potrzebne są cytaty tak zachowuje nowe linie.


Niezłe. +1. Dobry dodatek do git showskładni, o której wspomniałem powyżej.
VonC

23
Naprawdę nie rozumiem, dlaczego miałbyś używać echa, z cytatami lub bez nich. I nie rozumiem, dlaczego chcesz mieć dołączoną formę przekierowania danych wyjściowych. Czy nie byłoby lepiej po prostu napisać: git show 60d8bdfc: src / services / LocationMonitor.java> LM_60d8bdfc.java Jeśli z jakiegoś powodu chciałbyś wymusić zakończenie linii w stylu dos, możesz przepuścić go przez unix2dos. Ale nigdy nie uważałem za najmniej użyteczne zachowanie końcówek wiersza dos w systemie Windows, ponieważ wszelkie narzędzia tekstowe inne niż notatnik, których użyłem w systemie Windows, dobrze sobie radzą z liniami uniksowymi.
sootsnoot

4
git show 60d8bdfc: src / services / LocationMonitor.java >> LM_60d8bdfc.java pracował dla mnie.
Mike6679,

@ Mike: czy jesteś w systemie Windows?
Mr_and_Mrs_D

2
nie używaj podwójnych cudzysłowów, ponieważ jeśli znaki w pliku, które wyglądają jak zmienna powłoki, np. $ LANG, zostaną zastąpione. @ LưuVĩnhPhúc jest oszczędny. również nie używaj >>
Dołącza

3

Pomoże to uzyskać wszystkie usunięte pliki między zatwierdzeniami bez określania ścieżki, co jest przydatne, jeśli usunięto wiele plików.

git diff --name-only --diff-filter=D $commit~1 $commit | xargs git checkout $commit~1

1
git checkout {SHA1} -- filename

to polecenie pobiera skopiowany plik z określonego zatwierdzenia.


-2

Pobierz plik z poprzedniego zatwierdzenia poprzez pobranie poprzedniego zatwierdzenia i skopiowanie pliku.

  • Zwróć uwagę na gałąź, w której się znajdujesz: gałąź git
  • Sprawdź poprzednie zatwierdzenie, które chcesz: git checkout 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8
  • Skopiuj żądany plik do tymczasowej lokalizacji
  • Kasa od której zacząłeś: git checkout theBranchYouNoted
  • Skopiuj plik umieszczony w tymczasowej lokalizacji
  • Zatwierdź zmianę w git: git commit -m "added file ?? from previous commit"
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.