Коллективная разработка с использованием git и Trac в проекте Midnight Commander


    Действительно, в интернете сейчас можно найти достаточно много информации о настройке GIT и работе с ним, но недостаточно освещен вопрос коллективной разработки и "рабочего процесса" отдельно взятого проекта от начала и до конца.     Попробую восполнить этот пробел на примере открытого проекта Midnight Commander, не останавливаясь на вопросах установки необходимого ПО, так как этот момент неплохо описан в интернете, и вы сможете легко найти интересующую вас дополнительную информацию самостоятельно.
Используемые термины и определения
  • тикет - отчёт об ошибках либо о пожеланиях, улучшениях. Иные названия - багрепорт и т.п.
  • бранч - ветвь разработки, существующая в системе контроля версий (в git)
  • апстрим - главная ветвь в системе контроля версий. Для git это обычно ветвь "master"
  • стабильная ветвь - ветвь отпочковавшаяся от ветви "master" тэгированная и выпущенная в качестве релиза (в дальнейшем сопровождается отдельно)

Исправление ошибок/добавление функционала

Фиксация текущего состояния разработки с помощью Trac
    В нашей команде нет как такового лидера проекта, и у нас работает принцип долбанной демократии, т.е. решения принимаются коллегиально, большинством голосов. Чтобы принятие решений не затягивалось на долго, всё общение происходит в джаббер конференции в реальном времени. Кто не успел -- тот опоздал :). Но если решение требует голосов всех активных разработчиков, то заводится отдельный тикет для голосования на Trac-е проекта. Чтобы не было хаоса в процессе разработки, мы приняли ряд регламентов, оговаривающих непосредственный "рабочий процесс". Процесс сводится к нескольким этапам:
  • выявление проблемы
  • создание тикета на Trac-е
  • принятие разработчиком тикета в работу
  • публикация работы в виде бранча
  • обсуждение в комнате найденного решения, проверка работоспособности, аудит кода
  • утверждение бранча, если необходимое количество разработчиков сочли решение приемлимым
  • влитие бранча в апстрим
    Если один из разработчиков решает исправить проблему, описанную в тикете, или хочет добавить новый функционал - он назначает себя владельцем тикета и в дальнейшем считается ответственным за решение данной проблемы. Теперь он наблюдает за тикетом (общается с постановщиком задачи, следит за тем -- не предложил ли кто то из сторонних разработчиков своего "решения" в виде патчей и т.п.), создает новую ветку (бранч) для последующей работы в ней. Новые ветки обязательно должны следовать правилам наименования: XYZ_<здесь_некоторое_описание> где XYZ - это номер тикета; описание по возможности должно быть осмысленным и коротким.     Патчи из тикета никогда не применяются непосредственно к ветви "master", а проходят всегда процедуру обсуждения и ревизии в виде отдельной ветви.     После создания ветви и публикации ее в репозитарии ответственный за тикет разработчик выставляет ветвь на ревизию (review) для того, чтобы другие разработчики смогли увидеть что данный тикет готов к ревизии и обсуждению. Если это не сделано и тикет не выставлен на review - ветвь считается нестабильной и подлежит дальнейшей разработке.     В качестве примера приведу тикет #1746, в нем некто bilbo описал суть проблемы со встроенным ftp клиентом и приложил патч устраняющий проблему. Далее в этом же тикете он сообщает о публикации в репозитории новой ветви 1746_passive_mode_over_proxy и выставлении ее на голосование.
* owner set to bilbo * status changed from new to accepted * severity changed from no branch to on review Created branch 1746_passive_mode_over_proxy Initial changeset: b32c9e4a2a15cd50a6a07ad85b1a587328bd2cfc
После просмотра кода двое разработчиков проголосовали за данный код и обозначили его как утвержденный (approved).
* votes changed from slavazanko to slavazanko andrew_b * severity changed from on review to approved
Далее разработчик произвел слияние своей ветви 1746_passive_mode_over_proxy с основной ветвью master и сообщил об этом в тикете:
* status changed from accepted to testing * votes changed from slavazanko andrew_b to commited-master * resolution set to fixed * severity changed from approved to merged Fixed 2cfed22012ded42c2f4f47a13edc05bf405842db
Работа с кодом под контролем GIT
Работа над кодом с использованием git, в пределах одного тикета, сводится к следующим шагам: переключение на ветвь "master"
$ git checkout master
получение последних изменений
$ git pull
создание локального бранча, согласно правил наименования этого самого бранча
$ git checkout -b 123_branch_name
Далее разработчик вносит изменения в исходные тексты и коммитит изменения... фиксация изменений
$ git commit file.1 file.2 file.3
публикация ветви
$ git-publish-branch
скрипт git-publish-branch можно скачать тут
Ревизия кода
    Так же, как существует руководство по созданию тикетов -- существует и руководство по их обзору. Основные принципы, которыми мы пользуемся при обзоре кода, хорошо и ёмко изложены в статье, перевод которой опубликован здесь "Я ненавижу тебя: твой код – хлам!".     Разработчик, взваливший на себя ответственность за ревизию кода, должен в процессе обзора получить для себя ответы на следующие вопросы:
  • является ли патч вкладывающимся в общую концепцию проекта или патч является "хаком"?
  • аккуратно ли выглядит код?
  • делает ли код то, что должен делать (что было задекларировано в комментарии к патчу)?
  • добавляет ли код новые проблемы (ошибки)?
    Если патч нравится (выглядит приемлемым), то разработчик-рецензент должен добавить свой голос в поле для голосования (Votes for changeset) в формате <login>, где login - это имя пользователя в Trac. Если же патч не совсем безгрешный, то необходимо написать об этом ответственному за тикет и сменить статус тикета с review на rework     В настоящее время необходимы голоса двух разработчиков чтобы патч был применён к родительской ветви (либо к ветви "master"). Если кто-либо из рецензентов добавляет свой голос вторым, то ему необходимо также сменить статус тикета на approved (утверждено).     В ходе обсуждения в тикете, либо в ходе просмотра патчей разработчики могут убирать свои голоса при возникновении каких-либо проблем. Идеальный вариант тестирования:
$ git checkout master $ git reset --hard origin/master $ git pull $ git merge --log --no-ff origin/123_branch_name
вариант попроще
$ git checkout origin/123_branch_name -b 123_branch_name
Далее сборка, тестирование, просмотр кода, рецензия.
Применение патчей
    После процедуры ревизии и получения необходимого количества голосов за бранч, разработчик может влить свои изменения в основной ствол репозитория. При этом также должны быть соблюдены регламенты:
  • НИКОГДА(!!!) не производить перебазирование (rebase) стабильной ветки относительно "master", чтобы объединить исправления!
  • Обязательно в первом описании коммита указать номер тикета в формате, относительно которого был создан бранч, примерно так:
    Ticket #123 (ticket summary) <пустая строка> add: some text... fix: some text...
    это поможет в дальнейшем связать, через описание первого коммита, влитый бранч с номером тикета на Trac-е.
  • Обязательно произвести перебазирование своего бранча относительно родительской ветви. например если бранч основан на ветви "master"
    $ git checkout master $ git pull $ git checkout 123_branch_name $ git rebase -i origin/master
    ключ -i указывается если нужно произвести интерактивное перебазирование (если нужно удалить/склеить/переставить отдельные коммиты) После этого надо обновить ветвь на сервере
    $ git push origin +123_branch_name
    "+" указывает что нужно произвести принудительное (forced) обновление коммитов в удаленном бранче NB: Если не сделать перебазирование, то возможна ситуация когда другие разработчики уже влили свои конкурирующие изменения в нашу родительскую ветвь, и в лучшем случае история в ней будет путанной и сумбурной, а в худшем -- родительская ветвь перестанет собираться либо будет работать некорректно.
  • Выполнить слияние с родительской ветвью
    $ git checkout master $ git merge --log --no-ff 123_branch_name
    ключ --log показывает в коммите слияния, список патчей которые вводятся этим слиянием; ключ --no-ff позволяет сгенерировать коммит слияния даже в том случае, если ветвь является дочерней от вершины родителя (по нему проще отследить, какие патчи были сделаны в рамках данного тикета). Этот ключ значительно упрощает понимание взаимосвязей коммитов. обновление данных в удаленном репозитарии
    $ git push origin master
    удаление ветви 123_branch_name на сервере и локально
    $ git push origin :123_branch_name $ git branch -d 123_branch_name
  • Обязательно зафиксировать факт слияния в тикете, как было сказано выше, написав комментарий в виде
    Fixed 2cfed22012ded42c2f4f47a13edc05bf405842db
    где 2cfed22012ded42c2f4f47a13edc05bf405842db - это мерж-коммит бранча.
  • Закрыть тикет с указанием статуса "merged"
Уфф... кажется все, спасибо за внимание... PS: Был бы рад прочитать как это работает у вас.