git revert back to certain commit без изменения истории и создания нового коммита, такого как git revert


Есть ли способ вернуться к определенному коммиту без изменения удаленной истории, в основном отменяя все изменения от этого коммита в новом коммите, как git revert?

Для eg - у меня есть 3 коммита фиксация A - > B - > C, моя голова в данный момент находится на C Теперь я хочу создать еще один коммит D, который будет иметь тот же код, что и A, чтобы я мог отправить этот коммит в удаленную ветвь без изменения истории.

1 3

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