Резервное слияние на Mercurial

Как вы отменяете эффект слияния на поляризованных ветвях, не умирая от агонии?

Эта проблема преследовала меня в течение месяцев, и я, наконец, сдался.

У вас есть 1 репозиторий с 2 ​​ Именованными ветвями. A и B.

Изменения, которые происходят с A, неизбежно возникают на B.

Изменения, которые происходят непосредственно на B, НЕ ДОЛЖНЫ встречаться на A.

В такой конфигурации объединение "B" в "A" создает серьезную проблему в репозитории, так как все изменения в B появляются в A, как если бы они были сделаны в A.

Единственным "нормальным" способом восстановления из этой ситуации является "отпирание" слияния, то есть:

 hg up -r A 
 hg backout -r BadMergeRev --parent BadMergerevBeforeOnA 

Который выглядит отлично и денди, пока вы не решите слиться позже в правильном направлении, и вы получите всевозможные неприятные вещи, и код, который был стерт/прокомментирован специально, ветвь B внезапно становится неудовлетворительной или раскованной.

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

Вот изображение, разъясняющее проблему:

[Исходное изображение потеряно]

Файлы C и E (или изменения C и E) должны отображаться только на ветке b, а не на ветке a. Версия A9 здесь (ветвь a, revno 9) - это начало проблемы.

Изменения A10 и A11 являются этапами "Резервное слияние" и "Объединить резервные копии".

И ревизия B12 является mercurial, ошибочно повторяя изменение, которое не предназначалось для удаления.

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

Примечание

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

Чтобы выполнить

В модели я использовал файлы Seperate. Это делает проблему простой. Они представляют собой произвольные изменения, которые могут быть отдельной строкой.

Кроме того, чтобы добавить оскорбление к травме, на ветке A произошли существенные изменения, которые оставляют постоянную проблему "вносить изменения в ветвь A в конфликт с изменениями в ветке B, которая только что появилась (и получила поддержку), которая выглядит как изменение на ветке А вместо"

Об истории перезаписи трюков:

Проблема со всеми этими ретроактивными решениями такова:

  • У нас 9000 коммитов.
  • Cloning freshly таким образом занимает полчаса.
  • Если существует какой-то один плохой клон репозитория где-то, есть вероятность, что он возвращается в контакт с исходным репозиторием и снова сбивает его с толку.
  • Все уже клонировали этот репозиторий, и теперь прошло несколько дней с текущими фиксациями.
  • Один такой клоун, оказывается, является живым сайтом, поэтому "вытирая его и начинать с нуля" = "большой нон"

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

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

Ответ 1

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

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

Итак, если что-то проверено на BRANCH_V8, оно должно быть объединено с BRANCH_V9.

Теперь один из разработчиков делает следующую ошибку: он объединяет все изменения с BRANCH_V9 в BRANCH_V8 (т.е. слияние в неправильном направлении). Кроме того, после этого плохого слияния он выполняет некоторые дополнительные коммиты, прежде чем он замечает свою ошибку.

Итак, ситуация такова, как показано в графическом журнале ниже.

o  BRANCH_V8 - 13 - important commit right after the bad merge
|
o    BRANCH_V8 - 12 - wrong merge from BRANCH_V9
|\
| o  BRANCH_V8 - 11 - adding comment on BRANCH_V8 (ie. last known good state)
| |
o |  BRANCH_V9 - 10 - last commit on BRANCH_V9
| |

Мы можем исправить эту ошибку следующим образом:

  • обновите свой локальный каталог до последнего хорошего состояния BRANCH_V8: hg update 11
  • Создайте новый дочерний элемент этого последнего хорошего состояния:
    • изменить файл $EDITOR some/file.txt (это необходимо, потому что Mercurial не разрешает пустые коммиты)
    • зафиксировать эти изменения hg commit -m "generating commit on BRANCH_V8 to rectify wrong merge from BRANCH_V9"
      Ситуация выглядит следующим образом:
      o  BRANCH_V8 - 14 - generating commit on BRANCH_V8 to rectify wrong merge from BRANCH_V9
      |
      | o  BRANCH_V8 - 13 - important commit right after the bad merge
      | |
      | o  BRANCH_V8 - 12 - wrong merge from BRANCH_V9
      |/|
      o |  BRANCH_V8 - 11 - adding comment on BRANCH_V8
      | |
      | o  BRANCH_V9 - 10 - last commit on BRANCH_V9
      
  • Объедините вновь сгенерированный заголовок с ревизией, в которой произошло неудачное слияние, и отбросьте все изменения перед фиксацией. Не просто слияние двух головок, потому что после этого вы потеряете важную фиксацию, которая произошла после слияния!

    • merge: hg merge 12 (игнорировать любые конфликты)
    • выбросить все изменения: hg revert -a --no-backup -r 14
    • зафиксировать изменения: hg commit -m "throwing away wrong merge from BRANCH_V9" Ситуация теперь выглядит так:
      o    BRANCH_V8 - 15 - throwing away wrong merge from BRANCH_V9
      |\
      | o  BRANCH_V8 - 14 - generating commit on BRANCH_V8 to rectify wrong merge from BRANCH_V9
      | |
      +---o  BRANCH_V8 - 13 - important commit right after the bad merge
      | |
      o |  BRANCH_V8 - 12 - wrong merge from BRANCH_V9
      |\|
      | o  BRANCH_V8 - 11 - adding comment on BRANCH_V8
      | |
      o |  BRANCH_V9 - 10 - last commit on BRANCH_V9
      | |
      

    Т.е. на BRANCH_V8 есть две главы: одна, которая содержит исправление плохого слияния, а другая содержит левую над важной фиксацией на BRANCH_V8, которая произошла сразу после слияния.

  • Объедините две головки на BRANCH_V8:
    • merge: hg merge
    • commit: hg commit -m "merged two heads used to revert from bad merge"

Ситуация в конце на BRANCH_V8 теперь исправлена ​​и выглядит следующим образом:

o    BRANCH_V8 - 16 - merged two heads used to revert from bad merge
|\
| o    BRANCH_V8 - 15 - throwing away wrong merge from BRANCH_V9
| |\
| | o  BRANCH_V8 - 14 - generating commit on BRANCH_V8 to rectify wrong merge from BRANCH_V9
| | |
o | |  BRANCH_V8 - 13 - important commit right after the bad merge
|/ /
o |  BRANCH_V8 - 12 - wrong merge from BRANCH_V9
|\|
| o  BRANCH_V8 - 11 - adding comment on BRANCH_V8
| |
o |  BRANCH_V9 - 10 - last commit on BRANCH_V9
| |

Теперь ситуация на BRANCH_V8 верна. Остается только одна проблема: следующее слияние с BRANCH_V8 на BRANCH_V9 будет неправильным, так как оно будет сливаться с "fix" для плохого слияния, которое мы не хотим на BRANCH_V9. Трюк здесь состоит в том, чтобы объединиться с BRANCH_V8 в BRANCH_V9 в отдельных изменениях:

  • Сначала слияния, от BRANCH_V8 до BRANCH_V9, правильные изменения на BRANCH_V8 из-за неудачного слияния.
  • Второе слияние в ошибке слияния и его исправлении и, не требуя ничего проверить, выбросить все изменения.
  • В-третьих, объедините оставшиеся изменения с BRANCH_V8.

Подробнее:

  • Переключите рабочий каталог в BRANCH_V9: hg update BRANCH_V9
  • Слияние в последнем хорошем состоянии BRANCH_V8 (т.е. фиксация, которую вы создали для исправления плохого слияния). Это слияние является слиянием, как любое регулярное слияние, т.е. конфликты должны быть решены, как обычно, и ничего не нужно выбрасывать.
    • merge: hg merge 14
    • commit: hg commit -m "Merging in last good state of BRANCH_V8" Ситуация сейчас:
      @    BRANCH_V9 - 17 - Merging in last good state of BRANCH_V8
      |\
      | | o    BRANCH_V8 - 16 - merged two heads used to revert from bad merge
      | | |\
      | +---o  BRANCH_V8 - 15 - throwing away wrong merge from BRANCH_V9
      | | | |
      | o | |  BRANCH_V8 - 14 - generating commit on BRANCH_V8 to rectify wrong merge from BRANCH_V9
      | | | |
      | | o |  BRANCH_V8 - 13 - important commit right after the bad merge
      | | |/
      +---o  BRANCH_V8 - 12 - wrong merge from BRANCH_V9
      | |/
      | o  BRANCH_V8 - 11 - adding comment on BRANCH_V8
      | |
      o |  BRANCH_V9 - 10 - last commit on BRANCH_V9
      | |
      
  • Объединить неудачное слияние на BRANCH_V8 + его исправление и выбросить все изменения:
    • merge: hg merge 15
    • вернуть все изменения: hg revert -a --no-backup -r 17
    • передать слияние: hg commit -m "Merging in bad merge from BRANCH_V8 and its fix and throwing it all away" Текущая ситуация:
      @    BRANCH_V9 - 18 - Merging in bad merge from BRANCH_V8 and its fix and throwing it all away
      |\
      | o    BRANCH_V9 - 17 - Merging in last good state of BRANCH_V8
      | |\
      +-----o  BRANCH_V8 - 16 - merged two heads used to revert from bad merge
      | | | |
      o---+ |  BRANCH_V8 - 15 - throwing away wrong merge from BRANCH_V9
      | | | |
      | | o |  BRANCH_V8 - 14 - generating commit on BRANCH_V8 to rectify wrong merge from BRANCH_V9
      | | | |
      +-----o  BRANCH_V8 - 13 - important commit right after the bad merge
      | | |
      o---+  BRANCH_V8 - 12 - wrong merge from BRANCH_V9
      |/ /
      | o  BRANCH_V8 - 11 - adding comment on BRANCH_V8
      | |
      o |  BRANCH_V9 - 10 - last commit on BRANCH_V9
      | |
      
  • Объединить изменения слева от BRANCH_V8:
    • merge: hg merge BRANCH_V8
    • commit: hg commit -m "merging changes from BRANCH_V8"

В конце ситуация выглядит так:

@    BRANCH_V9 - 19 - merging changes from BRANCH_V8
|\
| o    BRANCH_V9 - 18 - Merging in bad merge from BRANCH_V8 and its fix and throwing it all away
| |\
| | o    BRANCH_V9 - 17 - Merging in last good state of BRANCH_V8
| | |\
o | | |  BRANCH_V8 - 16 - merged two heads used to revert from bad merge
|\| | |
| o---+  BRANCH_V8 - 15 - throwing away wrong merge from BRANCH_V9
| | | |
| | | o  BRANCH_V8 - 14 - generating commit on BRANCH_V8 to rectify wrong merge from BRANCH_V9
| | | |
o | | |  BRANCH_V8 - 13 - important commit right after the bad merge
|/ / /
o---+  BRANCH_V8 - 12 - wrong merge from BRANCH_V9
|/ /
| o  BRANCH_V8 - 11 - adding comment on BRANCH_V8
| |
o |  BRANCH_V9 - 10 - last commit on BRANCH_V9
| |

После всех этих шагов, в которых вам не нужно проверять какой-либо diff вручную, BRANCH_V8 и BRANCH_V9 верны, и будущие слияния с BRANCH_V8 на BRANCH_V9 также будут правильными.

Ответ 2

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

Я ссылался на эту страницу при выполнении более простой операции:

http://strongdynamic.blogspot.com/2007/08/expunging-problem-file-from-mercurial.html

Ответ 3

ОК, начните с создания нового пустого хранилища в отдельном каталоге из разбитого репозитория (hg init). Теперь поднимите и добавьте последнюю известную хорошую версию в новый репозиторий; убедитесь, что вы не потянете плохое слияние и все время тянете все. В старом репозитории обновите последнюю известную хорошую версию A и сделайте следующее:

hg graft r1 r2 r3

где r1-3 - изменения, сделанные после неудачного слияния. На данный момент у вас могут возникнуть конфликты; исправить их.

Это должно привести к новым изменениям в отношении последней известной хорошей версии A. Перенести эти новые изменения в новый репозиторий. Чтобы просто проверить, что вы ничего не пропустили, сделайте hg, входящий в старый репозиторий. Если вы видите что-то другое, кроме неудачного слияния и r1-3, потяните его.

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

Ответ 4

Итак, вы хотите объединить только несколько наборов изменений из B в A? Резервирование наборов изменений, как вы делали, действительно плохая идея, поскольку вы уже пострадали.

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

Ответ 5

После долгих обсуждений с некоторыми из полезных людей в #mercurial на freenode, mpm предоставила частичное решение, которое, похоже, работает для моего тестового примера (я создал поддельный репозиторий, пытающийся реплицировать сценарий)

Однако, по моему фактическому хранилищу, по причинам, которые я не совсем понимаю, он по-прежнему менее совершенен.

Вот схема предлагаемого в настоящее время способа решения этой проблемы:

[Исходное изображение потеряно]

Теперь он меньше проблем для исправления, но мне по-прежнему приходится сравнивать diff (т.е.: b46: b11 vs b46: b8, a43: a10 vs a43: a9) и вручную редактировать некоторые изменения.

Не закрывать этот вопрос/принимать ответ, пока я не получу гарантированный способ работы с каким-либо репозиторием.

Внимание!

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