Здравствуйте, уважаемые коллеги.
На форуме неоднократно поднимался вопрос об использовании систем управления версиями (СУВ, VCS - version control system) при разработке под Lotus.
В этой небольшой заметке я хочу поделиться своим опытом работы с СУВ.
Замечу, что у меня нет опыта по-настоящему командной разработки ПО под Lotus. Модули (отдельные БД) у нас пишутся разными программистами, межмодульное взаимодействие согласовывается. Итак, первый вопрос - зачем, по сути, разработчику-одиночке СУВ?
<div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">1. Почему СУВ</div></div><div class="sp-body"><div class="sp-content">
В настоящее время я занимаюсь разработкой некой системы на Lotus Domino/Notes. Система не коробочная, она настраивается для каждого заказчика, причем обойтись "настроечными" документами нет никакой возможности.
Как велась разработка в до-СУВ эпоху: выделялась некая общая базовая часть системы ("ядро") в один или несколько шаблонов, с них наследовались шаблоны для каждого заказчика. Такая схема, наверняка, многими используется. Недостатки такого подхода таже всем известны. Это, во-первых, дублирование элементов дизайна (не только кода), когда некая "фича" используется несколькими заказчиками и не входит в ядро. Или входит в ядро, но у некоторых заказчиков она несколько изменена и не наследуется с базового шаблона - по сути, дублируется. Во-вторых, проблемы при обновлении дублируемых элементов: как бы не забыть обновить везде и не потерять кастомное поведение. Есть и другие проблемы, но дублирование и производные от него - это, на мой взгляд, самое страшное.
Чем здесь может помочь СУВ? Автоматизацией дублирования. Создаем базовый шаблон и связанный с ним репозитарий on-disk проекта. Это может быть и не "наибольшая общая часть" системы (то самое "ядро"), а шаблон первого/самого важного/самого "фичастого"/и т. д. и т. п. заказчика. Репозитарий клонируем одной командой необходимое число раз. С каждого такого "клона" восстанавливаем ntf(nsf)-шаблон и вносим необходимые правки. Дальнейшее распространение изменений (новые "фичи", исправления ошибок и пр.) происходит практически при помощи нескольких простых команд.
О проблемах использования СУВ будет сказано ниже. А сейчас -
<div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">2. Выбор СУВ</div></div><div class="sp-body"><div class="sp-content">
Я рассматривал только две системы: Mercurial (hg) и Git. Естественно, под Windows. Желательно, с GUI. GUI-надстройки были TortoiseHg и TortoiseGit.
Очень важный момент, который повлиял на выбор СУВ, - это наличие элементов дизайна с названиями на русском языке. На дворе 2012 год, и неумение инструмента работать с файлами с произвольными именами, по-моему, просто неприлично.
Не буду тянуть кота за хвост, а скажу сразу, что в итоге я остановился на git в консольном (!) варианте. Причина одна - то самое неприличное неумение инструмента "готовить" русские имена файлов.
Начал я с более понравившегося мне инструмента - Mercurial и его GUI-оболочки TortoiseHg. Выбор был в пользу hg еще и потому, что есть плагин для дизайнера. (К слову, отсутствие аналога для git совершенно не мешает. Да и пользовался я плагином только для commit-ов. Все остальные действия делал внешними инструментами.) Работал я с TortoiseHg довольно продолжительное время, пока не столкнулся с конфликтом слияния элемента дизайна с русским названием.
Мой типичный сценарий работы такой (подробнее будет ниже):
1) внесение изменений в базовый шаблон;
2) commit (фиксация) изменений в vcs;
3) pull (вытягивание) изменений из базового репозитария в производный;
4) при необходимости - разрешение конфликтов слияния (пользовался штатным в TortoiseHg инструментом KDiff3) и commit изменений в производном репозитарии;
5) синхронизация дизайнером on-disk версии и nsf-версии, выборочная визуальная проверка результата.
И вот однажды изменения в форме, допустим, "Документ" не пришли во второй шаблон. Это заставило разобраться, что происходит. После гуглёжа и экспериментов я пришел к выводу, что с hg пора расставаться.
Если интересно, как воспроизвести проблему слияния файлов с русскими именами, то я напишу отдельным комментарием. А сейчас посмотрим, каким образом дизайнер работает с on-disk проектами.
<div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">3. Особенности Lotus</div></div><div class="sp-body"><div class="sp-content">
Domino Designer 8.5.3 (и 8.5.2) умеет создавать on-disk версию БД и синхронизировать ее с nsf-версией. Он также умеет создавать nsf-версию БД по on-disk версии.
Создайте on-disk версию какой-нибудь базы. (Для Designer 8.5.3 - правой кнопкой на БД в навигаторе, меню Team Development\Set Up Source Control for this Application...)
Дизайнер выгрузит все документы дизайна в файловую систему и аккуратно разложит их по каталогам. Файлы элементов дизайна представляют собой xml-документы, те же самые, что создаются при DXL export.
Помимо собственно дизайна элемента, xml-документ содержит массу метаданных: ReplicaID БД, NoteID и UNID документа дизайна, ревизия документа - sequence, даты создания/измения и т. д. Исключение здесь - Lotus Script библиотеки. Для них код сохраняется в одном файле, а метаданные - в другом.
Наличие метаданных в файлах документов дизайна - это большая и самая главная проблема использования СУВ при разработке под Lotus. Метаданные - это причина совершенно необоснованных (с точки зрения здравого смысла) конфликтов слияния.
Создали nsf-проект по on-disk проекту - получите новые ReplicaID во все элементы дизайна. И дата изменения тоже будет новая.
Сохранили элемент дизайна в дизанере - получите следующий sequence number в соответствующем файле. И дата изменения тоже обновится.
Используете таблицы для верстки форм? Изменили размер окна дизанера (если оно не распахнуто на весь экран) или другим образом изменили ширину области дизанера, в которой отображается форма, - при сохранении формы получите изменение атрибутов refwidth всех элеметов table.
И теперь, если были внесены изменения в один и тот же элемент дизайна в базовом и производном шаблоне, то при слиянии получите конфликты "на пустом месте", хотя, возможно, внесенные вами изменения, ради которых все это и затевалось, сольются автоматически без конфликта.
Еще одна "особенность" создания nsf-базы по on-disk проекту - это ошибки компиляции LS-библиотек, которые возникают, скорее всего, из-за нарушения порядка импорта библиотек и их компиляции. Лечится открытием проблемных библиотек (у них нет полей $ScriptLib и $ScriptLib_O, но есть поле $ScriptLib_error), изменением в них чего-нибудь (вставить пробел и удалить его) и сохранением. После этого я еще делаю Recompile All LotusScript.
Ну и как со всем этим работать?
<div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">4. Мои процедуры</div></div><div class="sp-body"><div class="sp-content">
0. Устнановка и настройка Git
Информации об установке и настройке Git под Windows в сети достаточно.
Я устанавливал
Ссылка скрыта от гостей
с опцией git-bash (что-то такое, вторая в списке опций в установщике).
На Хабре описаны некоторые
Ссылка скрыта от гостей
. Из приведенных там советов я воспользовался только опцией
Тексты коммитов пишу в Notepad++ в кодировке UTF-8 without BOM, для этого в git установил опцию
Код:
editor = \"C:\\Program Files (x86)\\Notepad++\\notepad++.exe\" -multiInst -nosession
1. Создание on-disk проекта для базового шаблона
On-disk проекты я создаю в специально отведенном для этого месте - каталоге C:\Work\repo. Не забывайте делать регулярное резервное копирование этого каталога, СУВ не панацея!
Например, для шаблона test.ntf для заказчика customer1 будет создан проект test-customer1 и помещен в каталог C:\Work\repo\test-custormer1\db
Я помещаю проект в подкаталог db, потому что в каталоге test-customer1 будет создан служебный каталог .git, и если он будет в том же каталоге, что и созданные дизайнером каталоги с документами дизайна, то заботливый дизайнер поместит каталог .git в ресурсы БД при синхронизации. (Надеюсь, понятно объяснил. Если нет, попробуйте поместить все в одно место и посмотрите, что получится.
)
2. Создание репозитария для базового шаблона
В каталоге test-customer1 я создаю файл .gitignore следующего содержания:
Код:
db/.settings/
db/.classpath
db/plugin.xml
db/Code/ScriptLibraries/*.lss.metadata
Этот файл указывает git, какие файлы не нужно отслеживать.
Далее в git-bash я говорю:
Код:
cd /C/Work/repo/test-customer1/
git init
git add .
git commit
Пишу комментарий к первому коммиту ("Начало."), сохраняю и закрываю Notepad++.
3. Клонирование репозитария для производного шаблона (для заказчика customer2)
В git-bash:
Код:
cd ..
git clone test-customer1 test-customer2
В файле test-customer\db\.project правлю название проекта на test-customer2, чтобы не было конфликтов при открытии этого проекта в том же Workspace дизайнера, в котором открыт проект test-customer1.
4. Создание ветки во втором репозитарии и первый коммит в нем
В git-bash:
Код:
cd test-customer2
git checkout -b customer2
git commit -a
Я делаю отдельную ветку в этом репозитарии, в которую буду коммитить специфичные для заказчика изменения. Это будет основная рабочая ветка для этого репозитария. О работе с ветками чуть ниже.
Сейчас зафиксировано только новое имя проекта.
5. Создание nsf-базы по on-disk проекту
В дизайнере в навигаторе в контекстном меню Import..., далее выбираю Existing Project into Workspace, нахожу C:\Work\repo\test-customer2\db, импортирую.
Далее, правой кнопкой на этот проект - Team Development\Associate with New NSF...
Далее, в только что созданной базе компилирую библиотеки (см. выше), делаю Recomile All LotusScript
6. Коммит новой базы в репозитарий
Как я говорил выше, после создания новой БД во все документы дизайна будет записано новое значение ReplicaID базы. Эти изменения нужно зафиксировать в репозитарии (в ветке customer2).
А теперь рутина.
Сначала опишу процесс в общем и целом, потом покажу пример.
Есть очень хорошая статья
Ссылка скрыта от гостей
(перевод на Хабре), но мой процесс ей не полностью соответствует.
Новые "фичи" разрабатываются в базовом шаблоне. Для каждой фичи создается своя ветка. Эти ветки после завершения разработки вливаются в ветку master.
Во "вторичных" шаблонах ветка master используется только для синхронизации с базовым шаблоном. Основной рабочей ветке для такого шаблона я даю имя заказчика. Фичи заказчика создаются в отдельных ветках, порождаемых от основной рабочей, которые потом вливаются обратно в рабочую ветку.
Перенос новой фичи из базового шаблона происходит так: в ветку master вторичного шаблона втягивается ветка master основного шаблона. Конфликтов слияния здесь нет. Затем ветка master вторичного шаблона вливается в основную рабочую ветку. Конфликтов здесь полно по описанным выше причинам.
7. Создание фичи
а) в основном шаблоне
Код:
git checkout -b featureX
git add .
git commit
git checkout master
git merge --no-ff featureX
git branch -d featureX
б) во вторичном шаблоне все то же самое, но вместо
делаю
8. Вливание новой фичи из основного шаблона во вторичный
Работа в репозитарии вторичного шаблона.
Код:
git checkout master
git pull origin master
git checkout customer1
git merge master
9. Разрешение конфликтов слияния
Для всех файлов, которые git не сможет слить, будут созданы diff-файлы. Конфликты нужно разрешить, добавить измененные файлы в индекс и зафиксировать:
Для разрешения конфликтов слияния я сейчас использую WinMerge. Но тут я не советчик, надо подбирать удобный инструмент.
Конфликты слияния, вызванные изменениями в метаданных, я разрешаю в пользу версии вторичного репозитария (ветки customer1). Если после этого дизайнер ругается на рассинхронизацию nsf- и on-disk версий, приоритет отдаю on-disk версии; после этого приходится делать еще один "синхронизационный" коммит.
А теперь задавайте ваши ответы.
P. S. Книжка про git:
Ссылка скрыта от гостей