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. (Вы все равно должны сделать новый коммит, как обычно.)