Ответ 1
Я считаю, что проблема заключается в том, что слияние работает иначе, чем вы думаете. Вы пишете
Так как новая ветвь релиза содержит все панели изменений ветки Feature (ничего не было отменено), почему ветка по умолчанию также не получает все эти изменения?
Когда вы объединяете две ветки, неправильно думать об этом, применяя все изменения из одной ветки на другую ветку. Таким образом, ветвь default
не получает "никаких" наборов изменений из release2
. Я знаю, что мы обычно думаем о слияниях, но это неточно.
Что действительно происходит при объединении двух наборов изменений:
-
Mercurial находит общего предка для двух наборов изменений.
-
Для каждого файла, который отличается между двумя наборами изменений, Mercurial запускает трехсторонний алгоритм слияния с использованием файла предка, файл в первом наборе изменений и файле во втором наборе изменений.
В вашем случае вы объединяете версии 11 и 12. Наименее распространенным предком является ревизия 8. Это означает, что Mercurial будет запускать трехстороннее слияние между файлами из них:
-
Редакция 8: нет отступлений
-
Отредактирована ветвь функций версии 11:
-
Редакция 12: нет резервных копий
В трехстороннем слиянии изменение всегда не превзойдет никаких изменений. Mercurial видит, что файлы были изменены между 8 и 11, и он не видит изменений между 8 и 12. Таким образом, он использует измененную версию из версии 11 в слиянии. Это применимо для любого трехмерного алгоритма слияния. Полная таблица слияния выглядит так: old
, new
,... - содержимое совпадающих узлов в трех файлах:
ancestor local other -> merge
old old old old (nobody changed the hunk)
old old new new (they changed the hunk)
old new old new (you changed the hunk)
old new new new (hunk was cherry picked onto both branches)
old foo bar <!> (conflict, both changed hunk but differently)
Я боюсь, что merge changeset не должен быть полностью отменен из-за этого удивительного поведения слияния. Mercurial 2.0 и более поздние версии будут прерваны и будут жаловаться, если вы попытаетесь отменить слияние.
В общем, можно сказать, что трехсторонний алгоритм слияния предполагает, что все изменения хороши. Поэтому, если вы объедините branch1
в dev
, а затем отмените слияние с резервным копированием, тогда алгоритм слияния будет считать, что состояние "лучше", чем раньше. Это означает, что вы не можете просто повторно объединить branch1
в dev
в более позднюю точку, чтобы вернуть обратно резервные изменения.
Что вы можете сделать, так это использовать "фиктивное слияние" при слиянии с default
. Вы просто объединяетесь и всегда сохраняете изменения в ветки релиза, которые вы объединяете в default
:
$ hg update default
$ hg merge release2 --tool internal:other -y
$ hg revert --all --rev release2
$ hg commit -m "Release 2 is the new default"
Это приведет к тому, что проблема и сила default
будут такими же, как release2
. Это предполагает, что на default
не происходит никаких изменений без объединения в ветвь release.
Если вы должны иметь возможность выпускать выпуски с пропущенными функциями, тогда "правильный" способ - не объединять эти функции вообще. Слияние - это сильная приверженность: вы говорите Mercurial, что у сменного набора теперь есть все хорошие вещи от обоих его предков. Пока Mercurial не позволит вам выбрать собственную версию базы при слиянии, трехсторонний алгоритм слияния не позволит вам передумать об отступлении.
Однако вы можете сделать резервную копию резервной копии. Это означает, что вы повторно вводите изменения из своей ветки функций в свою ветвь выпуска. Итак, вы начинаете с графика, например
release: ... o --- o --- m1 --- m2
/ /
feature-A: ... o --- o /
/
feature-B: ... o --- o --- o
Теперь вы решили, что функция A была плохая, и вы отменили слияние:
release: ... o --- o --- m1 --- m2 --- b1
/ /
feature-A: ... o --- o /
/
feature-B: ... o --- o --- o
Затем вы объединяете еще одну функцию в свою ветвь релиза:
release: ... o --- o --- m1 --- m2 --- b1 --- m3
/ / /
feature-A: ... o --- o / /
/ /
feature-B: ... o --- o --- o /
/
feature-C: ... o --- o --- o --- o --- o
Если вы хотите снова ввести функцию A, вы можете сделать резервную копию b1
:
release: ... o --- o --- m1 --- m2 --- b1 --- m3 --- b2
/ / /
feature-A: ... o --- o / /
/ /
feature-B: ... o --- o --- o /
/
feature-C: ... o --- o --- o --- o --- o
Мы можем добавить дельта к графику, чтобы лучше показать, что изменится где и когда:
+A +B -A +C --A
release: ... o --- o --- m1 --- m2 --- b1 --- m3 --- b2
После этого второго резервного копирования вы можете снова объединиться с feature-A
в случае добавления новых наборов изменений. Граф, который вы объединяете, выглядит так:
release: ... o --- o --- m1 --- m2 --- b1 --- m3 --- b2
/ / /
feature-A: ... o -- a1 - a2 / /
/ /
feature-B: ... o --- o --- o /
/
feature-C: ... o --- o --- o --- o --- o
и вы объедините a2
и b2
. Общим предком будет a1
. Это означает, что единственными изменениями, которые вам нужно учитывать при трехходовой слиянии, являются те, которые находятся между a1
и a2
и a1
и b2
. Здесь b2
уже есть основная часть изменений "в" a2
, поэтому слияние будет небольшим.