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

207

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

1. Начните работать над новой функцией:
$ git co -b newfeature-123 # (локальная ветка разработки функций)
сделать несколько коммитов (M, N, O)

мастер A --- B --- C
                \
newfeature-123 M --- N --- O

2. Вытащите новые изменения из основной ветки разработки:
$ git pull
(мастер обновлен с помощью ff-коммитов)

мастер A --- B --- C --- D --- E --- F
                \
newfeature-123 M --- N --- O

3. Перебазировать мастер, чтобы моя новая функция 
могут быть разработаны с учетом последних изменений в основной ветке разработки:
(из newfeature-123)
$ git rebase master

мастер A --- B --- C --- D --- E --- F
                            \
newfeature-123 M --- N --- O


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

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

hg up -CF  
hg branch -f newfeature-123  
трансплантация ртути -a -b newfeature-123 

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

В основном проблема в том, что я в конечном итоге с этим:

мастер 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 до F
hg ветка newfeature-123
hg qpush -a
hg qdel -r qbase: qtip

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

мастер A --- B --- C --- D --- E --- F
                            \
newfeature-123 M --- N --- O

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

$ git rebase master

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

jpswain
источник
7
«это нехорошо, потому что оно оставляет после себя локальные нежелательные коммиты, которые следует отбрасывать». - на самом деле, Git делает то же самое. Он не изменяет и не удаляет коммиты в исходной ветке, он просто создает новые, которые применяют тот же набор изменений поверх мастера. Вы по-прежнему можете получить доступ к старым, используя их, git reflogи они не исчезнут полностью, пока не соберет мусор. Если вы хотите хранить их в именованной ветке, чтобы вам не приходилось использовать reflog, просто сделайте это git branch feature-123_originalперед ребазингом.
MatrixFrog
5
Случайный вопрос: вы сами рисовали наборы изменений / ветки или есть инструмент, который это делает?
Амир Рахум
2
Просто сделал их сам с TextWrangler установленным на «перезапись».
jpswain

Ответы:

235

У 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, пока я убираю свою мыльницу. :)

Ry4an Brase
источник
18
Примечание: от курса, Git не точно позволит вам переписать историю, только чтобы создать новый легко ( utcc.utoronto.ca/~cks/space/blog/tech/GitNewHistory ). Добавляя RebaseExtension, Mercurial предоставляет точно такой же удобный способ заменить старую историю новой. Зачем? Потому что слияние не всегда правильный ответ, особенно когда ваша ревизия должна рассматриваться как эволюция сверху F, а не как обратная (P объединена поверх O)
VonC
19
VonC, я согласен, слияние не всегда является правильным выбором, но я думаю, что разница в том, что нужно, чтобы история VCS могла им рассказать. Я думаю, что история всегда должна быть в состоянии ответить на такие вопросы, как «Как я пытался интегрировать ее сначала, но это не сработало, и я думал, что в то время это было бесполезно». Ученые хранят журналы в ручке с пронумерованными страницами, а разработчики программного обеспечения AFAIC должны сохранять каждый байт, который они когда-либо набирали. Переписывание истории, даже происхождение cset, но, конечно, CollapseExtension, HistEdit и т. Д. Нарушают это. Это полностью вопрос личного выбора.
Ry4an Brase
14
+1 за личный выбор. Следовательно, в Git я использую rebase для тривиальных расхождений и сливаю для нетривиальных. Это позволяет мне сохранять историю слияний там, где я чувствую, что это важно, но поддерживать журнал чистым и линейным большую часть времени.
Кос
16
Также я делаю тонны интерактивных перебазировок, потому что сначала я делаю много небольших коммитов, затем присоединяюсь, маркирую и очищаю их, затем объединяю их с основной веткой (или перебазирую поверх). Мне нравится кодирование и управление изменениями, чтобы быть отдельными шагами.
Кос
6
Философия «сохранить каждый байт на пути разработки» не совсем подходит для крупных проектов с открытым исходным кодом, где участники предлагают набор исправлений, а затем переделывают их на основе отзывов сопровождающих. Затем, в конечном итоге, главный репозиторий проекта имеет правильную версию всех изменений со всеми связанными изменениями в одном коммите. Git Interactive ReBase действительно хорош для очистки рабочих изменений в последовательности коммитов, которые не оставляют дерево сломанным, и с сообщениями о коммитах, отражающими то, что вы решили сказать после того, как закончите работу над всем этим.
Питер Кордес
104

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

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

Получение от :

альтернативный текст

чтобы:

альтернативный текст


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

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

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

( --keepbranches: Унаследовать оригинальное имя ветви.)

Мойка упоминает:

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

Как показано ниже на Jonathan Blackburn :

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

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

[extensions]
rebase = 

до ~ / .hgrc.

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

sblom
источник
2
Просто добавить к этому в терминах команды, то вам нужно будет выполнить: hg rebase -s o -d f
Simple-Solution
21

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

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

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

Если я нахожусь в ветке feature3 и хочу перебазировать ее из коммита снова, я понимаю, что я бы запустил 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, которое я жаждал. Пару псевдонимов позже, и я перебираю, как никто другой.

Джонатан Блэкберн
источник
7
Только что обнаружил флаг --keepbranches на rebase. Задача решена. Если бы это был мой код, я бы сделал его по умолчанию, но это только я.
Джонатан Блэкберн
1
Я думаю, было бы полезно, если бы вы добавили эту информацию в свой ответ выше - мне понадобилось время, чтобы найти ее.
HansMari
3

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

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

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

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

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

Питер Кордес
источник