Резервне копіювання зворотного злиття на Mercurial


77

Як змінити ефект злиття на поляризованих гілках, не вмираючи від агонії?

Ця проблема мучить мене місяцями, і я нарешті здався.

У вас є 1 сховище з 2 іменованими гілками. 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 є ртутною, помилково неодноразово відмовляючись від змін, які не мали на меті відмінити.

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

Примітка

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

Розробити

У моделі я використовував окремі файли. Завдяки цьому проблема звучить просто. Вони просто представляють довільні зміни, які можуть бути окремим рядком.

Крім того, щоб додати образи до травми, відбулися суттєві зміни у гілці A, що залишає постійну проблему. на гілці А замість цього "

Про хитрощі з переписуванням історії:

Проблема всіх цих ретроактивних рішень полягає в наступному:

  1. У нас 9000 комітів.
  2. Таким чином клонування свіжо займає півгодини
  3. Якщо десь існує хоч один невдалий клон сховища , існує можливість, що він повернеться в контакт із початковим сховищем і вдарить його знову.
  4. Всі вже клонували це сховище, і ось уже минуло кілька днів із поточними комітами.
  5. Одним з таких клонів є веб-сайт, який працює в режимі реального часу, тому "витираючи його і починаючи з нуля" = "велике ноно"

(Я визнаю, що багато з перерахованого трохи хитрі, але вони поза моїм контролем).

Єдиними рішеннями, які є життєздатними, є ті, які припускають, що люди можуть і будуть робити все неправильно, і що є спосіб „скасувати” цю несправність.


1
Ой, це виглядає потворно ... Ви також опублікували це на selenic.com/mercurial/bts ? Це звучить як помилка Hg, яку слід усунути.
Mike G.

4
Вибачення усім, хостинг зображень пропав :( і я не можу знайти оригіналів
Кент Фредрік

1
Будь-які новини щодо цього просто з інтересу, після 2 років розробки я хотів би думати, що зараз можуть бути кращі способи вирішити це? :)
Піт Данкансон,

Чи можна зрозуміти, що гілка "A" - це QA / Prod, а "B" - Main / Dev?
Сани

Відповіді:


50

Думаю, я знайшов рішення, яке назавжди виправляє помилкове злиття і яке не вимагає вручну перевіряти будь-які відмінності. Фокус полягає в тому, щоб повернутися в історію і генерувати коміти паралельно поганому злиття.

Отже, у нас є сховище з окремими гілками для підтримуваної версії одного продукту. Як і ситуація, поставлена ​​у питанні, усі зміни, внесені у гілку попередньої версії (тобто виправлення помилок у цій версії), у підсумку повинні бути об’єднані з гілками пізніших версій.

Тож конкретно, якщо щось зареєстровано на BRANCH_V8, це має бути об’єднано з BRANCH_V9.

Зараз один із розробників допускає таку помилку: він об'єднує всі зміни з BRANCH_V9 у BRANCH_V8 (тобто об'єднання в неправильному напрямку). Крім того, після того поганого злиття він виконує деякі додаткові коміти, перш ніж помітить свою помилку.

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

o BRANCH_V8 - 13 - важливий коміт відразу після поганого злиття
|
o BRANCH_V8 - 12 - неправильне об'єднання з BRANCH_V9
| \
| o BRANCH_V8 - 11 - додавання коментаря до BRANCH_V8 (тобто останнього відомого доброго стану)
| |
o | BRANCH_V9 - 10 - останній коміт BRANCH_V9
| |

Ми можемо виправити цю помилку наступним чином:

  1. оновіть свій локальний каталог до останнього хорошого стану BRANCH_V8: hg update 11
  2. Створіть нову дитину цього останнього доброго стану:
    1. змінити якийсь файл $EDITOR some/file.txt(це необхідно, оскільки Mercurial не дозволяє порожні коміти)
    2. здійснити ці зміни hg commit -m "generating commit on BRANCH_V8 to rectify wrong merge from BRANCH_V9"
      Ситуація зараз виглядає наступним чином:
      o BRANCH_V8 - 14 - генерація коміту на BRANCH_V8 для виправлення неправильного злиття з BRANCH_V9
      |
      | o BRANCH_V8 - 13 - важливий коміт відразу після поганого злиття
      | |
      | o BRANCH_V8 - 12 - неправильне об'єднання з BRANCH_V9
      | / |
      o | BRANCH_V8 - 11 - додавання коментаря до BRANCH_V8
      | |
      | o BRANCH_V9 - 10 - останній коміт BRANCH_V9
      
  3. Об'єднайте нещодавно згенеровану голову з версією, в якій сталося погане злиття, і викиньте всі зміни перед фіксацією. Не просто об’єднуйте дві голови, тому що ви також втратите важливий коміт, який відбувся після об’єднання!

    1. злиття: hg merge 12(ігнорувати будь-які конфлікти)
    2. викинути всі зміни: hg revert -a --no-backup -r 14
    3. здійснити зміни: hg commit -m "throwing away wrong merge from BRANCH_V9" Ситуація тепер виглядає так:
      o BRANCH_V8 - 15 - викидання неправильного злиття з BRANCH_V9
      | \
      | o BRANCH_V8 - 14 - генерація коміту на BRANCH_V8 для виправлення неправильного злиття з BRANCH_V9
      | |
      + --- o BRANCH_V8 - 13 - важливий коміт відразу після поганого злиття
      | |
      o | BRANCH_V8 - 12 - неправильне об’єднання з BRANCH_V9
      | \ |
      | o BRANCH_V8 - 11 - додавання коментаря до BRANCH_V8
      | |
      o | BRANCH_V9 - 10 - останній коміт BRANCH_V9
      | |
      

    Тобто. на BRANCH_V8 є дві голови: одна, що містить виправлення помилкового злиття, а друга, що містить залишений важливий коміт на BRANCH_V8, який стався відразу після об’єднання.

  4. Об’єднайте дві голови в BRANCH_V8:
    1. злиття: hg merge
    2. здійснити: hg commit -m "merged two heads used to revert from bad merge"

Зрештою ситуація на BRANCH_V8 виправлена ​​і виглядає так:

o BRANCH_V8 - 16 - об'єднано дві головки, що використовуються для повернення з поганого злиття
| \
| o BRANCH_V8 - 15 - викидання неправильного злиття з BRANCH_V9
| | \
| | o BRANCH_V8 - 14 - генерація коміту на BRANCH_V8 для виправлення неправильного злиття з BRANCH_V9
| | |
o | | BRANCH_V8 - 13 - важливий коміт відразу після поганого злиття
| / /
o | BRANCH_V8 - 12 - неправильне об’єднання з BRANCH_V9
| \ |
| o BRANCH_V8 - 11 - додавання коментаря до BRANCH_V8
| |
o | BRANCH_V9 - 10 - останній коміт BRANCH_V9
| |

Зараз ситуація на BRANCH_V8 правильна. Залишається єдиною проблемою те, що наступне злиття з BRANCH_V8 у BRANCH_V9 буде неправильним, оскільки воно буде об'єднано у "виправленні" і для поганого злиття, чого ми не хочемо на BRANCH_V9. Фокус тут полягає в об’єднанні з BRANCH_V8 у BRANCH_V9 в окремих змінах:

  • Перше злиття, з BRANCH_V8 на BRANCH_V9, правильні зміни на BRANCH_V8 від до поганого злиття.
  • Друге злиття в помилці злиття та її виправлення, і, не потребуючи нічого перевіряти, викиньте всі зміни
  • По-третє, об’єднайте інші зміни, що залишилися з BRANCH_V8.

Детально:

  1. Переключіть свій робочий каталог на BRANCH_V9: hg update BRANCH_V9
  2. Об’єднання в останньому доброму стані BRANCH_V8 (тобто коміт, який ви створили для виправлення поганого злиття). Це злиття є злиттям, як будь-яке звичайне злиття, тобто. конфлікти слід вирішувати як завжди, і нічого не потрібно викидати.
    1. злиття: hg merge 14
    2. commit: hg commit -m "Merging in last good state of BRANCH_V8" Ситуація зараз:
      @ BRANCH_V9 - 17 - Злиття в останньому доброму стані BRANCH_V8
      | \
      | | o BRANCH_V8 - 16 - об'єднано дві головки, що використовуються для повернення з поганого злиття
      | | | \
      | + --- o BRANCH_V8 - 15 - викидання неправильного злиття з BRANCH_V9
      | | | |
      | o | | BRANCH_V8 - 14 - генерація коміту на BRANCH_V8 для виправлення неправильного злиття з BRANCH_V9
      | | | |
      | | o | BRANCH_V8 - 13 - важливий коміт відразу після поганого злиття
      | | | /
      + --- o BRANCH_V8 - 12 - неправильне об'єднання з BRANCH_V9
      | | /
      | o BRANCH_V8 - 11 - додавання коментаря до BRANCH_V8
      | |
      o | BRANCH_V9 - 10 - останній коміт BRANCH_V9
      | |
      
  3. Об’єднайте погане злиття на BRANCH_V8 + його виправлення та викиньте всі зміни:
    1. злиття: hg merge 15
    2. скасувати всі зміни: hg revert -a --no-backup -r 17
    3. здійснити злиття: hg commit -m "Merging in bad merge from BRANCH_V8 and its fix and throwing it all away" Поточна ситуація:
      @ BRANCH_V9 - 18 - Злиття в поганому злитті з BRANCH_V8 та його виправлення та викидання всього
      | \
      | o BRANCH_V9 - 17 - Злиття в останньому доброму стані BRANCH_V8
      | | \
      + ----- o BRANCH_V8 - 16 - об'єднано дві головки, що використовуються для повернення з поганого злиття
      | | | |
      o --- + | BRANCH_V8 - 15 - викидання неправильного об’єднання з BRANCH_V9
      | | | |
      | | o | BRANCH_V8 - 14 - генерація коміту на BRANCH_V8 для виправлення неправильного злиття з BRANCH_V9
      | | | |
      + ----- o BRANCH_V8 - 13 - важливий коміт відразу після поганого злиття
      | | |
      o --- + BRANCH_V8 - 12 - неправильне об'єднання з BRANCH_V9
      | / /
      | o BRANCH_V8 - 11 - додавання коментаря до BRANCH_V8
      | |
      o | BRANCH_V9 - 10 - останній коміт BRANCH_V9
      | |
      
  4. Об’єднати залишені зміни від BRANCH_V8:
    1. злиття: hg merge BRANCH_V8
    2. здійснити: hg commit -m "merging changes from BRANCH_V8"

Зрештою ситуація виглядає так:

@ BRANCH_V9 - 19 - об’єднання змін із BRANCH_V8
| \
| o BRANCH_V9 - 18 - Злиття в поганому злитті з BRANCH_V8 та його виправлення та викидання всього
| | \
| | o BRANCH_V9 - 17 - Злиття в останньому доброму стані BRANCH_V8
| | | \
o | | | BRANCH_V8 - 16 - об'єднано дві головки, що використовуються для повернення з поганого злиття
| \ | | |
| o --- + BRANCH_V8 - 15 - викидання неправильного об'єднання з BRANCH_V9
| | | |
| | | o BRANCH_V8 - 14 - генерація коміту на BRANCH_V8 для виправлення неправильного злиття з BRANCH_V9
| | | |
o | | | BRANCH_V8 - 13 - важливий коміт відразу після поганого злиття
| / / /
o --- + BRANCH_V8 - 12 - неправильне об'єднання з BRANCH_V9
| / /
| o BRANCH_V8 - 11 - додавання коментаря до BRANCH_V8
| |
o | BRANCH_V9 - 10 - останній коміт BRANCH_V9
| |

Після всіх цих кроків, у яких вам не доведеться перевіряти будь-яку різницю вручну, BRANCH_V8 та BRANCH_V9 є правильними, а майбутні злиття з BRANCH_V8 до BRANCH_V9 також будуть правильними.


В основному перевага цього методу полягає в тому, що ви генеруєте коміт (у даному випадку версію 15), який, починаючи з останньої позитивної точки на BRANCH_V8, містить лише неправильне злиття та його виправлення. Потім ви можете окремо об’єднати цей набір змін у BRANCH_V9 і можете безпечно ігнорувати всі зміни, що входять до цього злиття.
oenli

1
Аааа, </pre>після другого до останнього блоку коду зник. Знайшов деякий час, але саме тоді, коли я був готовий відмовитись ... Я думаю, зараз все відображається правильно :)
sth

Зауважте, що для Git можна використовувати ту саму техніку, щоб ви могли виправити зворотне злиття без перезапису історії, що спричиняє головний біль.
oenli

4
Це чудово. Дякую. Перш ніж виконувати будь-що з цього, @Kent повинен встановити гачок коміту, запобігаючи фіксації та / або натисканню зворотних злиттів. Усуньте першопричину проблеми, а потім усуньте залишки симптомів.
Харві

1
Я створив сховище Hg, щоб продемонструвати це рішення (без зайвого порожнього коміту
січня

2

Нещодавно ви можете експортувати сховище до групи різниць, редагувати історію, а потім склеїти все, що хочете, у нове сховище, так що немає ризику пошкодження. Можливо, для вашого прикладу непогано, але я не знаю, як виглядає справжня історія.

Я посилався на цю сторінку, виконуючи простішу операцію:

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


Так, це був би вичерпний процес, коли ви робите те, що ви робили, і це не обов’язково спрацювало б для моєї ситуації (іменовані філії працюють якось дивно), і історія - це свинарник, коли у вас є> 4 учасника комісії за власним графіком. це взагалі нелінійність;)
Кент Фредрік

2

Добре, почніть із створення нового порожнього сховища в окремому каталозі від непрацюючого сховища (hg init). Тепер підтягніть і включіть останню відому хорошу версію до нового сховища; переконайтеся , що ви НЕ тягнути погане злиття і зробити тягнути все перед ним. У старому сховищі оновіть останню відому хорошу версію A та виконайте такі дії:

hg graft r1 r2 r3

де r1-3 - зміни, внесені після пошкодженого злиття. У цей момент у вас можуть виникнути конфлікти; виправити їх.

Це повинно призвести нові зміни в ставленні останньої відомої хорошою версії . Витягніть ці нові зміни до нового сховища. Щоб ще раз перевірити, що ви нічого не пропустили, зробіть hg, що надходить на старе сховище. Якщо ви бачите щось інше, ніж невдале злиття та r1-3, витягніть його.

Викиньте старе сховище. Ви закінчили. Злиття взагалі не в новому сховищі, і вам ніколи не доводилося переписувати історію.


1

Отже, ви хочете об’єднати лише деякі набори змін з B в A? Резервне копіювання наборів змін, як ви робили, - це дійсно погана ідея, оскільки ви вже страждали.

Вам слід або використовувати розширення для трансплантації, або мати третю гілку, де ви вносите загальні зміни, щоб об’єднатись як в А, так і в В.


2
Не відступаючи від змін, тому що я хочу / хочу сюди;), і проблема полягає в тому, скільки б я не створив гілок, все одно можливо об’єднати їх неправильно, викликаючи цю проблему. (повірте мені, був на цьому шляху)
Кент Фредрік

1

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

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

Ось схема запропонованого в даний час способу вирішення цієї проблеми:

[Оригінальне зображення втрачено]

Зараз це менше проблем для виправлення, але мені все одно доводиться порівнювати відмінності (тобто: b46: b11 проти b46: b8, a43: a10 проти a43: a9) і вручну редагувати деякі зміни знову.

Не закриваючи це запитання / не приймаючи відповіді, доки я не отримаю гарантований спосіб роботи на будь-якому сховищі.

Важливо

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.