Как Mercurial работает со многими разработчиками? - PullRequest
14 голосов
/ 05 июля 2010

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

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

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

Когда они фиксируют, у нас теперь есть две ветви, а затем с 14 людьми, мы быстро получим 10+ (может быть, не 14 ...) ветвей, которые необходимо объединить с настройками по умолчанию.

Или ... Что я здесь не вижу? Возможно, это не проблема?


Редактировать : Я вижу некоторую путаницу относительно того, о чем я здесь на самом деле спрашиваю, поэтому позвольте мне уточнить.

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

Так что это не так.

Что мне интересно, так это то, как эти проекты с открытым исходным кодом управляют такой чистой историей. Для меня не важно (как удивился один комментарий), что история чиста, я имею в виду, мы делаем работаем параллельно, что хранилище способно отразить это, тем лучше (на мой взгляд) Однако у этих репозиториев, на которые я смотрел, этого нет. Похоже, что они работают по модели Subversion, где вы не можете выполнить коммит до обновления и слияния, и в этом случае история представляет собой одну прямую линию.

Так как они это делают?

Они «перебазируют» изменения так, что они следуют последнему совету ветви, даже если они были изначально зафиксированы в истории ветви? Пересадка наборов изменений, чтобы они казались «зафиксированными в основной ветке с самого начала?»

Или проекты, на которые я смотрел, были такими медленными (на данный момент, я не слишком давно смотрел в историю) на добавление новых вещей, которые на самом деле работали только по одному человеку за раз?

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

Ответы [ 6 ]

6 голосов
/ 05 июля 2010

Или ... Что я здесь не вижу? Возможно, это не проблема?

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

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

Давайте рассмотрим пример:

у вас есть:

[branch 1]  [branch2]
        \    /
         \  /
        [base]

Редактировать : для ясности ответвление Я имею в виду здесь неназванные ответвления.

Если у вас есть файл, измененный в branch 1, но тот же файл в branch 2 такой же, как в base, то выбирается версия в branch 1. Если файл изменяется как в branch 1, так и branch 2, то файлы объединяются построчно с использованием одного и того же алгоритма: если строка 1 в файле1 в branch 1 отличается от строки 1 в файле1 в base, но branch 2 и base имеют строку 1, равную, выбирается строка 1 в branch 1 (и так далее, и так далее).

Для строк, которые изменяются в обеих ветвях, Mercurial прерывает процесс автоматического слияния и предлагает пользователю выбрать, какие строки использовать, или редактировать строки вручную.

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

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

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

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

5 голосов
/ 05 июля 2010

Я разработчик Mercurial, поэтому позвольте мне объяснить, как мы / я это делаем.

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

Что касается моих собственных изменений, я использую rebase или mq , чтобы линеаризовать вещи, прежде чем нажимать их, снова, чтобы сохранитьистория опрятная.Это в основном вопрос выполнения

hg push  # abort: creates new remote head
hg pull
hg rebase
hg push

Вы можете комбинировать тягу и ребаз, если хотите (hg pull --rebase), но мне всегда нравилось делать один шаг за раз.

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

5 голосов
/ 05 июля 2010

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

Редактировать : Так как Im ожидает компиляции , здесь следует конкретный примериз того, что я имею в виду:

> hg init
> echo test > a.txt
> hg addremove && hg commit -m "added a.txt"
> echo test > b.txt
> hg addremove && hg commit -m "added b.txt"
> hg update 0 # go back to initial revision
> echo test > c.txt
> hg addremove && hg commit -m "added c.txt"

Запуск hg glog теперь показывает эту (расходящуюся) историю с двумя ветвями:

@  changeset:   2:c79893255a0f
|  tag:         tip
|  parent:      0:7e1679006144
|  user:        mizipzor
|  date:        Mon Jul 05 12:20:37 2010 +0200
|  summary:     added c.txt
|
| o  changeset:   1:74f6483b38f4
|/   user:        mizipzor
|    date:        Mon Jul 05 12:20:07 2010 +0200
|    summary:     added b.txt
|
o  changeset:   0:7e1679006144
   user:        mizipzor
   date:        Mon Jul 05 12:19:41 2010 +0200
   summary:     added a.txt

Сделайте ребазинг, сделав ревизию1 на ребенка 2 вместо 0:

> hg rebase -s 1 -d 2

Теперь давайте снова проверим историю:

@  changeset:   2:ea0c9a705a70
|  tag:         tip
|  user:        mizipzor
|  date:        Mon Jul 05 12:20:07 2010 +0200
|  summary:     added b.txt
|
o  changeset:   1:c79893255a0f
|  user:        mizipzor
|  date:        Mon Jul 05 12:20:37 2010 +0200
|  summary:     added c.txt
|
o  changeset:   0:7e1679006144
   user:        mizipzor
   date:        Mon Jul 05 12:19:41 2010 +0200
   summary:     added a.txt

Presto!Одна линия.:)

Также обратите внимание, что я не сделал слияние .Когда вы сделаете ребазинг таким образом, вам придется иметь дело с конфликтами слияния и всем таким же образом, как если бы вы сделали слияние.Потому что именно это и происходит под капотом.Поэкспериментируйте с этим в небольшом тестовом репо.Например, попробуйте изменить файл, добавленный в revision 0, а не просто добавить больше файлов.

3 голосов
/ 05 июля 2010

Да, нам нужно объединить и чтобы избежать заголовков в главном хранилище, разработчик должен объединить дочерние хранилища.

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

3 голосов
/ 05 июля 2010

Ядро Linux хранится в тысячах репозиториев и, вероятно, в миллионах ветвей, и это, похоже, не представляет проблемы. Для больших проектов вам нужна стратегия репозитория (например, стратегия диктатора-лейтенанта), но наличие множества ветвей является основной сильной стороной современных DVCS и вовсе не является проблемой.

2 голосов
/ 05 июля 2010

Я не знаю, как работает команда TortoiseHg, но вы можете использовать расширение Mercurial , чтобы «отсоединить» ветку и опустить ее на верхушку наконечника, создав одну ветвь.1003 *

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

...