Mercurial возвращается назад, затем повторно применяет наборы изменений

#mercurial

#mercurial

Вопрос:

У меня есть коммиты A, B, C, D и E. Я понимаю, что при фиксации B произошло что-то очень плохое, поэтому я хочу вернуться к A, на этот раз правильно внести изменения, которые ранее испортили B, а затем автоматически повторно применить C, D и E.

Вам может быть интересно, почему я не возвращаюсь обратно к B и не исправляю там, а затем не возвращаюсь обратно к E (это когда-нибудь хорошая идея?). Причина мне не совсем понятна, но она как-то связана с проблемой, возникающей в наборе специальных файлов visual Studio (которые следует редактировать только с помощью некоторых экранов графического интерфейса в visual Studio), которые плохо сочетаются с простым исправлением файла после возникновения ошибки… Я бы дал больше деталей, если бы знал их

Комментарии:

1. Если изменение незначительно, я бы, вероятно, просто отменил его вручную и установил новую версию F. Если это большое изменение, вы меня поняли. Я сам только начал использовать mercurial, поэтому мне тоже будет интересен ответ!

Ответ №1:

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

Если B — это служебный выпуск, внесите изменения там и впоследствии объедините их с F.

Ответ №2:

Это можно сделать с помощью очередей Mercurial (mq). Вы хотите:

  1. Импортируйте наборы изменений с B по E в mq
  2. Отменяет применение наборов изменений С по E
  3. Исправьте набор изменений B и обновите патч
  4. Повторно примените C через E
  5. Завершите исправления

Это делается следующим образом:

  1. cd <project>
  2. hg qinit
  3. hg qimport --rev B:E
  4. hg qpop --all
  5. hg qpush <patch name for B>
  6. …исправьте проблемы, которые вы обнаружили в B
  7. hg qrefresh
  8. hg qpush --all
  9. hg qfinish --applied

Все это предполагает, что с B по E не были отправлены ни в какие общедоступные репозитории. Если они уже были отправлены, то лучше всего просто исправить проблему в новом наборе изменений (F).

Комментарии:

1. Идея здесь в том, чтобы фактически изменить историю записанных наборов изменений. Исходя из моего понимания Mercurial и GIT, GIT более приспособлен к изменению истории, чем mercurial, но я также понимаю, что mercurial может это сделать. Однако мне кажется, что я бы почти никогда не захотел изменять исторические наборы изменений, вместо этого я всегда хотел бы «исправить» последнюю подсказку любым необходимым способом, а затем зафиксировать как новый набор изменений с соответствующими комментариями. Однако это не рекомендуется? Я сам довольно новичок в hg…

2. @drventure: Действия, перечисленные в моем ответе, изменят историю. Обычно в Mercurial это не одобряется, но безопасно, если изменяемые вами наборы изменений никогда не передавались на удаленный сервер. После того, как наборы изменений были отправлены на удаленный сервер, вы никогда не должны пытаться их изменять. Вместо этого вы должны создать новый набор изменений, который устраняет проблему (как вы уже отметили).

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

4. Просто для ясности, вы не можете этого сделать, если вы уже нажали.

Ответ №3:

Вы также можете использовать HisteditExtension (вместо MqExtension). MqExtension намного мощнее, но, я думаю, он также намного сложнее. HisteditExtension немного больше похоже git rebase --interactive .

 # Ordinarily it would be something like (I'd normally do -r -5, instead):
hg histedit d0844102a010
  

В вашем текстовом редакторе откроется файл, который выглядит примерно так:

 pick d0844102a010 A
pick a9448f0ba534 B
pick b754f9f2513b C
pick 736f7f2363ff D
pick 05bb58f48597 E

# Edit history between d0844102a010 and 05bb58f48597
#
# Commands:
#  p, pick = use commit
#  e, edit = use commit, but stop for amending
#  f, fold = use commit, but fold into previous commit
#  d, drop = remove commit from history
#
  

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

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

Помните, что вы должны использовать hg histedit --continue вместо hg commit (если вы «редактируете» или если есть конфликт слияния). 🙂 Если у вас возникают конфликты, и все выглядит не очень хорошо, и вы просто хотите отменить, тогда вы можете использовать hg histedit --abort .

 # Fix up files...
vim foo bar baz

# Finished; apply the changes (and pray for a clean merge ;).
hg histedit --continue
  

Редактируйте историю на свой страх и риск, конечно. Я рекомендую вам создать резервную архивную папку или zip-файл вашего дерева исходных текстов перед редактированием истории, пока вы не ознакомитесь с командами.