M&A в IT-бизнесе. Эксперты ТОП-уровня о слиянии и поглощении. Регистрируйтесь!

Mercurial: основы

Продолжение, см. начало: Mercurial: введение в распределённые системы контроля версий

Одним из несомненных плюсов меркуриала является его интерфейс, который покажется знакомым каждому, кто хоть какое-то время работал с subversion в командной строке. Естественно, что отличий хватает (сам принцип работы совершенно иной), но наиболее часто употребляемые команды — очень похожи. Рассматривать я буду только командную строку — во-первых, я ею пользуюсь сам, во-вторых, ни один GUI не подходит и близко по возможностям, и, в-третьих, она значительно ближе «к телу» — проще понять, что, как и почему так работает.

Базовые принципы

Сразу в двух словах опишу модель данных в меркуриале (и большинстве других DVCS) — она несколько отличается от привычной по централизованным системам.

Ревизия (changeset) — это сущность, описывающая изменения в каких-либо файлах. Эта сущность хранит информацию о своём авторе, времени создания, изменениях в файлах (естественно ;) и о родительских ревизиях (которых может быть одна в случае обычной ревизии и две в случае слияния). Кстати, подсчёт 40-цифрового 16-ричного sha1-хеша, которым идентифицируется ревизия, учитывает все эти значения — таким образом каждая ревизия идентифицирует не только себя, но и всю свою историю.

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

Головы — это ревизии, у которых (ещё) нет детей, конечные точки графа.

При этом существуют две специальные ревизии — null (ревизия-родитель самой первой ревизии под номером 0) и tip (самая последняя ревизия, в случае наличия нескольких голов выбирается в зависимости от обстоятельств).

Основы работы

Скачать hg для Windows (под никсами, я думаю, каждый и так знает, как пользоваться менеджером софта) можно здесь, в довесок к этому дистрибутиву идёт GUI, которым вроде бы даже можно пользоваться. :) Сразу упомяну, чтобы не забыть, о необходимости настройки меркуриала. Для этого надо отредактировать конфигурационный файл, который находится в ~/.hgrc в случае *nix, и в %USERPROFILE%\mercurial.ini в случае Windows. Надо туда добавить пару строчек:

[ui]
username = Alexander Solovyov <piranha@gtv>

Я думаю, они говорят сами за себя. :) hgrc в настоящий момент — самый обычный ini-файл, знакомый, я думаю, каждому. :)

Всё начинается с того, что мы создаём репозиторий:

hg init repo

Если посмотреть внутрь директории repo, можно увидеть директорию .hg — это и есть сам репозиторий, в котором хранятся ревизии и настройки данного конкретного экземпляра (репозитория, простите за каламбур ;). Начать можно с добавления файлов и коммита первой ревизии:

cd repo
echo "something" > <a href="http://read.me" target="_blank">read.me</a>
hg add
hg ci -m "Initial revision"

Теперь можно просмотреть историю репозитория с помощью hg log:

changeset:   0:2add2e250fd2
tag:         tip
user:        Alexander Solovyov <piranha@gtv>
date:        Tue Jul 22 14:36:39 2008 +0300
summary:     Initial revision

Или склонировать его:

cd ..
hg clone repo repoclone

repoclone — абсолютно идентичен repo в плане наполнения, однако в нём уже появился файл .hg/hgrc, в котором записано, что путь по умолчанию (для забирания и отдавания изменений) — это предыдущий repo:

[paths]
default = /home/piranha/repo

Теперь, если мы сделаем изменения в обоих репозиториях, мы можем увидеть такую картину:

piranha@gtv ~/repoclone>hg incoming
comparing with /home/piranha/repo
searching for changes
changeset:   1:99a5a4fc7247
tag:         tip
user:        Alexander Solovyov <piranha@gtv>
date:        Tue Jul 22 14:40:51 2008 +0300
summary:     Another commit

piranha@gtv ~/repoclone>hg outgoing
comparing with /home/piranha/repo
searching for changes
changeset:   1:7cb00df3cf09
tag:         tip
user:        Alexander Solovyov <piranha@gtv>
date:        Tue Jul 22 14:41:21 2008 +0300
summary:     commit in clone

Команды incoming и outgoing показывают соответственно входящие (те, которых ещё нету в локальном репозитории) и исходящие (те, которых не хватает в удалённом репозитории) ревизии. Обратите внимание, что я не указывал путь к удалённому репозиторию — меркуриал в этом случае берёт его из пути по умолчанию (который можно увидеть раньше). Или ругается, в случае его отсутствия. :)

Merge

Сложившаяся ситуация подразумевает слияние — у нас появились две ветки разработки, значит пора применять merge:

piranha@gtv ~/repoclone>hg pull
pulling from /home/piranha/repo
...
added 1 changesets with 1 changes to 1 files (+1 heads)
(run 'hg heads' to see heads, 'hg merge' to merge)

piranha@gtv ~/repoclone>hg heads
changeset:   2:99a5a4fc7247
tag:         tip
parent:      0:2add2e250fd2
user:        Alexander Solovyov <piranha@gtv>
date:        Tue Jul 22 14:40:51 2008 +0300
summary:     Another commit

changeset:   1:7cb00df3cf09
user:        Alexander Solovyov <piranha@gtv>
date:        Tue Jul 22 14:41:21 2008 +0300
summary:     commit in clone

piranha@gtv ~/repoclone>hg merge
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)

piranha@gtv ~/repoclone>hg ci -m "merge"

piranha@gtv ~/repoclone>hg tip
changeset:   3:a81fdfac4695
tag:         tip
parent:      1:7cb00df3cf09
parent:      2:99a5a4fc7247
user:        Alexander Solovyov <piranha@gtv>
date:        Tue Jul 22 17:26:51 2008 +0300
summary:     merge

Что произошло? Мы вытянули (pull) отсутствовавшую ревизию из удалённого репозитория (получив при этом две ветки локально), посмотрели на головы (heads — разъяснено ниже), слили изменения и зафиксировали это коммитом (ci — алиас для commit).

Некоторые пояснения: heads — команда, которая демонстрирует наличие двух (т.е. двух разошедшихся веток разработки). merge сливает ветки и говорит о том, что относительно первого родителя у нас обновился 1 файл. Ну и tip показывает, что у получившейся ревизии есть два родителя. Итого картина репозитория оказывается вот такой:

piranha@gtv ~/repoclone>hg glog
@    changeset:   3:bd58c96d6690
|\   tag:         tip
| |  parent:      2:99a5a4fc7247
| |  parent:      1:7cb00df3cf09
| |  user:        Alexander Solovyov <<a href="mailto:piranha@piranha.org.ua">piranha@piranha.org.ua</a>>
| |  date:        Wed Aug 06 14:21:40 2008 +0300
| |  summary:     merge
| |
| o  changeset:   2:99a5a4fc7247
| |  parent:      0:2add2e250fd2
| |  user:        Alexander Solovyov <<a href="mailto:piranha@piranha.org.ua">piranha@piranha.org.ua</a>>
| |  date:        Tue Jul 22 14:40:51 2008 +0300
| |  summary:     Another commit
| |
o |  changeset:   1:7cb00df3cf09
|/   user:        Alexander Solovyov <<a href="mailto:piranha@piranha.org.ua">piranha@piranha.org.ua</a>>
|    date:        Tue Jul 22 14:41:21 2008 +0300
|    summary:     commit in clone
|
o  changeset:   0:2add2e250fd2
   user:        Alexander Solovyov <<a href="mailto:piranha@piranha.org.ua">piranha@piranha.org.ua</a>>
   date:        Tue Jul 22 14:36:39 2008 +0300
   summary:     Initial revision

Такие вот деревья hg рисует с помощью расширения graphlog. Описание его будет в продолжении этой статьи. Естественно, есть и графические аналоги для отображения графа ревизий.

Есть один момент, на который хотелось бы обратить внимание — у ревизии может быть максимум 2 родителя. Т.е. если у нас оказывается 3 головы, одним мержем их слить не получится — меркуриал обратит внимание на то, что голов много и неплохо бы явно указать, с какой из ревизий хочется слить текущую: hg merge -r rev.

Обмен данными по сети

Один из наиболее приятных моментов hg для меня — это использование абсолютно стандартных протоколов для обмена данными между репозиториями: http (и https), ssh или, на худой конец, аттачами в email.

При этом никаких усилий или отдельных демонов (я предполагаю, что если хочется использовать http — какой-никакой веб-сервер уже работает :)) не требуется. ssh работает вообще без всякой настройки, а http-часть идёт в комплекте и требует веб-сервера, могущего cgi/fastcgi/wsgi (на выбор). Протоколы работы по ним очень похожи — локальный и удалённый меркуриалы обмениваются bundle’ами (далее по тексту — бандл), сжатыми файлами с группой ревизий (должен заметить, что эффективность довольно неплоха — бандл полного репозитория примерно в 2 раза меньше, чем его .tar.bz2 архив).

Интересный момент: по ssh меркуриал может не только вытягивать и заталкивать изменения, но и клонировать в удалённый хост:

hg clone repo <a href="ssh://piranha.org.ua/repo" target="_blank">ssh://piranha.org.ua/repo</a>

Бывает полезно, когда сидишь за NAT’ом, да и вообще лень делать много лишних движений. :) Приятно, когда на той стороне оказывается уже настроенный hgweb и этот свежесклонированный репозиторий сразу оказывается опубликованным по http. :)

Правда, возможность работать по голому http/sftp (без меркуриала на удалённой стороне, как со статическими файлами) отсутствует, но как показывает практика соседних DVCS (и история самого hg), скорость такой работы настолько низка, что лучше даже и не пробовать.

Обмен изменениями по email в текущей инкарнации предлагает выбор из двух вариантов — мы либо шлём текстовый патч, либо бандл (описание — ниже по тексту) с нужными ревизиями. Первое позволяет просмотреть себя глазами, а второе гарантирует то, что применённые ревизии будут точно такими же, как отправленные. Однако в MyDeco была сделана версия команды отсылания изменений, которая слала одновременно и патч, и бандл — для удобства. :)

Рабочий процесс

Организация рабочего процесса — это, наверное, одна из самых замечательных особенностей DVCS. Распределённая система значительно меньше ограничивает полёт фантазии разработчиков, позволяя строить процесс в соответствии с их вкусом.

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

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

В главный репозиторий может отправлять изменения ограниченное количество людей — тимлиды (если их так можно назвать, все поделены на небольшие команды по 3-4 человека), релиз менеджер и т.п. Остальные же, при достижении какого-то рабочего состояния (починил баг, реализовал какую-то возможность, и т.п.) отправляет письмо тимлиду с текстовым диффом (для просмотра) и бандлом (для применения).

При этом любой разработчик может с помощью .htaccess (использовался Apache) у себя в домашней директории (конечно, точнее говоря — в ~/public_html/) может настроить свою собственную копию сайта, работающую на основе любого из своих репозиториев.

У подобной схемы организации работы существует как минимум 3 плюса:

  • В репозиторий откровенно плохой код не попадает (так как тимлид хоть как-то, но просматривает этот код);
  • Обмен кода между разработчиками происходит быстро и просто, с помощью отправления писем или использования hg serve (встроенный http-сервер), когда они находятся рядом;
  • Незаконченные, но требующие какого-то согласования возможности или баги можно легко продемонстрировать на своей собственной копии сайта, что помогает поддерживать репозиторий в более чистом виде.

Могу сказать с уверенностью, что эта схема действительно является заметно более удачной, чем традиционная работа с svn.

Особенности работы

Несмотря на то, что базовые команды действительно похожи на набор команд из svn, разница всё равно существенна. Поэтому далее я вкратце опишу те операции, которыми приходится пользоваться достаточно часто, без подробного расписывания каждой опции, потому что это можно легко увидеть, используя hg help command.

Как указывать ревизии

Большинство команд (все, где это имеет смысл) имеют опцию -r, с помощью которой можно указать, над какой конкретно ревизией (или группой ревизий) мы хотим произвести действие (логично, что по умолчанию — текущая).

Идентификатором ревизии может служить либо её порядковый номер (который не является чем-то стабильным и легко может поменяться при, например, отправлении своих ревизий в другой репозиторий), либо 16-ричный хеш sha1 длиной в 40 цифр, либо тег (tag, описаны ниже). Также существует три зарезервированных имени:

  • null, указывает на ревизию пустого репозитория, родительскую по отношению к ревизии 0;
  • tip, указывает на самую новую ревизию;
  • ., указывает на текущую ревизию.

Указание группы ревизий имеет синтаксис, аналогичный синтаксису python — начало:конец. Если начало не указано, оно равняется 0. Если не указан конец, он равняется tip. Если начало больше, чем конец, ревизии идут в обратном порядке. Можно отметить, что ревизии начало и конец включаются в отображаемые ревизии (т.е. 3:5 — это 3, 4 и 5, в отличии от питона, где это просто 3 и 4).

Создание ревизий и обмен ими

Как можно было заметить в описании слияния, для вытягивания новых данных в локальный репозитория служит команда pull. Её можно ограничить до какой-то определённой ревизии (с помощью опции -r rev), а можно сразу заставить сделать update (с помощью опции -u) — про это написано в следующем подразделе. Это аналог команды svn update, или, скорее, половина этой команды (только скачивание изменений).

Для того, чтобы отправить свои ревизии в удалённый репозиторий, используется команда push, которая также крайне проста в использовании, и аналогично может ограничиваться до какой-то ревизии, если не хочется публиковать историю полностью. Это, опять же, половина команды из svn — svn commit, а, точнее, та её часть, которая отправляет изменения в удалённый репозиторий.

Для того же, чтоб получить новые ревизии, используется команда commit. В случае hg она только создаёт ревизии локально, никак не оповещая об этом удалённые репозитории. В качестве параметров принимает имена изменённых файлов, которые следует внести в ревизию (при отсутствии параметров — вносит все файлы).

update/revert

Так как вся информация о ревизиях у нас хранится локально, то прыгать по ним можно быстро и безболезненно, для чего используется команда update — вторая половина update из svn. Она «обновляет» (в кавычках, потому что можно «обновиться» и на ревизию старше текущей) рабочую копию до какой-то определённой ревизии (по умолчанию — до последней). Все незакоммиченные изменения будут слиты с новой ревизией рабочей копии (или проигнорированы, если указать опцию -C). Отличие от варианта из svn заключается в том, что эта команда всегда работает только с локальными данными (не делая запросов к удалённому репозиторию).

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

Отмена ревизии

Отмена изменений, сделанных в какой-то ревизии — достаточно спорная тема, учитывая философию неизменности истории. Но если всё же в репозиторий попал коммит с, например, неправильным автором, под рукой есть команда rollback, которая откатывает последнюю транзакцию (список команд есть в помощи по команде, commit там присутствует). При этом все локальные изменения, если они были, теряются (рабочая копия изменяется до того состояния, которое было на момент коммита).

backout — команда, подходящая к вопросу отмены ревизии с другой стороны. Она создаёт ревизию, ответвляющуюся от исходной, в которой отменены все изменения (или не все, указывается фильтрами, как в revert), после чего ревизия сливается с текущей веткой разработки.

Просмотр истории

Просмотр истории в меркуриале — вещь куда более весёлая, чем в svn, потому что происходит быстро и даёт в руки достаточное количество инструментов для фильтрации и настройке вывода.

Фильтровать можно многое — показывать (или скрывать) ревизии, содержащие в себе изменения какого-то конкретного файла, показывать/скрывать ревизии-слияния, ограничивать по дате, искать ключевое слово (в авторе/описании ревизии)... log также может показывать диффы этих ревизий.

Ещё к теме о просмотре истории можно упомянуть cat — вывод файла определённой ревизии, можно в другой файл (поддерживает форматирование имени), tip — краткий аналог log -r tip, id — совсем-совсем сокращённый (и по выводу тоже) аналог log -r .

Что мне нравится в меркуриаловском выводе лога по сравнению с таковым в svn — это возможность быстрого поиска и шаблоны.

С помощью log -k some-criteria можно в считанные доли секунды увидеть все ревизии, которые содержат этот критерий в описании или в имени автора.

Вторая приятная штука — шаблоны вывода. Они позволяют настроить внешний вид всех операций, которые выводят список ревизий. К примеру, я часто использую sheads — это мой алиас для heads, который использует шаблон для сокращения вывода, выглядит вот так:

sheads = heads --template '{date|shortdate} [{rev}:{node|short}] {author|person}: {desc|firstline}\n'

Аналогично я использую, например, slog вместо log — намного короче и проще быстро просмотреть, к чему дело идёт. :-) Мне кажется, что синтаксис довольно прост и понятен с первого взгляда — в фигурных скобках ключевое слово, через | к нему — фильтры. Фильтры — это небольшие функции на питоне, которые модифицируют данные — всё логично. Фильтры, что естественно, можно строить в цепочки. Список всех ключевых слов можно увидеть в hgbook, список фильтров — там же, ниже по тексту.

Поиск по репозиторию

Бывают такие ситуации, когда поиска по описанию и имени автора явно недостаточно, и надо найти какой-то кусочек кода, уже затерявшийся в седых глубинах ревизий. В такие моменты на помощь приходит hg grep — grep, который ищет не только в ширину (по разным файлам), но и в глубину (по разным ревизиям).

Сказать о нём больше особо нечего — кто не знает, что такое grep? :-) Разве что упомянуть о том, что ограничивать поиск можно, как и многие другие операции, по ревизиям и по файлам.

Входящие/исходящие изменения

Вот этих двух конкретных команд — incoming и outgoing — мне часто не хватает при работе с git’ом. Первая показывает список ревизий, которые существуют в удалённом репозитории, но не существуют в локальном. Последняя — показывает ревизии, которые существуют в локальном репозитории, но не существуют в удалённом.

Удобно, если ещё неизвестно, стоит ли обновляться. :)

Игнорирование файлов

Список игнорируемых файлов находится не где-то в метаданных, а в обычном версионируемом файле .hgignore, который лежит в корне репозитория (не в .hg/, а рядом). Поддерживает переключение между двумя синтаксисами в одном файле, один из которых — регулярные выражения, второй — подстановки из шелла.

Теги

Теги в меркуриале реализованы в виде крайне простой сущности — это обычный версионирующийся файл под названием .hgtags в корне репозитория, в котором хранятся пары «sha1-hash tag-name». hg tag tagname создаст новый тег, -r revspec позволяет явно указать ревизию, которую надо затегать. Создание тега — это появление нового коммита.

Теги могут быть локальные (создаются с помощью указания опции -l), тогда они не коммитят ничего в репозиторий, хранятся в файле .hg/localtags и между репозиториями не передаются.

Bundle

bundle я уже упоминал раньше, когда рассказывал про обмен ревизиями по email. Это такая упакованная (по умолчанию — с помощью bzip2) группа ревизий, которая занимает очень мало места (интересный факт — несмотря на то, что у git’а сам репозиторий занимает меньше места, чем у hg, бандлы получаются большего размера). Очень мало — в прямом смысле слова, при размере репозитория в 5.4 Мб (byteflow), полный бандл занимает 1.3 Мб.

Полезен для хранения «консервированных» репозиториев, а также для переноски на всяких флешках (записать один крупный файл намного проще, чем много мелких).

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

piranha@gtv ~>hg clone byteflow.bun byteflow
requesting all changes
adding changesets
adding manifests
adding file changes
added 906 changesets with 2554 changes to 804 files
updating working directory
478 files updated, 0 files merged, 0 files removed, 0 files unresolved

Точно так же работают hg pull и hg incoming.

Недостатки

Вот мы и подобрались к самой спорной части статьи. :) Спорная она потому, что достаточно индивидуальная, и для разных людей разные особенности оборачиваются плюсами или минусами: вот товарищ bialix часто пытается показать на такую проблему, как отсутствие встроенной утилиты для слияния. Для меня же это явное преимущество — ни под каким соусом мне не пытаются пропихнуть замену-недоделку для моего любимого Ediff, плюс усилия разработчиков не распыляются на создание утилиты, в общем-то связанной довольно посредственно с самой системой контроля версий.

Но всё-таки кое-какие недостатки я для себя вижу, как снаружи, так и внутри. Из внутренних проблем самая, наверное, яркая — это то, что переименование файла по сути дела копирует его, оставляя пометочку, что история его продолжается из какого-то предыдущего места дислокации. Для пользователя неудобствами не грозит, кроме случаев, когда этот файл занимает много мегабайт — переименование по сути дела увеличит репозиторий на размер этого файла. В большинстве случаев мелочь, но неприятная.

Из внешних же самый неприятный — скорее не недостаток, а отсутствие реализации. Было бы очень неплохо иметь для веток в графе репозитория имена — т.е. то, что в git’е называется named branch. На самом деле, есть уже кое-какая реализация этой штуки — hgbookmarks, но не завершённая — их ещё нельзя передавать по сети.

Наверняка со стороны приверженцев git’а можно услышать об отсутствии rebase (это уже явно совсем не базовый уровень, но всё-таки :-)), но, во-первых, он эмулируется с помощью mq (о Mercurial Queues — в продолжении этой статьи), а во-вторых, есть уже работающий проект GSoC.

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

  • пропускать на сервере только те ревизии, которые сделаны текущим пользователем
  • использовать gpg для подписи изменений

Первое несколько урезает распределённость VCS (возможность обмениваться ревизиями с другими людьми улетучивается абсолютно), а вторая требует разбирательств, обучения людей и т.п. Но в принципе, такое может случиться только в очень специфическом окружении. :)

Summary

Несмотря на то, что последует ещё как минимум одно продолжение, мне кажется, что данной статьи уже достаточно, чтоб начать продуктивно работать с меркуриалом. Для тех, кому не терпится узнать больше прямо сейчас, есть более подробный документ, даже книга — hgbook. К сожалению, она ещё не дописана и тем более не переведена на русский, но уже достаточно хорошо наполнена информацией.

Кстати о продолжении — оно будет посвящено расширениям меркуриала. А точнее — тем из них, которые используются (практически) ежедневно: bisect, mercurial queues, graphlog, record, а также альтернативным (консоли) интерфейсам.

См. продолжение: Mercurial: расширения.

  • Популярное

32 комментария

Подписаться на комментарииОтписаться от комментариев Комментарии могут оставлять только пользователи с подтвержденными аккаунтами.

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

Ни разу не профессионал, по сему думаю моё незнание будет простительно.

У многих фреймворков структура как раз определяется набором папок, в том числе. Так что же плохого в том, что бы насоздавать необходимые папки и сказать разработчикам: ты пишешь тут, а ты — в этой папке?

> Я набросал структура будущего проекта, закомитил и пустил в разработку нескольким разработчикам, что бы не было всяких неувязок.Структура будущего проекта == стопка пустых директорий? Интересно вы набрасываете структуру... Ну, тогда мне нечего сказать, всë плохо.

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

> Но в фреймверках есть пустые папки. Например для кеша. Теперь если я захочу использовать файловый кеш, то я должен помнить что мне нужно создать пустую папку.Зачем помнить? Есть специализированные утилиты для деплоймента и, повторюсь еще раз, система контроля версий ей не является. Есть make, scons, waf, еще куча всяких разных.> Но мое мнение таково — система хранения версий должна хранить все так как есть.Ну, такая вот фигня, хранит только данные, а за директориями не следит...

на счет логики с пустыми папками немного преувеличил. Но в фреймверках есть пустые папки. Например для кеша. Теперь если я захочу использовать файловый кеш, то я должен помнить что мне нужно создать пустую папку. Да и вообще во фреймверке есть всегда определенная структура директорий которой нужно придерживаться. Получается всегда нужно это помнить? Нет не нравится мне эта идеология. Может я не догоняю этой философии конечно в полной мере. Но мое мнение таково — система хранения версий должна хранить все так как есть.

Можно создавать файлики.empty какие-нибудь в этих папках.1. Система контроля версий — это не билд-тул. Есть специализированные.2. Завязывание логики на пустые папки — это не смешно.;) 3. Он вообще ни за какими папками не следит, только за файлами. Как, впрочем, и гит. Нет такой сущности — «папка», это всего лишь хранилище файлов, которые лежат по какому-то пути.

папка — это сущность, как это так он за ними не следит?, а как же тогда мне вылить из репа код чтобы он работал? скриптами дописывать папки пустые:)? каким тогда способом сказать системе — не используй эту «модную» фичу, а сделай так как мне надо? Флагов у clone таких нет, я вроде посмотрел.

Хорошо. А как же тогда быть если у меня на папках завязана логика, пусть даже на пустых. Нет папки нарушается логика. Как тогда быть?

> Второй более серьезный — в клонированном репозитории не появляются пустые папки.hg не следит за директориями вообще. Это не баг, это фича.

C первым вопросом разобрался — протупил. Второй более серьезный — в клонированном репозитории не появляются пустые папки. Т.е. если в локальном репе было много папок, одна из них пустая, то при клонировании репа на сервер и последующем hg update на сервере этой папки нет. Если сделать в локальном репе hg status — пустота. По-моему это баг.

странно, но у меня так не заработало hg clone repo ssh://piranha.org.ua/repoзаработало с указанием абсолютного пути hg clone repo ssh://piranha.org.ua//var/repo

hg fetch ничего более умного чем слова merge не оставляет.Типа привычка — merge одно слово — без кавычек быстрее клацать (не забывай для ввода двойных кавычек shift нада нажать).

> Кавычки ставить не обязательноЭто привычка, ставить кавычки для строки. Я не всегда знаю, что я собрался написать, когда открываю кавычку для мессаги.

> hg ci -m “merge” Кавычки ставить не обязательно (http://www.mpi-inf.mpg.de/~uwe...)

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

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

На forest всё-таки стоит посмотреть.

удобнее уже тогда будет хранить отдельно репозитории

Репозитории удобнее хранить так, чтоб потом их легко было найти и использовать. А уж какая это будет система — не так важно.:) В двух соседних директориях можно положить — и какие потом проблемы с поиском того, который нужен?

Части никак не связаны между собой, поскольку они хранятся в отдельных репозиториях, представляющих собой целостную единицу хранения и транспортировки. Это как запаковать части мясорубки в отдельные коробки.> соответствующий репозиторий, который может (и часто будет) храниться где-то в другом местеВ таком случае возможны организации хранения по другим признакам. Если клиент и сервер написаны на C++, а сайт поддержки — на JSP, а в наличии у меня куча простоп проектов на C++ и JSP, причем каждый упакован отдельно (в случае Меркуриал) и от других репозиториев не зависит, то удобнее уже тогда будет хранить отдельно репозитории, относящиеся к C++ исходникам, а отдельно — к JSP исходникам. Таким образом C-программисты будут знать где лежат их исходники, а джаверы — где их.

Проект логически получается разбитым и все три части не связаны друг с другом никак.

Первое — верно, второе — нет. Почему никак не связаны-то?

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

Но почему оно будет хранится в другом месте? Оно будет лежать рядом, потому что это логично и удобно.

Мож что-то типа svn: external?

Ну да, и это что-то называется forest.

Мож что-то типа svn: external?

Просто хранить их всех трёх в разных репозиториях, и чекаутить по отдельности.

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

Еще документация (для самых маленьких): A Gentle Introduction to Using TortoiseHG on Windows.

познавательнокстати немного гуя есть и в самом меркуриале, а именно команда qct для коммита:)

Да, TortoiseSVN более продвинутая, чем TortoiseHG. Чисто потому, что большинство людей, которые делают саму систему, обычно используют командную строку, и потому у них отсутствует главный стимул для разработки гуи-морды. А её делают те люди, кому она нужна -, а таких среди тех, кто может её делать, значительно меньше, чем тех, кому она не нужна.Потому развивается гуй не так бурно, как сама система.

TortoiseSVN мне показалась намного более продвинутой TortoiseHG, или для TortoiseHG нужно еще какие-то расширения ставить?

1) TortoiseHG вполне приятная утилита, конечно она урезаннее чем cmd-интерфейс, но в большинстве случаев пользоваться ею под Windows удобнее чем просто голой командной строкой.

Ну это дело вкуса. Я предпочитаю командную строку как минимум по привычке.:)

2) Насколько я смотрел по Меркуриалу, в нем нет возможности хранить модули и чекаутить их отдельно. В стиле, если мой сетевой проект состоит из клиента, сервера и веб-сайта поддержки, то нет нормальной возможности погрузить весь проект в репозиторий, а потом чекаутить дизайнеру на компьютер только веб-сайт, а программистам — исходники клиента и сервера.

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

3) А кто пользуется системой хранения версий дома — просто чтобы свои личные проекты версионированно хранить на одном компьютере и бэкапить — поделитесь, как вы это делаете?

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

1) TortoiseHG вполне приятная утилита, конечно она урезаннее чем cmd-интерфейс, но в большинстве случаев пользоваться ею под Windows удобнее чем просто голой командной строкой.2) Насколько я смотрел по Меркуриалу, в нем нет возможности хранить модули и чекаутить их отдельно. В стиле, если мой сетевой проект состоит из клиента, сервера и веб-сайта поддержки, то нет нормальной возможности погрузить весь проект в репозиторий, а потом чекаутить дизайнеру на компьютер только веб-сайт, а программистам — исходники клиента и сервера.3) А кто пользуется системой хранения версий дома — просто чтобы свои личные проекты версионированно хранить на одном компьютере и бэкапить — поделитесь, как вы это делаете? Я работаю дома под Windows, программирую на C++, Delphi, PHP, JS и еще несколько языков. Организовал на Subversion центральный репозиторий, куда добавил папки под каждый вид проектов (CPP, Delphi, PHP и т.д.). Сами проекты хранятся в разных местах на диске — делаю в них коммит — они попадают в центральный репозиторий. Временами же сам центральный репозиторий сохраняю на диск. Удобно тем, что все значимые для меня исходники собраны в одном месте, именно поэтому распределенные Меркуриал и Гит для дома мне не подошли. До SVN стояла CVS (CVSNT), но она портила исходники — у в ряде файлов в делфи и си хранились кодовые строки с неалфавитными символами, так CVSNT на каком-то из них стопорила и отрезала весь дальнейший кусок файла. С SVN такой проблемы нет.Хотелось бы услышать как кто еще реализовал локальное домашнее хранение исходников.

Хех, а я никогда и не смотрел на русские доки на офсайте... Как будет время, попробую заняться.:)

Я немного переводил туториал на офсайте, было бы хорошо, если бы кто-то помог.А то времени свободного не очень много

Я тут подумал... Вот, на всякий случай, мой конфиг меркуриала. Вдруг кому-то интересно будет.

Из граблей, на которые я уже наступил: 1. формат.hgignore несовместим с svn; требуется указание «syntax: glob» 2. hg convert записывает историю в отдельный бранч, не сразу сообразил как перенести их не default

Сегодня утром закончил перевод codebase сайта developers.org.ua на меркуриал, не без Сашиных советов. Trac уже работает, пошел чинить deployment.;)

Подписаться на комментарии