Как получить один файл из определенной ревизии в Git
У меня есть Git-репозиторий, и я хотел бы посмотреть, как какой-то файл выглядел несколько месяцев назад. Я нашел ревизию в тот день, и это 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8
, Мне нужно посмотреть, как выглядел один файл, а также сохранить его в файл.
Мне удалось увидеть файл с помощью gitk
, но у него нет возможности сохранить его. Я попытался с инструментами командной строки, ближе всего я получил:
git-show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8 my_file.txt
Однако эта команда отображает diff, а не содержимое файла. Я знаю, что могу позже использовать что-то вроде PAGER=cat
и перенаправить вывод в файл, но я не знаю, как добраться до фактического содержимого файла.
По сути, я ищу что-то вроде svn cat.
12 ответов
Чтобы завершить свой собственный ответ, синтаксис действительно
git show object
git show $REV:$FILE
git show somebranch:from/the/root/myfile.txt
git show HEAD^^^:test/test.py
Команда принимает обычный стиль ревизии, что означает, что вы можете использовать любое из следующего:
- название ветви (как предложено ash)
HEAD
+ х число^
персонажи- Хэш SHA1 данной ревизии
- Первые несколько (возможно, 5) символов данного хэша SHA1
Совет Важно помнить, что при использовании git show
msgstr " всегда указывайте путь от корня хранилища, а не текущую позицию каталога.
(Хотя Mike Morearty упоминает, что, по крайней мере с git 1.7.5.4, вы можете указать относительный путь, поставив " ./
"в начале пути - например:
git show HEAD^^:./test.py
)
До 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
)
(Объединено Юнио С Хамано - gitster
- в коммите 7889ed2, 21 сентября 2016 г.)
cat-file
: служба поддержки--textconv
/--filters
в пакетном режимеДаже если "
git hash-objects
", который является инструментом, позволяющим взять поток данных внутри файловой системы и поместить его в хранилище объектов Git, позволил выполнять преобразования" из внешнего мира в Git"(например, преобразования в конце строки и применение чистого -filter), и с самого начала у него была функция, включенная по умолчанию.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
)
(Объединено Юнио С Хамано - gitster
- в коммите bfbc2fc, 28 сентября 2017 г.)
Если вы хотите заменить / перезаписать содержимое файла в текущей ветке содержимым файла из предыдущего коммита или другой ветки, вы можете сделать это с помощью следующих команд:
git checkout 08618129e66127921fbfcbc205a06153c92622fe path/to/file.txt
или же
git checkout mybranchname path/to/file.txt
Затем вам нужно будет зафиксировать эти изменения, чтобы они вступили в силу в текущей ветке.
Вам необходимо указать полный путь к файлу:
git show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8:full/repo/path/to/my_file.txt
Самый простой способ - написать:
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
git checkout {SHA1} -- filename
эта команда получает скопированный файл из определенного коммита.
В Windows с помощью Git Bash:
- в вашей рабочей области измените dir на папку, где находится ваш файл
git show cab485c83b53d56846eb883babaaf4dff2f2cc46:./your_file.ext > old.ext
В дополнение ко всем параметрам, перечисленным в других ответах, вы можете использовать
git reset
с объектом Git (хеш, ветка,
HEAD~x
, тег, ...) и путь к вашему файлу:
git reset <hash> /path/to/file
В вашем примере:
git reset 27cf8e8 my_file.txt
Это значит, что он вернется
my_file.txt
к своей версии при фиксации
27cf8e8
в индексе, оставив его нетронутым (как в текущей версии) в рабочем каталоге.
Оттуда все очень просто:
- вы можете сравнить две версии вашего файла с
git diff --cached my_file.txt
- вы можете избавиться от старой версии файла с помощью
git restore --staged file.txt
(или до Git v2.23,git reset file.txt
) если вы решите, что вам это не нравится - вы можете восстановить старую версию с помощью
git commit -m "Restore version of file.txt from 27cf8e8"
иgit restore file.txt
(или до Git v2.23,git checkout -- file.txt
) - вы можете добавлять обновления из старой в новую версию только для некоторых ханков, запустив
git add -p file.txt
(тогдаgit commit
иgit restore file.txt
).
Наконец, вы даже можете интерактивно выбрать, какие блоки нужно сбросить на самом первом шаге, если вы запустите:
git reset -p 27cf8e8 my_file.txt
Так
git reset
с путем дает вам большую гибкость для получения определенной версии файла для сравнения с его текущей извлеченной версией и, если вы решите сделать это, полностью или только для некоторых фрагментов вернуться к этой версии.
Изменить: я только что понял, что не отвечаю на ваш вопрос, поскольку то, что вам нужно, не было разницей или простым способом получить часть или всю старую версию, а просто
cat
та версия.
Конечно, вы все еще можете сделать это после сброса файла с помощью:
git show :file.txt
для вывода на стандартный вывод или
git show :file.txt > file_at_27cf8e8.txt
Но если это все, что ты хотел, беги
git show
непосредственно с
git show 27cf8e8:file.txt
как предлагали другие, конечно, гораздо более прямолинейно.
Я собираюсь оставить этот ответ, потому что
git show
напрямую позволяет вам мгновенно получить эту старую версию, но если вы хотите что-то с ней сделать, это будет не так удобно, как если бы вы сбросили эту версию в индексе.
И, чтобы красиво сбросить его в файл (по крайней мере на Windows) - Git Bash:
$ echo "`git show 60d8bdfc:src/services/LocationMonitor.java`" >> LM_60d8bdfc.java
"
кавычки необходимы, чтобы сохранить новые строки.
Это поможет вам получить все удаленные файлы между коммитами без указания пути, полезно, если удалено много файлов.
git diff --name-only --diff-filter=D $commit~1 $commit | xargs git checkout $commit~1
Использование, как уже было указано другими, вероятно, является правильным ответом. Я отправляю другой ответ, потому что, когда я пробовал этот метод, я иногда получал следующую ошибку от git:
fatal: path 'link/foo' exists on disk, but not in 'HEAD'
Проблема возникает, когда часть пути к файлу является символической ссылкой. В таких случаях метод не сработает. Действия по воспроизведению:
$ 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'
Проблема в том, что утилиты вроде
$ git show HEAD:link
test
В то время как с каталогами команда выводит заголовок, за которым следует содержимое каталога:
$ git show HEAD:test
tree HEAD:test
foo
Итак, в моем случае я просто проверил вывод первого вызова
Получить файл из предыдущего коммита путем извлечения предыдущего коммита и копирования файла.
- Обратите внимание, на какой ветке вы находитесь: git branch
- Оформить предыдущий коммит вы хотите:
git checkout 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8
- Скопируйте файл, который вы хотите во временную папку
- Оформите ветку, с которой вы начали:
git checkout theBranchYouNoted
- Скопируйте файл, который вы поместили во временную папку
- Зафиксируйте изменения в git:
git commit -m "added file ?? from previous commit"
Если вы предпочитаете использовать для этого графический интерфейс, следующее будет работать, если вы знаете, когда приблизительно файл был изменен.
В Visual Studio с установленным расширением Git:
- Git -> Просмотр истории веток
- Щелкните правой кнопкой мыши фиксацию, в которой был изменен файл, затем выберите «Просмотреть сведения о фиксации».
- В списке изменений справа нажмите на интересующий файл. Вы увидите параллельное сравнение всего содержимого файла до и после изменения. Просто выберите все, скопируйте содержимое файла и вставьте в любое место.