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

211

Я ищу git commit --amendаналог Mercurial, то есть способ изменить коммит, с которым связана моя рабочая копия. Меня интересует только последний коммит, а не произвольный ранний коммит.

Требования к этой процедуре внесения поправок:

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

  • если обязательство изменить - один из моих нынешних филиалов, новый руководитель создавать не следует. Если коммит не является головой, может быть создан новый руководитель.

  • процедура должна быть безопасной, так что если по каким-либо причинам изменение не удастся, я хочу восстановить ту же рабочую копию и состояние хранилища, что и до внесения изменений. Другими словами, если само изменение может потерпеть неудачу, должна существовать отказоустойчивая процедура для восстановления рабочей копии и состояния хранилища. Я имею в виду «сбои», которые лежат в природе процедуры внесения изменений (например, конфликты), а не проблемы, связанные с файловой системой (например, ограничения доступа, невозможность заблокировать файл для записи, ... )

Обновление (1):

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

Обновление (2):

  • файлы в рабочем каталоге не должны быть затронуты (могут быть блокировки файловой системы на некоторых измененных файлах). Это особенно означает, что возможный подход ни в коем случае не может потребовать чистого рабочего каталога.
mstrap
источник

Ответы:

289

В выпуске Mercurial 2.2 вы можете использовать --amendопцию hg commitдля обновления последнего коммита текущим рабочим каталогом.

Из справки командной строки :

Флаг --amend может использоваться для изменения родительского элемента рабочего каталога новым коммитом, который содержит изменения в родительском элементе в дополнение к тем, о которых в настоящее время сообщается в hg status, если они есть. Старый коммит хранится в резервном пакете в .hg / strip-backup (см. Hg help bundle и hg help unbundle о том, как его восстановить).

Сообщение, пользователь и дата взяты из исправленного коммита, если не указано иное. Если сообщение не указано в командной строке, редактор откроется с сообщением исправленного коммита.

Самое замечательное в том, что этот механизм является «безопасным», поскольку он опирается на относительно новую функцию «Фазы» для предотвращения обновлений, которые могли бы изменить историю, которая уже стала доступной за пределами локального репозитория.

Крис Филлипс
источник
2
Хороший ответ! Экспериментальное расширение evolve позволяет безопасно вносить изменения, не связанные с головой . Старый коммит будет помечен как устаревший и скрытый. С сервером без публикации вы можете даже сделать это безопасно после того, как вы отправили наборы изменений.
Мартин Гейслер,
5
Чтобы просто обновить сообщение о последнем коммите: hg commit --amend -m "это мое новое сообщение"
Jay Sheth
52

У вас есть 3 варианта редактирования коммитов в Mercurial:

  1. hg strip --keep --rev -1отмените последний (1) коммит (ы), так что вы можете сделать это снова (см. этот ответ для получения дополнительной информации).

  2. Использование расширения MQ , которое поставляется с Mercurial

  3. Даже если он не поставляется с Mercurial, расширение Histedit стоит упомянуть

Вы также можете посмотреть страницу истории редактирования вики Mercurial.

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

Я не очень знаком с git commit --amendкомандой, но AFAIK, Histedit - то, что кажется самым близким подходом, но, к сожалению, оно не поставляется с Mercurial. MQ действительно сложен в использовании, но вы можете делать с ним почти все.

Krtek
источник
1
Я не уверен, почему я пропустил откат, но он, кажется, делает (почти) то, что я хочу. Единственная проблема заключается в том, что когда файл был удален для моего исходного коммита и он был воскрешен для моего исправленного коммита: до отката он будет неверсированным, после отката он будет запланирован для удаления (но файл все еще существует в рабочий каталог)
mstrap 18.11.11
@Marc Я не уверен, что понимаю твою проблему, но взгляни на команду забудьте, думаю, это то, что ты ищешь.
кртек
Я не думаю, что "забыть" будет полезно здесь. Вот проблема более подробно: (1) Я в редакции 2 (2) Удалите «файл» и внесите некоторые другие изменения (3) Зафиксируйте изменения, приведшие к редакции 3 (4) Теперь я передумаю и решу «file» не должен быть удален из коммита, поэтому я хочу изменить редакцию 3. Следовательно, я повторно добавлю «file», который теперь не версионный (5) Теперь я выполняю откат: он сбросит dirstate и пометит » файл "как удалено. (6) При повторном выполнении hg commit «file» останется удаленным, хотя больше этого не должно быть. Как может выглядеть автоматическое исправление?
Mstrap
1
Для автоматизированной части я не знаю, но вы можете сделать, hg revert myfileчтобы отменить удаление. Возможно повторное добавление с hg addфайлом после того, как rollbackработает.
Кртек
3
Я согласен с тем, что следует избегать редактирования истории опубликованных изменений, но редактирование моей локальной истории является одним из основных моментов DVCS. MQ с его qimport - это просто редактирование истории, AFAICT.
Mstrap
38

GUI эквивалент для hg commit --amend:

Это также работает из графического интерфейса TortoiseHG (я использую v2.5):

Перейдите к представлению «Зафиксировать» или в представлении рабочей среды выберите запись «Рабочий каталог». Кнопка «Подтвердить» имеет параметр «Изменить текущую редакцию» (нажмите на стрелку раскрывающегося списка кнопки, чтобы найти ее).

введите описание изображения здесь

          ||
          ||
          \/

введите описание изображения здесь

Будьте бдительны :

Эта дополнительная опция будет включена, только если версия mercurial имеет версию не ниже 2.2.0, а текущая версия не является публичной, не является патчем и не имеет дочерних элементов. [...]

Нажатие на кнопку вызовет 'commit --amend', чтобы «изменить» ревизию.

Подробнее об этом на канале разработчиков THG

Кристиан Дьяконеску
источник
Очень полезно, спасибо. THG достаточно умен, чтобы использовать сообщение по умолчанию (изменить) в сообщении от предыдущего коммита - именно то, что я хотел.
UuDdLrLrSs
7

Я настраиваюсь на то, что написал krtek. Более конкретно решение 1:

Предположения:

  • Вы совершили одну (!) ревизию, но еще не добавили ее
  • Вы хотите изменить этот набор изменений (например, добавить, удалить или изменить файлы и / или сообщение о коммите)

Решение:

  • использовать hg rollbackдля отмены последнего коммита
  • совершить снова с новыми изменениями на месте

Откат действительно отменяет последнюю операцию. Его способ работы довольно прост: обычные операции в HG будут добавлять только файлы; это включает в себя фиксацию. Mercurial отслеживает длины файлов последней транзакции и поэтому может полностью отменить один шаг, урезав файлы до их старых длин.

Лусеро
источник
1
Спасибо за настройку решения (1); осталась только небольшая проблема с откатом, пожалуйста, смотрите мой комментарий в решении krtek.
Mstrap
8
Одна вещь, на которую нужно обратить внимание при откате, потому что он привлекает внимание, заключается в том, что откатывается последняя транзакция в репо, а не последняя фиксация. Так что, если что-то еще вызвало запись в репо, откат не поможет. Это тонкая, но важная вещь для запоминания. MQ и histedit могут помочь после закрытия окна отката, но только до определенного момента.
Пол С
7

Предполагая, что вы еще не распространили свои изменения, вот что вы можете сделать.

  • Добавьте к вашему .hgrc:

    [extensions]
    mq =
    
  • В вашем хранилище:

    hg qimport -r0:tip
    hg qpop -a
    

    Конечно, вам не нужно начинать с нулевой ревизии или извлекать все патчи, поскольку достаточно только одного pop ( hg qpop) (см. Ниже).

  • удалите последнюю запись в .hg/patches/seriesфайле или патчи, которые вам не нравятся. Переупорядочение тоже возможно.

  • hg qpush -a; hg qfinish -a
  • удалите .diffфайлы (не примененные исправления), все еще в .hg / patches (должен быть один в вашем случае).

Если вы не хотите , чтобы забрать все из вашего патча, вы можете редактировать его с помощью hg qimport -r0:tip(или аналогичный), а затем редактировать материал и использовать hg qrefreshдля слияния изменений в верхний патч на свой стек. Читать hg help qrefresh.

Редактируя .hg/patches/series, вы можете даже удалить несколько патчей или изменить их порядок. Если ваша последняя ревизия 99, вы можете просто использовать hg qimport -r98:tip; hg qpop; [edit series file]; hg qpush -a; hg qfinish -a.

Конечно, эта процедура крайне не рекомендуется и рискованно . Сделайте резервную копию всего, прежде чем сделать это!

Как примечание, я делал это миллионы раз на частных репозиториях.

hochl
источник
Я также рассмотрел использование mq-extension, однако для этого требуется довольно много операций, для некоторых из которых может произойти сбой (например, если задействованы двоичные файлы). Кроме того, необходимость редактирования .hg / patch / series будет неприемлемой, поскольку эту процедуру следует использовать в клиенте с графическим интерфейсом (я обновил требования выше)
mstrap
Хммм, извините, что это не для вас, в частном репозитории это действительно пинает задницу (с резервными копиями - я уже толстый палец уничтожил репутацию с этим ^^). Это довольно прохладно , чтобы объединить исправления в одно до нажатия на локальные изменения , используя hg qfold, кстати
hochl
+1 за использование MQ, но я думаю, что вы перешли за борт. Он только просит изменить последний коммит. Кроме того, этот импорт прекратится, как только произойдет слияние. 'qimport -r tip; <править материал>; qrefresh -e; qfin -a 'выполнит эту работу (-e, чтобы отредактировать сообщение коммита)
Paul S
правда, слияния являются проблемой, я обычно высовываю только один патч и использую hg import -r<prev>:tip. Жаль, что нет ярлыка для предыдущей версии, как в Subversion.
hochl
2

Последние версии Mercurial включают evolveрасширение, которое предоставляет hg amendкоманду. Это позволяет вносить изменения в коммит, не теряя предыдоговую историю в вашем контроле версий.

hg изменить [ВАРИАНТ] ... [ФАЙЛ] ...

псевдонимы: обновить

объединить ревизию с обновлениями и заменить ее новой

Commits a new changeset incorporating both the changes to the given files
and all the changes from the current parent changeset into the repository.

See 'hg commit' for details about committing changes.

If you don't specify -m, the parent's message will be reused.

Behind the scenes, Mercurial first commits the update as a regular child
of the current parent. Then it creates a new commit on the parent's
parents with the updated contents. Then it changes the working copy parent
to this new combined changeset. Finally, the old changeset and its update
are hidden from 'hg log' (unless you use --hidden with log).

См. Https://www.mercurial-scm.org/doc/evolution/user-guide.html#example-3-amend-a-changeset-with-evolve для полного описания evolveрасширения.

Карл Бартел
источник
Повторное использование одного и того же сообщения о фиксации - хорошая функция!
mpen
1

Может не решить всех проблем в первоначальном вопросе, но, поскольку это, похоже, фактический пост о том, как mercurial может изменить предыдущую фиксацию, я добавлю информацию на 2 цента.

Если вы похожи на меня и хотите изменить только предыдущее сообщение о фиксации (исправить опечатку и т. Д.) Без добавления каких-либо файлов, это будет работать

hg commit -X 'glob:**' --amend

Без шаблонов включения или исключения hg commitпо умолчанию будут включены все файлы в рабочем каталоге. Применение шаблона -X 'glob:**'исключит все возможные файлы, позволяя только изменять сообщение коммита.

Функционально это то же самое, git commit --amendкогда нет файлов в индексе / сцене.

kaskelotti
источник
0

Другим решением может быть использование uncommitкоманды для исключения конкретного файла из текущего коммита.

hg uncommit [file/directory]

Это очень полезно, если вы хотите сохранить текущий коммит и отменить выбор некоторых файлов из коммита (особенно полезно, если files/directoriesони были удалены).

Сэм Ляо
источник