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 .

Milan Babuškov
źródło
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
możliwy duplikat Czy istnieje szybkie polecenie git, aby zobaczyć starą wersję pliku?
Ciro Santilli 冠状 病毒 审查 六四 事件 法轮功
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)

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

ca
źródło
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
Milan Babuškov
źródło
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
jmarceli
źródło
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
Alessandro Jacopson
źródło
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.

Mr_i_Mrs_D
źródło
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
Adrian Gunawan
źródło
1
git checkout {SHA1} -- filename

to polecenie pobiera skopiowany plik z określonego zatwierdzenia.

jsina
źródło
-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"
rocketInABog
źródło