Як отримати один файл із певної версії в Git?


831

У мене є сховище Git, і я хотів би побачити, як виглядали деякі файли кілька місяців тому. Я знайшов перегляд у цю дату; це 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8. Мені потрібно подивитися, як виглядає один файл, а також зберегти його як ("новий") файл.

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

git-show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8 my_file.txt

Однак ця команда показує різний, а не вміст файлу. Я знаю, що згодом можу використовувати щось подібнеPAGER=cat та перенаправляти вихід у файл, але не знаю, як дістатися до фактичного вмісту файлу.

В основному я шукаю щось на кшталт svn cat .


73
Ключ тут: git show(безпомилково) використовує різні синтаксиси з двокрапкою. git show 2c7cf:my_file.txt
Стів Беннетт

4
Для подальшого уточнення, наведена вище команда просить git показати два окремі об'єкти, версію та файл. Нижче прийнята відповідь, що використовує двокрапку між двома елементами, просить певний файл під час певної редакції.
jhclark

2
На * nix вам не потрібен ПАГЕР, просто перенаправлення виводу оболонки на>
Костянтин Пелепелін


Checat має важливий коментар для тих, хто хоче, щоб вміст експортувався в якийсь файл. Вам потрібно щось подібне: git show {sha}: my_file.txt> old_my_file.txt
ormurin

Відповіді:


743

Щоб завершити власну відповідь, синтаксис справді є

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

Команда займає звичайний стиль редагування, тобто ви можете використовувати будь-яке з наступного:

  1. назва філії (як запропоновано по золі )
  2. HEAD+ x кількість ^символів
  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-файла, який справді повинен називатися git-cat-object, і просто скидається що об'єкт для stdout.


Примітка: оскільки Git 2.11 (Q4 2016), ви можете застосувати контент-фільтр до git cat-fileвиводу!

Див. Команду 3214594 , фіксує 7bcf341 (09 вересня 2016), фіксує 7bcf341 (09 вересня 2016) та виконує b9e62f6 , виконує 16dcc29 (24 серпня 2016) Йоганнеса Шинделіна ( dscho) .
(Об'єднав Хуніо С Хамано - gitster- у комітеті 7889ed2 , 21 вересня 2016 р.)

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

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

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

Примітка: "git cat-file --textconv " нещодавно почався сегментарний процес (2017), який було виправлено у Git 2.15 (Q4 2017)

Див. Комісію cc0ea7c (21 вересня 2017) Джеффа Кінга ( peff) .
(Об’єднав Хуніо С Хамано - 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)


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обробляє rev:pathсинтаксис pre-1.5.x ? (В останній 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 - вказівка ​​імені шляху означає, що перевіряється лише відповідний файл. З чоловікової сторінки git-checkout: master git checkout ~ 2 Makefile
RichVel

1
Потім, як повернутися до попереднього стану, перш ніж запустити цю команду?
Кремінь

@Flint, якщо ви приїжджаєте зі стану HEAD, це було б так само просто, як і Git checkout HEAD - [повний шлях].
Тіаго Еспінья

72
Зауважте, що це перезаписує існуючий файл на цьому шляху, тоді як git show SHA1:PATHрішення друкує лише для stdout.
Flimm

Приємно! Я б не зміг цього зрозуміти, дивлячись git help checkout. Мені довелося перевірити підкаталог на певну дату, і використовуючи цей підхід, я міг би git checkout @{YYYY-MM-DD} sub-dir
спрацювати

150

Вам потрібно надати повний шлях до файлу:

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

7
не повинно бути повним шляхом. Шлях від кореневого каталогу git (тих, хто зайшов git show --name-only, теж достатньо
Mohsen

7
Ерм, повний шлях від кореня сховища. Погляньте краще на приклад, який я наводив. Немає провідної косої риски перед "повною".
Мілан Бабушков

7
FYI, якщо ви перебуваєте в підкаталозі, ви також можете успішно використовувати ./filename.ext.
Мандрівник

Я думаю, що справа полягає в тому, що якщо ви знаходитесь, full/repo/path/toі ви намагаєтесь:, git show 27cf8e84:my_file.txtви отримаєте нагороду таким повідомленням, як: fatal: Шлях "full / repo / path / to / my_file.txt" існує, але не "my_file.txt" . Ви мали на увазі '27cf8e84: full / repo / path / to / my_file.txt' aka '27cf8e84: ./ my_file.txt'? Можливо, Гіт міг би допомогти прямо, але вирішив бути тут педантичним.
Ед Рендалл

101

Самий простий спосіб полягає в запису:

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

де:

  • HASH - хеш-номер GA revision 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

1
Додаткова інформація: Ви можете отримати HASH, наприклад, з журналом git
xotix

@xotix Дякую Я отримав всю історію HASH для конкретного файлу, використовуючиgit log file/path/name.ext
Sriram Kannan


8

І щоб красиво скинути його у файл (принаймні в Windows) - Git Bash:

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

Ці "лапки необхідні , так що зберігає переведення рядків.


Хороший. +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

@Mike: ти на Windows?
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

Ця команда отримує скопійований файл з конкретної фіксації.


-2

Отримайте файл з попереднього комітету через перевірку попереднього фіксації та копіювання файлу.

  • Зауважте, на якій гілці ви знаходитесь: гіт git
  • Оформити попереднє зобов’язання: git checkout 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8
  • Скопіюйте потрібний файл у тимчасове місце
  • Оформіть відділення, з якого ви почали: git checkout theBranchYouNoted
  • Скопіюйте у файл, який ви розмістили у тимчасовому місці
  • Введіть свої зміни в git: git commit -m "added file ?? from previous commit"
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.