Mercurial: как отменить последний разблокированный коммит?

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

Как мне отменить этот коммит и вернуть мою рабочую копию в состояние, в котором она была до коммита, чтобы я мог сделать то, что должен был сделать в первую очередь?

Я не толкнул или потянул или что-нибудь еще с момента совершения.


Вы можете подозревать, что это дубликат, поэтому я объясню, почему следующие вопросы отличаются, или не отвечу на мой вопрос:

Mercurial отменить последний коммит

Ответ на этот вопрос гласит, что вы можете сделать это с помощью hg commit --amend, но не объясняет, как и не приводит пример этого. Меркуриальная помощь не объясняет это и для меня.

Как вы "откатываете" последний коммит на Mercurial?

Штаты используют hg rollback. Эта команда явно устарела, я все равно пытался ее использовать, но получил сообщение: информация об откате недоступна. Жаль, что это не работает, поскольку это будет действительно интуитивно понятный способ достичь того, чего я хочу.

Ответ 1

Основываясь на информации из этого вопроса:

hg strip --keep --rev.
--keep: do not modify working directory during strip
--rev. (точка обозначает последний коммит. прочитайте sid0 ответ относительно потомков)


Для людей, более знакомых с языком git, вы ищете git reset --mixed HEAD^

hard что бы отменить ваши изменения, заставив вашу работу "исчезнуть" (я полагаю, что это не вариант)

soft отменяет фиксацию, но сохраняет индексируемые ранее зафиксированные файлы (то есть отслеженные)

mixed сохраняет измененные файлы на месте, но указывает индексу отменить фиксацию. в git-говорить: git st сказал бы, что Changes not staged for commit


См. Также git-reset docs, Разница git reset soft/mixed, git/hg Таблица эквивалентности команд

Ответ 2

Хорошо, я думаю, что нашел ответ, чтобы включить расширение strip и использовать следующую команду:

hg strip -r -1 --keep

Это удаляет последнюю ревизию из repostory (бит -r -1), а параметр --keep означает, что в рабочую копию не вносятся изменения. Таким образом, вы получаете рабочую копию точно так же, как и до фиксации, и никакой последней фиксации в репозитории.

Я не эксперт по ртути, поэтому используйте на свой страх и риск.

Ответ 3

То, что я сделаю в этой ситуации, это создать новую ветвь, которая имеет изменения, которые я хочу, прежде чем я когда-нибудь подумал об удалении плохого набора изменений. Поэтому в этом случае мне нужно будет вернуться к ревизии, прежде чем я совершу плохое коммит, повторно сделаю свои изменения, а затем сделаю несколько коммитов, по одному для каждого файла.

Шаг за шагом:

1) Вернитесь до неудачной фиксации.

% cd <top of repo>
% hg log -l 5
<identify the last good revision>
% hg update -r <last good revision number>

2) Внести изменения: я бы получил патч, который описывает изменения, которые я хочу, и применил их к дереву. (Я предполагаю, что подсказка в настоящее время указывает на то, с чего мы начали)

% hg diff -r .:tip | patch -p1
patching file a/b/c/d
patching file a/b/e/f

3) Сделайте новые коммиты: мы вернулись в состояние, прежде чем вы совершили коммит, который хотите разбить. Сделайте hg status и посмотрите на измененные файлы, убедитесь, что все так, как вы ожидаете. На этом этапе вы можете либо зафиксировать файлы по одному, назвав их в командной строке, либо использовать расширение, например record или crecord, чтобы их интерактивно выбрать.

% hg commit a/b/c/d
% hg commit a/b/e/f

... или...

% hg crecord
<select files in UI>
% hg crecord
<select files in UI>

Вы получите репо, которое выглядит так:

o----o----B
      \
       \
        --o----o----o----T

Где B - старое плохое коммит, а T - новый кончик репо. Если вы хотите сделать эту ветвь закрытой, поэтому она не отображается в журналах /etc, вы можете...

% hg update -r <revision B>
% hg commit --close_branch
% hg update -r tip

Если вы хотите полностью удалить его, вы можете удалить его.

% hg strip -r <revision B>

В любом случае ваш журнал будет выглядеть так, как будто ничего не произошло.

Ответ 4

комментировать и уточнять пост @crobar, потому что количество символов недостаточно.

когда вы выполняете локальный коммит (без push), затем запускаете hg strip -r -1 --keep, он удаляет ваш предыдущий коммит и сохраняет ваш список файлов, ожидающих фиксации. в основном это полная отмена.

если я использую hg strip -r -1 без --keep, он все равно удаляет ваш предыдущий коммит, НО, когда я пытаюсь перечислить файлы, которые будут зафиксированы, он не может найти изменения, поэтому я бы не рекомендовал делать это.

если я делаю фиксацию, затем делаю push (в удаленный режим), затем делаю hg strip -r -1 --keep, он делает именно то, что должен делать, НО, когда вы делаете другой коммит, а затем push, он создает другую ветвь.

I.E. 

o----o----Branch (local)
      \
       \
        --o----o----o----Branch (with previous push)

мой источник/ссылка: тестирование этих сценариев