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

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

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

git-show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8 my_file.txt

Jednak to polecenie pokazuje różnicę, a nie Zawartość pliku. Wiem, że mogę później użyć czegoś takiego jak PAGER=cat i przekierowanie wyjścia do pliku, ale nie wiem, jak dostać się do rzeczywistej zawartości pliku.

Zasadniczo szukam czegoś w rodzaju svn cat.

Author: SherylHohman, 2009-03-04

11 answers

Za pomocą git show

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 rewizji, co oznacza, że możesz użyć dowolnego z następujących poleceń:

  1. branch name (as suggested by ash)
  2. HEAD + x liczba ^ znaków
  3. hash SHA1 danej wersji
  4. kilka pierwszych (Może 5) znaków danego hasha SHA1

Wskazówka ważne jest, aby pamiętać, że podczas używania "git show", zawsze należy podać ś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żesz określić ścieżkę względną, umieszczając "./" na początku ścieżki. Na przykład:

git show HEAD^^:./test.py

)

Za pomocą git restore

Z Git 2.23+ (Sierpień 2019), możesz również użyć git restore który zastępuje mylące git checkout polecenie

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

, który przywróci na drzewie roboczym tylko plik obecny w źródle "" (-s) commit SHA1 lub branch somebranch.
Aby przywrócić również indeks:

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

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

Używanie niskopoziomowych poleceń git plumbing

Przed git1. 5.x, to było zrobione jakimś kanalizacją:

git ls-tree <rev>
pokazuje listę co najmniej jednego obiektu 'blob' w commicie

git cat-file blob <file-SHA1>
cat a file as it has been committed w ramach określonej rewizji (podobnej do svn cat). użyj git ls-tree, aby pobrać wartość podanego pliku-sha1

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

git-ls-tree wyświetla ID obiektu $file w revision $REV, jest on wycięty z wyjścia i używany jako argument do git-cat-file, który powinien być naprawdę nazywany git-cat-object, i po prostu zrzuca ten obiekt do stdout.


Uwaga: Od wersji Git 2.11 (Q4 2016), możesz zastosować filtr zawartości do wyjścia git cat-file.

Zobacz commit 3214594 , commit 7bcf341 (09 wrz 2016), commit 7bcf341 (09 wrz 2016), oraz commit b9e62f6 , commit 16dcc29 (24 sierpnia 2016) by Johannes Schindelin (dscho).
(dodane przez Junio C Hamano -- gitster -- in commit 7889ed2, 21 Sep 2016)

git config diff.txt.textconv "tr A-Za-z N-ZA-Mn-za-m <"
git cat-file --textconv --batch
W 2017 roku segfaulting został poprawiony w Git 2.15 (Q4 2017) {[36]]}

Zobacz commit cc0ea7c (21 września 2017) by Jeff King (peff).
(dodane przez Junio C Hamano -- gitster -- in commit bfbc2fc, 28 Sep 2017)

 805
Author: VonC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-25 19:23:07

Jeśli chcesz zastąpić / zastąpić Zawartość pliku w bieżącej gałęzi zawartością pliku z poprzedniego commita 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żącej gałęzi.

 522
Author: c-a,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-01 16:12:41

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

git show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8:full/repo/path/to/my_file.txt
 153
Author: Milan Babuškov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-20 23:52:09

Najprostszym sposobem jest napisanie:

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

Gdzie:

  • HASH jest numerem skrótu Git revision SHA-1
  • plik / ścieżka / nazwa.ext to nazwa pliku, którego szukasz
  • some_new_name.ext jest ścieżką i nazwą, do której należy zapisać stary plik

Przykład

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

To zapisze my_file.txt z rewizji 27cf8ejako nowy plik o nazwie my_file.txt.OLD

To było testowane z Git 2.4.5.

Jeśli chcesz odzyskać usunięty plik możesz użyć HASH~1 (jeden commit przed podanym Hashem).

Przykład:

git show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8~1:deleted_file.txt > deleted_file.txt
 115
Author: jmarceli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-20 09:12:55

W Windows, z Git Bash:

  • w obszarze roboczym zmień katalog do folderu, w którym mieszka Twój plik
  • git show cab485c83b53d56846eb883babaaf4dff2f2cc46:./your_file.ext > old.ext
 12
Author: Alessandro Jacopson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-02 16:17:24

I ładnie wrzucić go do pliku (przynajmniej na Windows) - Git Bash:

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

Cudzysłowy " są potrzebne, aby zachować nowe linie.

 8
Author: Mr_and_Mrs_D,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-20 23:53:50
git checkout {SHA1} -- filename

To polecenie pobiera skopiowany plik z określonego commita.

 6
Author: jsina,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-09-28 19:42:48

To pomoże ci uzyskać wszystkie usunięte pliki między zatwierdzeniami bez podawania ścieżki, przydatne, jeśli istnieje wiele usuniętych plików.

git diff --name-only --diff-filter=D $commit~1 $commit | xargs git checkout $commit~1
 5
Author: Adrian Gunawan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-24 02:34:05

Oprócz wszystkich opcji wymienionych w innych odpowiedziach, możesz użyć git reset z obiektem Git (hash, branch, HEAD~x, tag,...) interesującego i ścieżki pliku:

git reset <hash> /path/to/file

W twoim przykładzie:

git reset 27cf8e8 my_file.txt

To powoduje, że powróci my_file.txt do swojej wersji w zatwierdzeniu 27cf8e8 w indeksie, pozostawiając ją nietkniętą (tak jak w bieżącej wersji) w katalogu roboczym.

Stamtąd wszystko jest bardzo proste:

  • możesz porównać dwie wersje Twojego pliku z git diff --cached my_file.txt
  • możesz pozbyć się starej wersji pliku za pomocą git restore --staged file.txt (lub, przed Git v2.23, git reset file.txt) jeśli zdecydujesz, że ci się nie podoba
  • możesz przywrócić starą wersję za pomocą git commit -m "Restore version of file.txt from 27cf8e8" i git restore file.txt (lub, przed Git v2.23, git checkout -- file.txt)
  • możesz dodawać aktualizacje ze starej do nowej wersji tylko dla niektórych kawałków, uruchamiając git add -p file.txt (następnie git commit i git restore file.txt).

Wreszcie, można nawet interaktywnie wybrać i wybrać, które hunk (s) do resetowania w bardzo pierwszy krok po uruchomieniu:

git reset -p 27cf8e8 my_file.txt

Tak więc git reset ze ścieżką daje dużą elastyczność pobierania określonej wersji pliku w celu porównania z aktualnie pobraną wersją i, jeśli zdecydujesz się to zrobić, aby przywrócić w pełni lub tylko dla niektórych fragmentów do tej wersji.


Edit: właśnie zdałem sobie sprawę, że nie odpowiadam na twoje pytanie, ponieważ to, co chciałeś, nie było diffem ani łatwym sposobem na odzyskanie części lub całości starej wersji, ale po prostu cat, że wersja.

Oczywiście nadal możesz to zrobić po zresetowaniu pliku za pomocą:

git show :file.txt

Do wyjścia na standardowe wyjście lub

git show :file.txt > file_at_27cf8e8.txt

Ale jeśli to było wszystko, czego chciałeś, bieganie git show bezpośrednio z git show 27cf8e8:file.txt, jak sugerowali inni, jest oczywiście o wiele bardziej bezpośrednie.

Zostawię jednak tę odpowiedź, ponieważ uruchamianie git show bezpośrednio pozwala na natychmiastowe uzyskanie starej wersji, ale jeśli chcesz coś z nią zrobić, nie jest to aż tak wygodne, aby to zrobić jest, jeśli zresetujesz tę wersję w indeksie.

 2
Author: prosoitos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-09-14 00:21:26

Użycie git show $REV:$FILE, Jak już wskazywali inni, jest prawdopodobnie właściwą odpowiedzią. Zamieszczam kolejną odpowiedź, ponieważ kiedy próbowałem tej metody, czasami dostałem następujący błąd od git:

fatal: path 'link/foo' exists on disk, but not in 'HEAD'

Problem występuje, gdy część ścieżki do pliku jest dowiązaniem symbolicznym. W takich przypadkach metoda git show $REV:$FILE będzie działać , a nie. Kroki do odtworzenia:

$ git init .
$ mkdir test
$ echo hello > test/foo
$ ln -s test link
$ git add .
$ git commit -m "initial commit"
$ cat link/foo
hello
$ git show HEAD:link/foo
fatal: path 'link/foo' exists on disk, but not in 'HEAD'

Problem polega na tym, że narzędzia takie jak realpath tutaj nie pomagają, ponieważ dowiązanie symboliczne może nie istnieć w bieżącym / align = "left" / Nie znam dobrego ogólnego rozwiązania. W moim przypadku wiedziałem, że dowiązanie symboliczne może istnieć tylko w pierwszym komponencie ścieżki, więc rozwiązałem problem używając metody git show $REV:$FILE dwa razy. To działa, ponieważ gdy git show $REV:$FILE jest używane na dowiązaniu symbolicznym, to jego cel jest drukowany:

$ git show HEAD:link
test

Podczas gdy w przypadku katalogów, polecenie wyświetli nagłówek, a następnie zawartość katalogu:

$ git show HEAD:test
tree HEAD:test

foo

Więc w moim przypadku właśnie sprawdziłem wyjście pierwszego wywołania git show $REV:$FILE i jeśli była to tylko pojedyncza linia, następnie zastąpiłem pierwszy komponent mojej ścieżki wynikiem, aby rozwiązać dowiązanie symboliczne poprzez git.

 1
Author: josch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-12-23 11:42:54

Pobranie pliku z poprzedniego zatwierdzenia poprzez sprawdzenie poprzedniego zatwierdzenia i skopiowanie pliku.

  • zwróć uwagę, na której gałęzi jesteś: Git branch
  • Sprawdź poprzedni commit, który chcesz: git checkout 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8
  • skopiuj plik do tymczasowej lokalizacji
  • Sprawdź gałąź, z której zacząłeś: git checkout theBranchYouNoted
  • skopiuj plik umieszczony w tymczasowej lokalizacji
  • Zatwierdź swoją zmianę do git: git commit -m "added file ?? from previous commit"
 -1
Author: rocketInABog,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-10 00:14:59