Git возврат к нескольким коммитам в указанных c файлах - PullRequest
0 голосов
/ 16 января 2020

У меня есть несколько файлов, которые я уже опубликовал, но только потом я понял, что у меня есть файлы, в которых говорится, что они были изменены из-за дополнительного пространства или небольшого изменения. Я хочу вернуть эти файлы обратно к нескольким коммитам go, но только к указанным c файлам.

Я пробовал git revert <commithash>~4 -- path/to/filename1 path/to/filename2, где 4 - для 4 коммитов до текущего но, похоже, это не сработало: изменения, которые я надеялся увидеть go, не отразились go в моих файлах.

В настоящий момент коммиты есть только в моей ветке и не были слились с любыми другими. Я не хотел возвращать весь коммит, а только некоторые файлы из этого плохого коммита, из-за которого у меня проблемы.

Ответы [ 2 ]

1 голос
/ 16 января 2020

Я думаю, вам придется отменить коммит (ы) , где вы ошибочно выдавили неверные файлы (используя git reset), а затем выполнить новый коммит. Коммит похож на набор изменений проекта и должен рассматриваться как единица , поэтому изменения в одном файле не рассматриваются независимо от остальной части фиксации. (Редактировать: это поможет вам, только если ваши коммиты еще не были объединены.)

В любом случае, есть способ отменить только те специальные файлы, которые были добавлены в коммит. Ключевое слово здесь - Cherry Picking , которое "применяет изменения, которые вносит каждый [коммит], записывая новый коммит для каждого".

0 голосов
/ 16 января 2020

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 для другого вопроса - уже есть много ответов на эти вопросы.)

...