Отмена изменений без удаления из истории

180

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

Я обновился с более ранней ревизии и зафиксировал, создав тем самым новую голову.


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

Кажется, я не могу найти, как это сделать, и начинаю верить, что это невозможно. Все, что я нахожу, это что-то о ветвях или о слиянии.

о0' .
источник
1
Он находится в вашем репо, поэтому он не был удален из истории. Вы создали новую голову, так что вы можете продолжать вносить изменения без ошибок. Что мешает вам продолжать новую голову?
Атайлор
Что с твоим отвращением к веткам?
Андрес Яан Так
@Andres Это не совсем отвращение к веткам. Мне просто нужно, чтобы это работало без глупого дополнительного шага создания, просто чтобы закрыть его.
о0 '.
Любой, кто читает - обратите внимание, что в этом сценарии уже была создана ветка; обратите внимание на объяснение, приведенное в этом ответе: stackoverflow.com/a/3692607/3195477
UuDdLrLrSs

Ответы:

181

Обновите свой репозиторий до заголовка с ревизией, о которой вы хотите забыть, затем используйте, hg commit --close-branchчтобы пометить эту (анонимную) ветвь как закрытую. Затем обновиться до руководителя филиала , что вы действительно хотите, и продолжать работать.

Вы по-прежнему можете видеть закрытую ветвь, если используете -cопцию to hg heads, но она не будет отображаться по умолчанию и не hg mergeбудет пытаться объединиться с закрытой головкой.

Вам нужно будет использовать hg push --forceпервый раз, когда вы перемещаете эту закрытую головку в другой репозиторий, так как вы фактически создаете дополнительные головки в удаленном репозитории при нажатии. Так что скажите Mercurial, что это нормально --force. Людей, которые тянут закрытую голову, не будут беспокоить никакие предупреждения.

Найл С.
источник
3
@ Найл С. Разве это не сработает, только если он пометит это как именованную ветку? Я предполагаю из того, что он сказал, что он сделал, что это по умолчанию
msarchet
но ... это не правда, я все равно получаю в списке обе головы при вызове hg heads... Я использую Mercurial 1.4.3, это более новая функция?
о0 '.
2
@msarchet: AFAIK, пробуя сегодня, --close-branch НЕ работает для анонимных веток. Должен, но не делает. Я надеюсь, что это изменится в некоторых будущих версиях Mercurial. Анонимные ветви очень хороши, но должны быть первоклассными, как именованные ветви.
Крейзи Глеу
4
@KrazyGlew: Проблема в том, что «анонимная» ветвь - это просто вторая ветвь с тем же именем, что и ветка, на которой она была основана. Вы на самом деле не пытаетесь закрыть (именованную) ветку: вы пытаетесь отменить изменения, которые вы сделали. Другими словами, hg branchesвсе равно должно отображаться название ветки, в которой вы находитесь. Вместо того, чтобы пытаться закрыть ветку, объедините вашу анонимную ветку с исходной веткой, отбросив все изменения.
StriplingWarrior
2
В моем случае у меня есть ветвь с именем default (это стандартная), а другая - с именем default / master (я думаю, из-за того, что удаленная депо на самом деле git). hg update default / master; hg commit --close-branch; hg update default работал у меня.
MattD
68

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


Нет проблем с тем, чтобы вести себя так же, как вы, и не беспокоиться о наличии нескольких головок, но если вы хотите привести в порядок вещи, чтобы случайно не выбрать неправильную головку, вы можете убить старую ветку.

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

Я думаю, что лучший вариант для вас - пометить старую ветку как "закрытую". Если ваша старая голова - ревизия "123", тогда:

hg update -r 123
hg commit --close-branch -m 'Closing old branch'
hg update -C default
Ник Пирпойнт
источник
3
Blurgh - только что увидел ответ @ Найла после того, как я вошел. Буду поднимать голос Найла, а мой может томиться в пуле нулевых очков. :)
Ник Пирпойнт
1
Мне больше нравится ваш ответ, он требует меньше терминологии merucrial (который, насколько я могу судить, выбран для того, чтобы сбить с толку пользователей git)
tacaswell
8
лол, это наоборот! Терминология Mercurial была выбрана так, чтобы она звучала естественно для пользователей SVN, в то время как у Git она чертовски запутанная! Во всяком случае, голосование против этого ответа, потому что он включает в себя последнее обновление -C
Тобия
2
Зачем вам -Cв hg update? Казалось бы, ни один файл не был бы изменен, поэтому он должен работать без него.
максимум
1
насколько я могу судить, вам нигде не нужен -C. однако, если у вас есть выдающиеся изменения при попытке обновления, вы получите прерывание.
Эли Альберт
21

Прежде всего, введите:

hg heads

Представьте, у вас есть три головы в списке:

changeset:   223:d1c3deae6297
user:        Your name  <your@email.com>
date:        Mon Jun 09 02:24:23 2014 +0200
summary:     commit description #3

changeset:   123:91c5402959z3
user:        Your name <your@email.com>
date:        Sat Dec 23 16:05:38 2013 +0200
summary:     commit description #2

changeset:   59:81b9804156a8
user:        Your name <your@email.com>
date:        Sat Sep 14 13:14:40 2013 +0200
summary:     commit description #1

Допустим, вы хотите сохранить активную последнюю голову (223) и закрыть остальные.

Затем вы должны сделать следующее:

Закрыть голову № 59

hg up -r 59
hg ci --close-branch -m "clean up heads; approach abandoned"

Закрыть голову # 123

hg up -r 123
hg ci --close-branch -m "clean up heads; approach abandoned"

Зафиксируйте изменения

hg push

Не забудьте переключиться на правую голову в конце

hg up -r 223

И вы сделали.

Артур Барсегян
источник
Это хороший учебник, но примеры сообщений коммита немного мета. Я бы включил лучшие примеры, чтобы те, кто учится у вас, могли лучше передавать сообщения. Нечто подобное --close-branch -m "Closing branch - technique #2 abandoned in favor of technique #3".
Джейсон Р. Кумбс
5
Кроме того, вы в конце все сделали, за исключением того, что ваша рабочая копия все еще находится на голове, которую вы только что закрыли. Передача другого изменения произойдет на закрытой голове, открывая ее снова. Вы захотите, hg up -r 223прежде чем вносить какие-либо изменения.
Джейсон Р. Кумбс
@ Джейсон Р. Кумбс: Точно!
Артур Барсегян
Согласно @Niall, и моему собственному опыту сейчас, вам нужно будет hg push --forceне просто hg pushпройти мимо предупреждения о толкании нескольких голов.
Craq
1
@ Артур Я согласен в целом. В этом случае hg pushсамо по себе не работает для меня. Как вы рекомендуете вносить изменения во внешний репо, если он отказывается из-за нескольких голов?
Craq
12

Вы хотите использовать hg backout. Это удаляет изменения, сделанные набором изменений, из любого дочернего набора изменений.

Проверьте это для хорошего объяснения. Mercurial Backout

msarchet
источник
2
Это точно правильный ответ. Backout добавляет обратный набор изменений, отменяя работу и давая вам сообщение о коммите, чтобы напомнить себе, почему вам не понравилась идея.
Ry4an Brase
7
Я на самом деле не согласен - отказ от работы над одной головой и начало с хорошей отправной точки кажется более чистой схемой работы, чем использование отступлений. Тем более, что вы не можете отказаться от более чем одной ревизии за раз.
Мартин Гейслер
1
@Martin Geisler, в общем, я согласен с этим, но ОП заявил, что хочет отказаться от изменений без веток
msarchet
2
@Martin Geisler, да, я все за ветвление, просто иногда нюкируя плохие изменения - лучшее
msarchet
1
иногда это может быть полезно, но это не совсем то, что я хотел. В любом случае, спасибо :)
o0 '.
2

Ответы Найла и Ника прямо. Поскольку я обнаружил, что создаю множество свисающих голов, я написал псевдоним, чтобы легче закрывать головы. Добавив это к вашему .hgrc:

[alias]
behead = !REV=$($HG id -i); $HG update $@ -q && $HG ci --close-branch -m "Closing dead head" && $HG update $REV -q

(если у вас уже есть [alias]раздел, вы можете добавить к нему вместо)

Теперь вы можете закрыть заголовок одной командой (без необходимости вручную обновлять другой набор изменений) следующим образом:

$ hg behead 123

Примечание: псевдоним использует тот факт, что псевдонимы Mercurial могут быть командами оболочки . Это означает, что это, вероятно, будет работать только в UNIX, а не в Windows.

jjst
источник
2

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

Допустим, история изменений выглядит так:

1-2-3-4-5-6    
       \    
        7-8-*

и это, 5и 6которые больше не нужны.

Ты можешь сделать это:

hg up 8
hg merge -r 6 -t :local
hg commit ...

который создаст это:

1-2-3-4-5-6    
       \   \
        7-8-9-*

Обновление 8гарантирует, что вы работаете над желаемой головой в истории, которую вы хотите сохранить.

В -t :localинструктирует ¯hG использовать Объединить «инструмент» под названием местный , который говорит ему , чтобы игнорировать изменения из другой ветви, т.е. не представленного текущего состояния рабочей папки. Более подробная информация .

Таким образом, нежелательные изменения 5и 6сохраняются в истории, но не влияют ни на что более недавнее.

UuDdLrLrSs
источник
2

Это пример использования расширения Evolve . В настоящее время он не входит в комплект Mercurial, поэтому технически это расширение стороннего производителя. Но он довольно активно используется группой людей, включая разработчиков Mercurial, очень активно разрабатывается и никуда не денется.

С расширением Evolve вы просто делаете

hg prune -r revname

и продолжить свою жизнь. Cset все еще будет там, но устарел. Он не будет виден, если вы не передадите эту --hiddenопцию командам Mercurial, и по умолчанию не будет передан в удаленные репозитории. Хотя я думаю, что вы можете заставить это, если вы действительно хотите.

Если cset, который вы обрезаете, имеет предков, которых вы хотите сохранить, то вам придется запустить, hg evolveчтобы перебазировать эти наборы изменений. hg evolveсделает это автоматически. В противном случае вам не нужно ничего делать.

Фахим Митха
источник
1

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

hg clone --rev myGoodResition myDirtyRepo myCleanRepo
kjam
источник
1
Это совершенно не то, что я спросил, извините.
о0 '.
4
@Kristof: это шутка? Перечитайте первую строчку моего поста: «откажитесь от него, не удаляя его из истории »
o0 '.
-1

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

На вашей локальной копии, получите последнюю версию и затем:

  1. Найдите начало головы, которую вы хотите раздеть (где новая ветвь начинает разветвляться), получите номер ревизии

  2. Сними это.


Источник: TipsAndTricks .

Источник: PruningDeadBranches # Using_strip .

hg --config extensions.hgext.mq= strip -n <rev>
  1. Сделайте тривиальное обновление файла (добавьте пробел в файл), подтвердите и нажмите.

У вашего репо теперь должна быть снята голова. Последний шаг важен, поскольку удаление не создает никаких изменений, которые вы можете перенести в ваш центральный репозиторий. Без последнего шага вы только обнажили голову локально.

sonjz
источник
1
Но нажатие никогда не удаляет ничего из удаленного хранилища. Это только добавляет информацию. Если набор изменений уже находится в центральном репозитории, вам нужно либо использовать расширение evolve, либо каким-либо образом удалить его на самом центральном сервере. Если набор изменений еще не находится в центральном репозитории, то его локального удаления будет достаточно без какого-либо принудительного нажатия.
Бен