Как получить один файл из определенной ревизии в Git?

833

У меня есть Git-репозиторий, и я хотел бы посмотреть, как некоторые файлы выглядели несколько месяцев назад. Я нашел ревизию в тот же день; это 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8. Мне нужно посмотреть, как выглядит один файл, а также сохранить его как («новый») файл.

Мне удалось увидеть файл с помощью gitk, но у него нет возможности сохранить его. Я попробовал с инструментами командной строки, ближе всего я получил:

git-show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8 my_file.txt

Однако эта команда отображает diff, а не содержимое файла. Я знаю, что позже смогу использовать что-то подобное PAGER=catи перенаправить вывод в файл, но я не знаю, как добраться до реального содержимого файла.

По сути, я ищу что-то вроде svn cat .

Милан Бабушков
источник
73
Ключ здесь: git show(бесполезно) использует другой синтаксис с двоеточием. git show 2c7cf:my_file.txt
Стив Беннетт
4
Чтобы уточнить, приведенная выше команда просит git показать два отдельных объекта, ревизию и файл. Принятый ответ ниже, который использует двоеточие между этими двумя пунктами, запрашивает определенный файл в определенной ревизии.
jhclark
2
В * nix вам не нужен PAGER, просто перенаправление вывода оболочки>
Константин Пелепелин
Возможный дубликат Есть ли быстрая команда git, чтобы увидеть старую версию файла?
Сиро Сантилли 郝海东 冠状 病 六四 事件 法轮功
У Checat есть важный комментарий для тех, кто хочет экспортировать контент в какой-то файл. Вам нужно что-то вроде этого: git show {sha}: my_file.txt> old_my_file.txt
ormurin

Ответы:

745

Чтобы завершить свой собственный ответ, синтаксис действительно

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

Команда принимает обычный стиль ревизии, то есть вы можете использовать любое из следующего:

  1. название филиала (как предложено по золе )
  2. HEAD+ х количество ^символов
  3. Хэш SHA1 данной ревизии
  4. Первые несколько (возможно, 5) символов данного хэша SHA1

Совет Важно помнить, что при использовании " git show", всегда указывайте путь от корня хранилища , а не текущую позицию каталога.

(Хотя Майк Морарти упоминает, что, по крайней мере с git 1.7.5.4, вы можете указать относительный путь, поставив " ./" в начале пути - например:

git show HEAD^^:./test.py

)


В Git 2.23+ (август 2019 г.) вы также можете использовать команду,git restore которая заменяет запутанную git checkoutкоманду

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

Это восстановило бы на рабочем дереве только тот файл, который присутствует в коммите "source" ( -s) SHA1 или ветви somebranch.
Чтобы восстановить также индекс:

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

( -SW: сокращение от--staged --worktree )


До git1.5.x это было сделано с помощью некоторой сантехники:

git ls-tree <rev>
показать список одного или нескольких объектов blob в коммите

git cat-file blob <file-SHA1>
cat файл, который был зафиксирован в определенной ревизии (аналог svn cat). используйте git ls-tree для получения значения заданного файла-sha1

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

git-ls-tree перечисляет идентификатор объекта для $ file в ревизии $ REV, это вырезано из вывода и используется в качестве аргумента для git-cat-file, который на самом деле должен называться git-cat-object, и просто выдает дамп этот объект на стандартный вывод.


Примечание: начиная с Git 2.11 (4 квартал 2016 г.), вы можете применить фильтр содержимого к git cat-file выводу!

См. Коммит 3214594 , коммит 7bcf341 (09 сентября 2016 г.), коммит 7bcf341 (09 сентября 2016 г.) и коммит b9e62f6 , коммит 16dcc29 (24 августа 2016 г.) от Johannes Schindelin ( dscho) .
(Слиты Junio C Hamano - gitster- в фиксации 7889ed2 , 21 сент 2016)

cat-file: поддержка --textconv/--filters в пакетном режиме

Несмотря на то, что " git hash-objects", который является инструментом для получения потока данных внутри файловой системы и помещения его в хранилище объектов Git, позволял выполнять преобразования "из внешнего мира в Git" (например, преобразования конца строки и приложения чистого фильтра), и с самого начала у него была функция, включающая по умолчанию, его обратная операция " git cat-file", которая берет объект из хранилища объектов Git и выводит его для потребления внешним миром, не имела эквивалентного механизма для запустить "Git-to-external-world"

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

Примечание: " git cat-file --textconv" начал segfaulting недавно (2017 г.), что было исправлено в Git 2.15 (4 квартал 2017 г.)

Смотрите коммит cc0ea7c (21 сентября 2017 г.) Джеффа Кинга ( peff) .
(Объединено Junio ​​C Hamano - gitster- в коммите bfbc2fc , 28 сентября 2017 г.)


Обратите внимание, что для переопределения / замены файла с прошлым содержимым вам больше не следует использовать запутанную git checkoutкоманду , но git restore(Git 2.23+, август 2019 г.)

git restore -s <SHA1> -- afile

Это восстановит на рабочем дереве только тот файл, который присутствует в коммите "source" ( -s) SHA1.
Чтобы восстановить также индекс:

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

( -SWсокращение от--staged --worktree )

VonC
источник
6
@Oscar, поскольку по git showсути выдает содержимое в stdout(стандартный вывод), вы можете просто перенаправить этот вывод в любой файл, который вы хотите ( tldp.org/LDP/abs/html/io-redirection.html ).
VonC
8
git checkout [branch | revision] filepathэто правильная команда
Гауи
12
@Gaui, но вместо git checkoutэтого ваш файл будет переопределен другой версией, git showчто позволит вам сохранить его под другим именем, чтобы вы могли видеть и видеть обе версии (текущую и старую). Из вопроса неясно, хочет ли ОП заменить свою текущую версию старой.
VonC
9
Я хотел бы отметить , что ^^^также можно записать в более общем плане, как ~~~или, лучше, ~3. Использование тильд также имеет то преимущество, что не вызывает сопоставления имен файлов некоторых оболочек (например, zsh).
Эрик О Лебигот
2
У меня нет достаточно старого git для проверки: git rev-parseобрабатывает ли pre-1.5.x rev:pathсинтаксис? (В более позднем git вы можете git cat-file -p $REV:path. Однако, он git showработает и для путей к каталогам, поэтому он не просто короче, он обычно ближе к тому, что нужно.)
torek
510

Если вы хотите заменить / перезаписать содержимое файла в вашей текущей ветке содержимым файла из предыдущего коммита или другой ветки, вы можете сделать это с помощью следующих команд:

git checkout 08618129e66127921fbfcbc205a06153c92622fe path/to/file.txt

или

git checkout mybranchname path/to/file.txt

Затем вам нужно будет зафиксировать эти изменения, чтобы они вступили в силу в текущей ветке.

Калифорния
источник
4
самое простое решение, и именно для этого предназначена git-checkout - указание пути означает, что извлекается только соответствующий файл. Со страницы
руководства
1
Затем, как вы вернетесь в предыдущее состояние, прежде чем запустить эту команду?
Флинт
@Flint, если вы выходите из состояния HEAD, это будет так же просто, как git checkout HEAD - [полный путь].
Тиаго Эспинья
72
Обратите внимание, что это перезаписывает существующий файл по этому пути, тогда как git show SHA1:PATHрешение печатает только в стандартный вывод.
Flimm
Ницца! Я не смог бы понять это, посмотрев на git help checkout. Мне нужно было извлечь подкаталог с определенной даты, и, используя этот подход, я мог заставить этот синтаксис работать:git checkout @{YYYY-MM-DD} sub-dir
haridsv
150

Вам необходимо указать полный путь к файлу:

git show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8:full/repo/path/to/my_file.txt
Милан Бабушков
источник
7
не должно быть полного пути. Путь из корневого каталога git (тем, кто зашел git show --name-only, тоже достаточно
Мохсен
7
Хм, полный путь от корня хранилища. Посмотрите лучше на пример, который я привел. Перед "полным" нет косой черты.
Милан Бабушков
7
К вашему сведению, если вы находитесь в подкаталоге, вы также можете успешно использовать ./filename.ext.
Путешественник
Я думаю, суть в том, что если вы попали full/repo/path/toи попытаетесь:, git show 27cf8e84:my_file.txtвы будете вознаграждены сообщением типа: fatal: путь 'full / repo / path / to / my_file.txt' существует, но не 'my_file.txt' , Вы имели в виду «27cf8e84: полный / репо / путь / к / my_file.txt» или «27cf8e84: ./ my_file.txt»? Похоже, Git мог бы помочь напрямую, но решил быть педантичным здесь.
Эд Рэндалл
101

Самый простой способ - написать:

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

где:

  • HASH - номер хэша Git-ревизии SHA-1
  • file / path / name.ext - это имя файла, который вы ищете
  • some_new_name.ext - путь и имя, в котором должен быть сохранен старый файл

пример

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

Это сохранит my_file.txt из ревизии 27cf8e как новый файл с именем my_file.txt.OLD

Он был протестирован с Git 2.4.5.

Если вы хотите восстановить удаленный файл, вы можете использоватьHASH~1 (один коммит перед указанным HASH).

ПРИМЕР:

git show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8~1:deleted_file.txt > deleted_file.txt
jmarceli
источник
1
Дополнительная информация: Вы можете получить HASH, например, с помощью git log
xotix
@xotix Спасибо. Я получил всю историю HASH для конкретного файла, используяgit log file/path/name.ext
Шрирам Каннан
11

В Windows с помощью Git Bash:

  • в вашей рабочей области измените dir на папку, в которой находится ваш файл
  • git show cab485c83b53d56846eb883babaaf4dff2f2cc46:./your_file.ext > old.ext
Алессандро Якопсон
источник
8

И, чтобы красиво сбросить его в файл (по крайней мере на Windows) - Git Bash:

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

Эти "кавычки необходимы , так что сохраняет переводы строк.

Mr_and_Mrs_D
источник
Хороший. +1. Хорошее дополнение по git showсинтаксису, о котором я упоминал выше.
VonC
23
Я действительно не понимаю, почему вы должны использовать эхо, с или без кавычек. И я не понимаю, почему вы хотите добавить форму перенаправления вывода. Не лучше ли было бы просто написать: git show 60d8bdfc: src / services / LocationMonitor.java> LM_60d8bdfc.java Если по какой-то причине вы на самом деле хотите форсировать конец строки в стиле dos, вы можете передать его через unix2dos. Но я никогда не находил ни малейшим полезным сохранять в DOS окончания строк в Windows, поскольку любые текстовые инструменты, кроме блокнота, которые я использовал в Windows, прекрасно справляются со строками в стиле Unix.
sootsnoot
4
git show 60d8bdfc: src / services / LocationMonitor.java >> LM_60d8bdfc.java работал для меня.
Mike6679
@ Майк: ты на окнах?
Mr_and_Mrs_D
2
не используйте двойные кавычки, потому что если в вашем файле символы, похожие на переменную оболочки, то есть $ LANG, он будет заменен. @ LưuVĩnhPhúc это заставка. также не используйте >> Он добавит файл, если он существует, и может привести к ошибкам
theguy
3

Это поможет вам получить все удаленные файлы между коммитами без указания пути, полезно, если удалено много файлов.

git diff --name-only --diff-filter=D $commit~1 $commit | xargs git checkout $commit~1
Адриан Гунаван
источник
1
git checkout {SHA1} -- filename

эта команда получает скопированный файл из определенного коммита.

jsina
источник
-2

Получить файл из предыдущего коммита путем извлечения предыдущего коммита и копирования файла.

  • Обратите внимание, на какой ветке вы находитесь: git branch
  • Оформить предыдущий коммит вы хотите: git checkout 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8
  • Скопируйте файл, который вы хотите во временную папку
  • Оформите ветку, с которой вы начали: git checkout theBranchYouNoted
  • Скопируйте файл, который вы поместили во временную папку
  • Зафиксируйте изменения в git: git commit -m "added file ?? from previous commit"
rocketInABog
источник