Hg: Как сделать перебазирование, например, перебазирование git

В Git я могу сделать это:

1. Start working on new feature:
$ git co -b newfeature-123  # (a local feature development branch)
do a few commits (M, N, O)

master A---B---C
                \
newfeature-123   M---N---O

2. Pull new changes from upstream master:
$ git pull
(master updated with ff-commits)

master A---B---C---D---E---F
                \
newfeature-123   M---N---O

3. Rebase off master so that my new feature 
can be developed against the latest upstream changes:
(from newfeature-123)
$ git rebase master

master A---B---C---D---E---F
                            \
newfeature-123               M---N---O


Я хочу знать, как сделать то же самое в Mercurial, и я поискал в Интернете ответ, но лучшее, что я смог найти, было: git rebase - может hg это сделать?

Эта ссылка содержит 2 примера:
1. Я признаю, что это: (заменяя исправления из примера на те из моего собственного примера)

hg up -C F  
hg branch -f newfeature-123  
hg transplant -a -b newfeature-123 

не так уж и плохо, за исключением того, что он оставляет после перебазирования M-N-O в качестве не объединенной головы и создает 3 новых коммита M ', N', O ', которые представляют их ответвления от обновленной основной линии.

В основном проблема в том, что я получаю следующее:

master A---B---C---D---E---F
                \           \
newfeature-123   \           M'---N'---O'
                  \
newfeature-123     M---N---O

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

  1. Другой вариант по той же ссылке -
hg qimport -r M:O
hg qpop -a
hg up F
hg branch newfeature-123
hg qpush -a
hg qdel -r qbase:qtip

и это приводит к желаемому графику:

master A---B---C---D---E---F
                            \
newfeature-123               M---N---O

но эти команды (всего их 6!) кажутся намного сложнее, чем

$ git rebase master

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


person jpswain    schedule 20.04.2010    source источник
comment
это нехорошо, потому что оставляет после себя локальные нежелательные коммиты, которые следует отбросить. - собственно, git делает то же самое. Он не изменяет и не удаляет коммиты в исходной ветке, он просто создает новые, которые применяют тот же набор изменений поверх master. Вы все еще можете получить доступ к старым, используя git reflog, и они не исчезнут полностью, пока не будут собраны сборщиком мусора. Если вы хотите сохранить их в именованной ветке, чтобы вам не приходилось использовать журнал ссылок, просто сделайте git branch feature-123_original перед перебазированием.   -  person MatrixFrog    schedule 24.12.2010
comment
Случайный вопрос: вы сами рисовали в ascii ревизии / ветки или есть инструмент, который это делает?   -  person Amir Rachum    schedule 23.12.2012
comment
Просто сделал их сам, установив TextWrangler на перезапись.   -  person jpswain    schedule 25.12.2012
comment
В последнее время, работая с hg и git, я тоже заметил, что они ведут себя по-разному. Для людей, прибывающих сюда, таких как я, ищущих проблему: как указано в других ответах ниже, в наши дни используйте --keepbranches. Если вы используете TortoiseHg, для этого есть переключатель в диалоговом окне переустановки.   -  person Rainer Schwarze    schedule 08.11.2020


Ответы (5)


У VonC есть ответ, который вы ищете, расширение Rebase. Однако стоит потратить секунду или две на размышления о том, почему ни mq, ни rebase не включены по умолчанию в mercurial: потому что mercurial - это все о нестираемых наборах изменений. Когда я работаю так, как вы описываете, а это почти ежедневно, я беру вот такую ​​схему:

1. Start working on a new feature:
$ hg clone mainline-repo newfeature-123
do a few commits (M, N, O)

master A---B---C
                \
newfeature-123   M---N---O

2. Pull new changes from upstream mainline:
$ hg pull

master A---B---C---D---E---F
                \
newfeature-123   M---N---O

3. merge master into my clone so that my new feature 
can be developed against the latest upstream changes:
(from newfeature-123)
$ hg merge F

master A---B---C---D---E---F
                \           \
newfeature-123   M---N---O---P

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

А теперь иди и выбери ответ VonC, пока я убираю свою мыльницу. :)

person Ry4an Brase    schedule 20.04.2010
comment
Примечание: конечно, Git не точно позволяет вам переписывать историю, только чтобы легко создать новую (utcc.utoronto.ca/~cks/space/blog/tech/GitNewHistory). Добавляя RebaseExtension, Mercurial предоставляет точно такой же удобный способ заменить старую историю новой. Почему? Поскольку слияние не всегда является правильным ответом, особенно когда ваш набор изменений следует рассматривать как эволюцию поверх F, а не наоборот (P слит поверх O) - person VonC; 20.04.2010
comment
VonC, я согласен, слияние - не всегда правильный выбор, но я думаю, что разница в том, что каждый хочет, чтобы его история VCS могла рассказать им. Я думаю, что история должна всегда быть в состоянии ответить на такие вопросы, как "Что это было таким образом". Я пытался сначала интегрировать это, но это не сработало, и в то время я думал, что это бесполезно. Ученые ведут дневники в ручку с пронумерованными страницами, а разработчики программного обеспечения AFAIC должны сохранять каждый байт, который они когда-либо вводили. Перезапись истории, даже происхождения cset, но, конечно, CollapseExtension, HistEdit и т. Д. Нарушают это. Это полностью вопрос личного выбора. - person Ry4an Brase; 20.04.2010
comment
+1 на личный выбор. Поэтому в Git я использую rebase для тривиальных расхождений и merge для нетривиальных. Это позволяет мне сохранять историю слияний там, где я считаю важным, но большую часть времени сохранять лог чистым и линейным. - person Kos; 07.08.2012
comment
Также я делаю множество интерактивных перемещений, потому что я обычно сначала делаю множество небольших коммитов, затем присоединяю, помечаю и очищаю их, а затем объединяю их обратно (или переустанавливаю поверх) основной ветки. Мне нравится, что кодирование и управление изменениями - это отдельные шаги. - person Kos; 07.08.2012
comment
Если слияние когда-либо затуманивает мое видение, я просто использую параметр --no-merges, доступный в большинстве команд листинга cset, но, как мы все говорим, это полностью вопрос личных предпочтений как в git, так и в Mercurial. - person Ry4an Brase; 18.10.2013
comment
Сохранение каждого байта на пути философии разработки не совсем подходит для крупных проектов с открытым исходным кодом, где участники предлагают набор исправлений, а затем переделывают их на основе отзывов от сопровождающих. Затем в конечном итоге в основном репозитории проекта будет только правильная версия всех изменений со всеми связанными изменениями в одной фиксации. git interactive rebase действительно хорош для очистки рабочих изменений до последовательности коммитов, которые не оставляют дерево сломанным, и с сообщениями коммитов, отражающими то, что вы решите сказать после того, как закончите работу над всем этим. - person Peter Cordes; 15.12.2014
comment
Знание о том, что в какой-то момент вы допустили ошибку, никому не поможет за две недели. Несмываемые ревизии бесполезны. - person Tim Harper; 06.05.2016

Возможно, вы ищете Rebase Extension. (реализовано как часть SummerOfCode 2008)

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

Как добраться:

alt text

to:

alt text


Как прокомментировано ниже от steprobe:

В случае, если вы не вносите изменения и у вас есть две ветки в вашем репо, вы можете сделать ( с использованием keepbranches):

hg up newfeature-123 
hg rebase -d master --keepbranches

(--keepbranches: унаследовать исходное имя ветки.)

Mojca упоминает:

Мне нравится использовать hg rebase --source {L1's-sha} --dest {R2's-sha}, но я не знал, что могу добавить --keepbranches в конце.

Как проиллюстрировано ниже Джонатан Блэкберн:

 hg rebase -d default --keepbranches
person VonC    schedule 20.04.2010
comment
Я посмотрел на Rebase Extension, но мне все еще непонятно. Не могли бы вы объяснить, как сделать то, что я описал выше? - person jpswain; 20.04.2010
comment
В случае, если вы не вносите изменения и у вас есть две ветки в вашем репо, вы можете сделать: hg up newfeature-123, за которым следует hg rebase -d master --keepbranches - person steprobe; 26.05.2011
comment
Я считаю, что с rebase нет ничего плохого, это просто вопрос выбора. Проблема в том, что rebase злоупотребляют, и я с @ Ry4an по этому поводу не переписываю историю, чтобы вы могли знать, что и когда произойдет. - person Jorge Vargas; 01.08.2011
comment
@steprobe: спасибо за подсказку по использованию --keepbranches. Мне нравится использовать hg rebase --source {L1's-sha} --dest {R2's-sha}, но я не знал, что могу добавить --keepbranches в конце. Это упоминается в других ответах с более низким рейтингом, но было бы неплохо явно написать это и в этом ответе. - person Mojca; 22.02.2019
comment
@Mojca Нет проблем. Я соответствующим образом отредактировал ответ. - person VonC; 22.02.2019

Предполагая, что у вас современная установка Hg, вы можете просто добавить:

[extensions]
rebase = 

в ~ / .hgrc.

Затем вы можете использовать команды hg rebase, hg pull --rebase или hg help rebase.

person sblom    schedule 20.04.2010
comment
Просто чтобы добавить к этому с точки зрения команды, вам нужно выполнить: hg rebase -s o -d f - person Simple-Solution; 23.12.2013

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

Скажем, я начну с этого графика (созданного с помощью расширения graphlog. Серьезная любовь компьютерных фанатов к graphlog).

@  9a4c0eb66429 Feature 3 commit 2 tip feature3
|
| o  af630ccb4a80 default againagainagain  
| |
o |  98bdde5d2185 Feature 3 branch commit 1  feature3
|/
o  e9f850ac41da foo   

Если я нахожусь в ветке feature3 и хочу удалить ее из коммита againagainagain, я понимаю, что я бы запустил hg rebase -d default. Это дает следующий результат:

@  89dada24591e Feature 3 commit 2 tip 
|
o  77dcce88786d Feature 3 branch commit 1  
|
o  af630ccb4a80 default againagainagain  
|
o  e9f850ac41da foo  

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

В Git результат будет выглядеть так:

@  9a4c0eb66429 Feature 3 commit 2 tip
|
o  98bdde5d2185 Feature 3 branch commit 1 **feature3**
|
o  af630ccb4a80 default againagainagain
|
o  e9f850ac41da foo

Обратите внимание, что ветка feature3 все еще существует, две фиксации все еще находятся в ветке feature3 и не отображаются по умолчанию. Без сохранения ветки задачи я не понимаю, чем это функционально отличается от слияния.

ОБНОВЛЕНИЕ: я обнаружил флаг --keepbranches, поддерживаемый hg rebase, и рад сообщить, что все в порядке. Используя hg rebase -d default --keepbranches, я в точности копирую поведение Git, которого я так жаждал. Через пару псевдонимов я перебазирую как никому.

person Jonathan Blackburn    schedule 19.04.2013
comment
Только что обнаружил флаг --keepbranches при перебазировании. Проблема решена. Если бы это был мой код, я бы сделал его по умолчанию, но это только я. - person Jonathan Blackburn; 19.04.2013
comment
Я думаю, было бы полезно, если бы вы добавили эту информацию в свой ответ выше - мне потребовалось время, чтобы ее найти. - person HansMari; 21.04.2013

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

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

На странице x265 участников объясняется, как повторно зафиксировать набор изменений, которые вы ' мы работаем, чтобы подготовить их к отправке в проект x265. (Включая использование TortoiseHG для фиксации некоторых, но не всех изменений в отдельном файле, например, фрагмент разницы этапов / неэтапности git gui для фиксации).

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

Я предполагаю, что вы должны скопировать / вставить, а затем отредактировать сообщения фиксации из предыдущих итераций набора исправлений, который вы пересматриваете. Или, может быть, вы могли бы привить свои старые коммиты (выбор вишни на языке git), а затем изменить их один за другим, чтобы ваши старые сообщения о коммитах стали отправной точкой для редактирования.

person Peter Cordes    schedule 15.12.2014