git revert back to certain commit без изменения истории и создания нового коммита, такого как git revert
Есть ли способ вернуться к определенному коммиту без изменения удаленной истории, в основном отменяя все изменения от этого коммита в новом коммите, как git revert?
Для eg - у меня есть 3 коммита фиксация A - > B - > C, моя голова в данный момент находится на C Теперь я хочу создать еще один коммит D, который будет иметь тот же код, что и A, чтобы я мог отправить этот коммит в удаленную ветвь без изменения истории.
1 ответ:
Будьте осторожны со словом "вернуться"
Когда люди говорят "Я хочу вернуться" в Git, они иногда имеют в виду то, что делаетgit revert
, что больше похоже на операцию back out, а иногда имеют в виду то, что вы делаете, то есть восстанавливаете исходную базу из более ранней версии . Для иллюстрации предположим, что у нас есть коммит, который имеет только один файл,README
, и три коммита:A <-B <-C <-- master (HEAD)
Версия
README
в редакции А говорит: "Я-файл README", и это всего одна строка длинный.Версия
README
в редакции B говорит: "Я-файл README."как и раньше, но есть вторая строка, добавленная:" этот файл длиной в пять строк."Версия
README
в редакции C исправлена тем, что во второй строке написано: "Этот файл имеет длину в две строки."Git'S
git revert
может отменить изменение, так что прямо сейчас запускgit revert <hash-of-B>
попытается удалить добавленную строку. Это не сработает, так как линия больше не совпадает (и мы можем запуститьgit revert --abort
, чтобы сдаваться). Аналогично, запускgit revert <hash-of-C>
попытаетсяотменить исправление . Это будет успешным, эффективно возвращая к пересмотруB
!Этот вопрос, отменить конкретный коммит в Git, который был отправлен в удаленные РЕПО, Все о резервном виде возврата. Хотя это иногда приводит к возврату-к виду возврата, это не одно и то же. То, что вы хотите, согласно вашему вопросу, больше: "сделайте мне новый коммит
D
, который имеет тот же исходный код , что и commitA
". Вы хотите вернуться к версииA
.Git не имеет пользовательской команды для возврата к , но это легко
Этот вопрос, Как вернуть репозиторий Git к предыдущему коммиту?, полон ответов, говорящих об использовании
git reset --hard
, который делает свою работу-но делает это, отсекая историю. Однако принятый ответ включает в себя один из ключей, а именно: это:git checkout 0d1d7fc32 .
Эта команда говорит Git извлечь из данного коммита
0d1d7fc32
, все файлы , которые находятся в этом снимке и в текущем каталоге (.
). Если ваш текущий каталог находится в верхней части рабочего дерева, то он будет извлекать файлы из всех каталогов, так как.
рекурсивно включает файлы вложенных каталогов.Единственная проблема с этим заключается в том, что да, он извлекает все файлы, но не удаляет (из индекса и work-tree) любые файлы, которые у вас есть и которые вам не нужны. Чтобы проиллюстрировать это, давайте вернемся к нашему репозиторию с тремя коммитами и добавим четвертый коммит:
$ echo new file > newfile $ git add newfile $ git commit -m 'add new file'
Теперь у нас есть четыре коммита:
A <-B <-C <-D <-- master (HEAD)
Где commit
D
имеет правильную двухстрочнуюREADME
, и новый файлnewfile
.Если мы это сделаем:
$ git checkout <hash-of-A> -- .
Мы перепишем версию индекса и рабочего дерева
README
с версией из commitA
. Мы вернемся к однострочномуREADME
. Но мы все равно будем иметь, в нашем индексе и рабочем дереве файлnewfile
.Чтобы исправить это, вместо того, чтобы просто извлекать все файлы из фиксации, мы должны начать с удаления всех файлов, которые находятся в индексе:
$ git rm -r -- .
Тогда можно безопасно повторно заполнить индекс и дерево работы из commit
A
:$ git checkout <hash> -- .
(я пытаюсь использовать
После того, как вы выполнили эти два шага, это безопасно для--
здесь автоматически, в случае, если имя пути, которое я хочу, похоже на имя опции или ветви или что-то подобное; это делает эту работу, даже если я просто хочу проверить файл или каталог с именем-f
, например).git commit
результата.Минор: короткий путь
Поскольку Git фактически просто делает коммиты из индекса, все, что вам нужно сделать, это скопировать нужный коммит в индекс. Команда
git read-tree
делает это. Вы можете одновременно обновить дерево работ, так что:$ git read-tree -u <hash>
Достаточно вместо remove-and-checkout. (Вы все равно должны сделать новый коммит, как обычно.)