TL; DR
Вы, вероятно, (, вероятно, , это может усложниться), хотите определенный режим git checkout
или, в Git 2.23 или позже, git restore
, Вот. Вы можете извлечь определенные файлы из определенных коммитов таким образом, без фактического изменения коммитов. Детали становятся немного запутанными, хотя новый git restore
, вероятно, делает именно то, что вы хотите, прямо из коробки, как это было бы:
git restore <commit-hash> -- path/to/filename1 path/to/filename2
Long
Каждый коммит в Git репозиторий является (или содержит действительно) снимок всех ваших файлов.
Когда вы используете:
git checkout <commit-hash>
(или с тех пор Git 2.23, то же самое с git switch
), вы просите Git переключиться на данный коммит как отдельную ГОЛОВУ . Это считывает выбранный коммит в индекс - индекс, или промежуточную область, содержит ваш предложенный следующий коммит , поэтому переключение на коммит требует его заполнения из этого коммита - и в процессе корректирует содержимое вашего коммита. рабочее дерево для соответствия коммиту, к которому вы переключились.
Когда вы используете git checkout <em>branch-name</em>
(или снова git swtich
), Git делает то же самое, за исключением того, что теперь специальное имя HEAD
is присоединено к названию ветви. Git теперь запоминает, в какой ветке вы находитесь, и при создании нового коммита в этом имени ветки будет записан идентификатор ha sh нового коммита.
Ну, это все хорошо, но теперь вы хотите некоторый определенный файл из одного определенного коммита, без переключения коммитов вообще. Здесь Git 2.23 и более поздние версии лучше, потому что для этого есть отдельная команда git restore
. Мы вернемся к этому чуть позже, но сначала давайте поговорим подробнее о git checkout
.
Команда git checkout
нелепо сложна. Он имеет, в зависимости от того, как вы считаете, что-то около четырех-семи различных режимов работы. Здесь нас интересует тот, который извлекает определенных файлов из определенных коммитов . То есть нам нужно:
git checkout <commit-hash> -- <paths>
Здесь важно запомнить индекс Git, потому что этот вид git checkout
сначала записывает файлы в индекс . Аргумент paths
, который вы задаете после --
, определяет, какие файлы выходят из выбранного коммита. Сам --
существует только для того, чтобы убедиться, что эти имена файлов не похожи на флаги, имена ветвей или что-то еще. Часть commit-hash
может быть любой, приемлемой для git rev-parse
, при условии, что она именует объект commit или tree внутри; коммит ha sh хорош здесь.
Скопировав файлы, которые вы назвали, из коммита, который вы назвали, в индекс, этот git checkout
продолжит записывать файлы в ваше рабочее дерево. Обратите внимание, что в отличие от обычного, безопасного git checkout
, этот конкретный режим уничтожит текущее содержимое именованных файлов, даже если они не были сохранены где-либо еще. Так что если вы использовали git checkout
много и доволен тем, что он скажет вам: нет, я не могу этого сделать, я потеряю некоторые файлы, которые вы, возможно, забыли сохранить , просто помните, что эта форма git checkout
совершенно безжалостен.
В Git 2.23 и более поздних версиях есть отдельная команда git restore
, которая выполняет эту работу. Новая команда restore
может скопировать файл отдельно в индекс, в ваше рабочее дерево или в оба. По умолчанию это просто копирование в рабочее дерево, без влияния на индекс (а также без проверки, сохранил ли вы файл рабочего дерева где-либо, так что будьте осторожны с этим!). Итак:
git restore <commit-hash> -- path/to/filename1 path/to/filename2
скопирует эти файлы из этого коммита в ваше рабочее дерево. Обновленные файлы не будут подготовлены для фиксации, так как ваш индекс вообще не был изменен. (Как и прежде, --
- это случай, когда имя файла выглядит странно, как --staged
. Если это не так, вы можете опустить --
. Хотя это хорошая привычка.) Если все выглядит хорошо, вы можете git add
и git commit
как обычно.
(Если после этого вы хотите использовать интерактивный ребаз или программный сброс и фиксацию, чтобы убрать sh некоторых дополнительных промежуточных коммитов, это топика c для другого вопроса - уже есть много ответов на эти вопросы.)