Пользователь
0,3
рейтинг
21 ноября 2009 в 23:33

Разработка → Командная работа в Git

Git*
Во всем множестве статей по git'у, которые я смог найти в сети, не хватает одного существенного момента — описания командной работы. То, что обычно описывают как командную работу, на самом деле является просто работой с удаленным репозиторием.

Ниже я хочу описать свой опыт командной работы над проектом с использованием git'а.

1. Общий принцип

Рабочий процесс у меня организован следующим образом.

Я ведущий разработчик тире руководитель отдела тире проджект менеджер. У меня в команде есть несколько разработчиков.

Моя работа заключается в следующем:

1) поговорить с заказчиком
2) превратить смутное и путанное пожелание заказчика в четко сформулированную задачу
3) поставить эту задачу разработчику
4) проверить результат выполнения задачи разработчиком
5) неудовлетворительный результат вернуть разработчику на доработку
6) удовлетворительный результат представить заказчику на утверждение или сразу отправить в продакшн
7) утвержденный заказчиком результат отправить в продакшн
8) неутвержденный заказчиком результат вернуть разработчику на доработку

Работа разработчика, соответственно, заключается в следующем:

1) получить от меня задачу
2) выполнить ее
3) отправить мне результат
4) если задача вернулась на доработку — доработать и снова отправить мне

Для управления задачами я использую Trac. Так же в Trac'е ведется документация по проекту, как программерская, так и пользовательская.

Сформулировав задачу, я записываю ее в Trac и назначаю какому-то разработчику. Разработчик, выполнив задачу, переназначает ее мне. Я проверяю результат и, либо снова переназначаю ее разработчику, либо отмечаю как выполненную.

Алгоритм работы с git'ом и общая картина происходящего схематически представлены на картинке:

image

Теперь от теоретической части перейдем к практической и разберемся, что все это значит и как работает.

2. Git

Установите Git. Прочитайте какой-нибудь мануал. Разберитесь с локальным репозиторием.

Обратите внимание — эта статья не про команды git'а, а про то, как увязать эти команды в нужную последовательность. Поэтому далее я буду приводить команды git'а без подробных объяснений, предполагая, что назначение отдельных команд вам известно.

3. Доступ к репозиторию

При командной работе потребуется обеспечить доступ к репозиторию нескольким пользователям. Для удобного разруливания прав доступа к репозиторию я использую gitosis.

Gitosis — это набор скриптов, реализующих удобное управление git-репозиториями и доступом к ним. Работает это так:

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

Скрипты и конфиги gitosis сами хранятся в репозитории и настраиваются путем отправки коммитов в этот репозиторий. Звучит безумно, но на деле ничего особо хитрого, вполне просто и удобно.

4. Установка gitosis

Для установки gitosis'а нужно (сюрприз!) вытянуть установочный репозиторий gitosis'а с сервера разработчика gitosis'а:

$ git clone git://eagain.net/gitosis.git

Установить gitosis:

$ cd gitosis
$ su
# python setup.py install


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

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

$ su
# adduser gituser


А затем инициализировать gitosis в домашнем каталоге созданного пользователя, с открытым ключом того, кто будет администратором gitosis'а. Открытый ключ, понятно, нужно положить куда-то, откуда его сможет прочитать пользователь gituser:

# su gituser
$ cd ~
$ gitosis-init < id_rsa.pub


Обратите внимание — пользователь gituser и администратор gitosis'а — это не одно лицо. Пользователь gituser является просто «хранителем» репозиториев и сам никаких действий вообще никогда не выполняет.

Я в качестве администратора gitosis'а использую другого зарегистрированного в системе пользователя. Но, вообще говоря, администратору вовсе не обязательно быть зарегистрированным в системе пользователем. Главное, указать при инициализации gitosis'а открытый ключ администратора.

После инициализации gitosis'а в домашнем каталоге пользователя gituser появится каталог repositories, в котором и будут храниться все репозитории. Сначала там будет только репозиторий gitosis-admin.git, в котором хранятся настройки самого gitosis'а.

Обратите внимание — по некоторым причинам, связанным с особенностями разных версий Питона, может понадобиться прописать права на исполнение скрипту post-update, находящемуся в репозитории gitosis'а:

$ chmod 755 ~/repositories/gitosis-admin.git/hooks/post-update

На этом установка gitosis'a закончена и начинается настройка.

5. Настройка gitosis'а и создание репозиториев

Настройка gitosis'а заключается в изменении администратором содержимого репозитория gitosis'а.

Становимся администратором gitosis'а (если администратор — зарегистрированный в системе пользователь) или вообще выходим из системы и логинимся там, где администратор зарегистрирован (например, на своем ноутбуке).

Теперь вытягиваем настроечный репозиторий gitosis'а:

$ git clone gituser@githost:gitosis-admin.git

Где githost — это имя сервера, на котором мы установили gitosis (и где будем хранить репозитории).

Обратите внимание — какое бы имя не имел администратор, обращение к серверу всегда выполняется под именем пользователя gituser.

После этого в домашнем каталоге администратора появится каталог gitosis-admin. В этом каталоге нас интересует файл gitosis.conf, именно в нем производится настройка всех репозиториев.

По умолчанию в нем будет нечто такое:

[group gitosis-admin]
writable = gitosis-admin
members = admin@host

Что означает «пользователю admin разрешена запись в репозиторий gitosis-admin».

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

[group project-write]
writable = project
members = superdeveloper

[group project-read]
readonly = project
members = developer1 developer2 developer3 user1 user2

[group dev]
writable = dev
members = superdeveloper developer1 developer2 developer3

где superdeveloper — ведущий разработчик, developer* — разработчики, user* — прочие интересующиеся

Этот конфиг означает следующее:

1) ведущему разработчику позволено писать в главный репозиторий
2) всем позволено читать из главного репозитория
3) ведущему разработчику и всем разработчикам позволено писать в рабочий репозиторий

Все эти пользователи, как и администратор gitosis'а, вовсе не обязательно должны быть зарегистрированными в системе пользователями. Главное, чтобы у них были открытые ключи.

Открытые ключи указанных в конфиге пользователей нужно скопировать в каталог gitosis-admin/keydir. Файлы ключей должны иметь имена вида имя_пользователя.pub. В данном примере это будут имена superdeveloper.pub, developer1.pub, user1.pub и.т.д.

После правки конфига и копирования ключей нужно закоммитить изменения в локальный репозиторий:

$ git add.
$ git commit -am 'Add project Project'


И отправить коммит в центральный репозиторий, где сделанные настройки подхватит gitosis:

$ git push

Все, теперь наш сервер репозиториев настроен и нужные репозитории созданы (вру, репозитории еще не созданы, но будут созданы автоматически при первом коммите).

6. Назначение репозиториев

Если в предыдущем разделе у вас возник вопрос — почему для одного проекта нужно два репозитория — то вот ответ.

Первый репозиторий, он же главный — это продакшн. На коде из этого репозитория будет работать боевая копия проекта. Второй репозиторий, он же рабочий — это разработка. В этом репозитории ведется, понятно, разработка проекта.

Я пробовал разные схемы командной работы и наиболее удобной на данный момент мне представляется «двухрепозиторная» схема. Работа в ней ведется примерно следующим образом:

1) я ставлю задачу разработчику
2) разработчик берет актуальную ветку проекта из главного репозитория и делает с нее локальный бранч
3) в этом бранче разработчик решает поставленную задачу
4) бранч с выполненной задачей разработчик отправляет в рабочий репозиторий
5) я беру из рабочего репозитория этот бранч и проверяю его
6) если задача выполнена правильно, я сливаю этот бранч с актуальной веткой проекта в главном репозитории

Эта схема имеет два ключевых отличия от широко описанной схемы, когда вся разработка идет в ветке master одного репозитория.

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

Во-вторых, актуальная ветка у меня никогда не бывает в нерабочем состоянии.

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

Поясню на примере.

Допустим, разработчик Р1 сделал правку П1 и отправил ее в ветку master. Я проверил эту правку и нашел ее плохой. Плохую правку нужно переделывать.

Пока я проверял, разработчик Р2 сделал правку П2 и тоже отправил ее в master. Эта правка оказалась хорошей. Хорошую правку нужно отправлять в продакшн.

Но теперь в ветке master находятся две правки, хорошая и плохая. Хорошую правку нужно бы отправить в продакшн, но присутствие плохой правки не позволяет это сделать. Придется ждать, пока плохая правка будет исправлена.

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

В общем, нужно сделать так, чтобы правками можно было рулить по отдельности друг от друга, не сваливая их все кучей в ветку master.

Для этого разработчики отправляют в репозиторий все свои бранчи по отдельности, не сливая их с master'ом. Сливанием занимаюсь я. Соответственно, в актуальную ветку попадают только проверенные мной правки. Плохие правки отправляются на доработку, а правки, ждущие утверждения заказчика, отправляются в тестовую ветку и просто… ждут. И никому не мешают.

Таким образом, актуальная ветка всегда находится в рабочем состоянии.

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

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

7. Первичная загрузка проекта в репозиторий

Обратите внимание — первичную загрузку делает ведущий разработчик, так как только у него есть право писать в главный репозиторий.

Создаем локальный репозиторий в каталоге проекта и загоняем в него файлы проекта:

$ cd /старый/каталог/проекта
$ git init
$ git add.
$ git commit -am 'poehali!'


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

$ git remote add origin gituser@githost:project.git

Теперь оправляем коммит в главный репозиторий:

$ git push origin master

Все, проект отправлен в главный репозиторий. Теперь старый каталог проекта можно смело грохнуть и начать работу уже в новом каталоге (или вообще на другом компе), под управлением git'а.

8. Репозиторий ведущего разработчика

Переходим в новый каталог (или вообще на другой комп) и вытягиваем главный репозиторий:

$ cd /новый/каталог/проекта
$ git clone gituser@githost:project.git


Это мы получили копию главного репозитория. В ней находится актуальная ветка. Теперь нужно создать тестовую ветку.

Просто скопируем актуальную ветку в главный репозиторий под именем тестовой:

$ git push origin master:stage

А затем вытянем тестовую ветку из главного репозитория уже под собственным именем:

$ git checkout -b stage origin/stage

Теперь локальный репозиторий содержит две ветки, master и stage. Обе ветки связаны с одноименными ветками в главном репозитории.

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

Кроме того, нужно указать местонахождение рабочего репозитория dev:

$ git remote add dev gituser@githost:dev.git

9. Инфраструктура проекта

Проект у нас включает не только репозитории, но и «исполняющие» узлы — продакшн и отладку.

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

Запуск продакшна, не вдаваясь в детали, был таким:

1) зарегистрировать в системе нового пользователя, из-под которого будет работать продакшн
2) добавить этого пользователя в gitosis (см. раздел 5, в моем примере это user*)
3) клонировать главный репозиторий project в каталог этого пользователя
4) Настроить виртуальный хост Apache (или что там вам больше нравится) на каталог проекта

И теперь для обновления продакшна достаточно просто зайти в этот каталог и выполнить одну-единственную команду:

$ git pull

Все обновления, находящиеся в актуальной ветке, во мгновение ока окажутся в продакшне.

Отладочная копия проекта устроена идентично, за исключением того, что после клонирования главного репозитория было сделано переключение с актуальной ветки master на тестовую ветку stage:

$ git checkout -b stage origin/stage

Теперь pull в отладке будет вытягивать обновления из тестовой ветки.

10. Репозиторий разработчика

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

Главный репозиторий нужно склонировать:

$ git clone gituser@githost:project.git

А рабочий репозиторий просто добавить в конфиг:

$ git remote add dev gituser@githost:dev.git

Эта настройка выполняется только один раз. Вся дальнейшая работа выполняется по стандартной схеме (распечатать памятку и прилепить на монитор).

11. Памятка разработчика

Проверить почту. Если пришло уведомление из Trac'а о новой задаче — начать работать:

$ quake exit

Создать новый бранч на основе актуальной ветки из главного репозитория (мы у себя договорились называть бранчи номерами тикетов из Trac'а):

$ git checkout -b new_branch origin/master

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

$ git checkout -b old_branch dev/old_branch

Вытянуть последние изменения:

$ git pull

---
Выполнить задачу в новом бранче. Тут происходит работа с кодом.
---

Если в процессе работы были созданы новые файлы — добавить их в бранч:

$ git add .

Сохранить изменения в локальном репозитории:

$ git commit -am 'komment'

Отправить новый бранч в рабочий репозиторий:

$ git push dev new_branch

Или повторно отправить туда же старый бранч:

$ git push

Выполненную задачу переназначить в Trac'е ведущему разработчику. Обратно разработчику она вернется либо с указанием на то, что нужно переделать, либо со статусом closed.

10 goto проверить почту;

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

Во-первых, бранчи, отправленные в рабочий репозиторий, более не нужны локально и могут быть смело удалены:

$ git branch -D new_branch

Во-вторых, список бранчей в удаленных репозиториях, выдаваемый командой

$ git branch -r

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

$ git remote prune dev

которая удалит из локального кеша отсутствующие в удаленном репозитории бранчи. Обратите внимание — обновлять сведения нужно только о рабочем репозитории. В главном репозитории никаких изменений никогда не происходит, там всегда находятся одни и те же бранчи — master и stage.

12. Действия ведущего разработчика

Получив уведомление из Trac'а о переназначенной мне задаче, я открываю эту задачу и смотрю, про что там вообще было, чтобы знать, что проверять.

Затем я обновляю данные об удаленных репозиториях:

$ git remote update

Теперь мне будут видны новые бранчи в рабочем репозитории, в том числе бранч, соответствующий проверяемой задаче:

$ git branch -r

Затем я вытягиваю проверяемый бранч из рабочего репозитория к себе (поскольку название бранча соответствует номеру тикета, то я всегда точно знаю, какой бранч вытягивать):

$ git checkout -b branch dev/branch

Если это не новый бранч, а исправление старого, то нужно еще вытянуть обновления:

$ git pull

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

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

Если правка простая, то я просто сливаю проверенный бранч с актуальной веткой и отправляю обновленную актуальную ветку в главный репозиторий:

$ git checkout master
$ git merge branch
$ git push


После этого я удаляю бранч у себя локально и из рабочего репозитория, больше этот бранч никому и никогда не понадобится:

$ git branch -D branch
$ git push dev :branch


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

Если же правка требует согласования, то проверяемый бранч сливается не с актуальной веткой, а с тестовой:

$ git checkout stage
$ git merge branch
$ git push


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

$ git branch -D branch

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

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

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

(оригинал статьи)
Михаил Иванов @ivanych
карма
8,0
рейтинг 0,3
Пользователь
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (68)

  • +1
    Подскажите, как я понял, у вас для каждой правки отдельная ветка в репозитории? Или для например определенного задания?
    • +2
      Одно задание — одна ветка. Я не различаю задания и правки. Может быть, переформулируете вопрос, я не совсем Вас понял.
  • 0
    Очень хорошая инструкция, только не написали где разработчикам хранить свои ключи.
    • 0
      Применяется стандартный способ авторизации SSH по ключам. Ключи, хранятся в домашних каталогах разработчиков. Я просто не стал вдаваться в детали, чтобы совсем от темы не отходить.
  • +1
    А если задание совсем очень простое — как то поправить пару строчек — тоже делаете под это дело отдельные бранчи?
    Я выполняю похожую на вашу роль руководителя, различие только в одном — репозиторий у нас один и работа с ветками устроена немного по другому:
    master, как и у вас — стабилен. Туда сливаются только проверенные изменение, которых ждут на production'е. Если что то поменялось в мастере — значит на production'е пора пойти сделать pull.
    Разработка же ведется в ветках с названиями dev<номер версии>, например, dev0.8, dev0.11, версии в моем случае — набор задач, который объединяется в версию. Когда цель достигнута — версия тестируется, сливается с мастером и выкладывается на продашкн.
    В ситуации, если требуется какая то срочная правка мастера (багфикс) также создается временный бранч, который потом сливается с мастером.
    Всякие экспериментальный фичи, которым не нашлось места в версии живет в именнованных бранчах.

    Кстати, недавно отошел от трака в пользу redmine. Если вы ведете много проектов плюс очень большой — из коробки поддерживается много проектов, права настраиваются очень гибко. И видно все из одного места, не надо ползать по куче траков.
    • 0
      Тут существенное значение имеет то, на каком этапе разработки находится проект. Если говорить о самых первых этапах, то действительно, бывает сложно четко выделить конкретную задачу. Вроде надо сделать одну простую штуку, а начинаешь делать, оказывается, что сначала надо бы сделать другую штуку, и все это связано с третьей штукой и.т.д. В такой ситуации действительно имеет смысл вести разработку в «крупных» ветках, в которых отдельные правки не выделяются в отдельные бранчи.

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

      Но большинство моих разработчиков работают над уже развитой частью проекта. Там любую задачу я могу четко формализовать. К тому же, любая правка там должна быть под чутким контролем. Поэтому основная часть работы ведется именно так, как описано в статье — отдельный бранч на каждую, пусть даже мелкую, задачу.
    • +2
      Да, Redmine очень удобен. Я даже не работая в команде использую его как хранилище данных о проекте и сам себе задачи назначаю =). Плюс очень удобная вещь там — учет времени на задачу.
      Раньше тоже использовал Trac.
  • 0
    а вебморды для gitosis не знаете? Чтобы пользователей и тд, добавлять через браузер
    • 0
      Нет, не возникало такой задачи. Но там же очень простой конфиг, так что я не заморачиваюсь, руками правлю.
    • 0
      Ставьте Gitolite и Gitlab.
  • НЛО прилетело и опубликовало эту надпись здесь
    • +2
      Эээ… Вы, простите, ерунду сказали. Файлы, которые должны быть изменены для работы на конкретной машине, вообще не должны быть под контролем git'а.

      Скажем, логов в репозитории вообще не должно быть, а на конкретных машинах они должны быть проигнорированы путем создания файлов .gitignore. А конфиги должны быть внесены в репозиторий в виде файлов .orig и на конкретных машинах должны копироваться в новые файлы, опять же, игнорируемые через .gitignore.
      • НЛО прилетело и опубликовало эту надпись здесь
        • +1
          Вот именно про файлы типа конфигов Вы и говорили. А я сказал, как нужно делать, чтобы эти файлы и в репозитории трекались, и локально правились, и куда не надо не коммитились.

          Настройте все правильно и юзайте -am, вместо ручного перечисления полусотни измененных файлов.
          • +2
            откуда полсотни то возьмется? непонятно зачем писать так код, чтобы в коммит попадало так много изменений за раз, на мой взгляд это плохая практика.
            • 0
              Ну как откуда? Это если задача «переименовать кнопку Сохранить в кнопку Записать», тогда конечно, в коммите будет одно изменение. А если задача «исправить функцию расчета Итого в финансовых отчетах», то изменений будет ого-го.
        • +2
          Я обычно перед тем, как делать коммит делаю git status и вижу, что пойдет в коммит. Поэтому -am можно небояться.
          А все конфиги должны быть в .gitignore. А их default версии в файликах .default.
      • +1
        От чего-ж ерунду, а мой взгляд -a совсем не лучший вариант, я тоже всегда перечисляю весь список файлов для коммита, на мой взгляд так гораздо проще не запихать ерунды в коммит.
        • –1
          Т.е. Вы предлагаете иметь ерунду в файлах, и постоянно волноваться, чтобы эту ерунду не отправить в репозиторий? Нет уж, спасибо, я лучше вообще ну буду иметь ерунды.
          • +3
            Ерундой может оказаться случайно измененный файл (ненужный пробел, перевод строки, ...), вывод отладочной информации (к примеру излишне подробный логгинг) и тому подобные изменения.
            Лучше всё-таки просматривать код до коммита (git add -p, git gui). В крайнем случае — git status + git diff + git commit -a.
    • –1
      чтобы в git commit не перечислять файлы, можно и нужно пользовать команду git add <маска_поиска_файлов>

      После того как пометите все файлы которые идут в коммит (проверяете c помощью git status) использовать git commit -m «какой то коммит»
    • +1
      Я вот вообще hunk-ами стараюсь коммититься.

      $ git add -p

      рулит :-)

      Коммитов больше, зато и контроля больше. Чётко видно, что, где и почему поменялось.
  • +1
    Во-первых, спасибо за статью!

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

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

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

    Очень много искал на эту тему но пока ничего дельного не придумалось.
    • 0
      У меня нет отдельно CMS и отдельно проекта/проектов на ней. Разрабатывается проект, и все функции, которые проекту требуются, сразу в него и встраиваются. Проект узкоспецифический, коробочная версия не предполагается.
    • 0
      Я предпочитаю разделять такие вещи по разным проектам и работа с ними независимо. Управлять слиянием конфигурации и движка надо извне (например, системой управления зависимостями платформы).

      А так для меня есть 2 подхода для решения описанной вами задачи средствами только git: git submodule и git subtree. Первый плох тем, что недостаточно объединяет подмодуль и его контейнер: имея репозиторий с контейнером можно не иметь понятия о том, где брать подмодуль и наоборот. Второй плох тем, что недостаточно устоялся и тем, что для выгрузки изменений из контейнера в репозиторий модуля надо делать промежуточное действие: выгрузку изменений подкаталога внутри репозитория контейнера.
  • +2
    Небоьшую путаницу вносит то, что вы употребляете слова «ветка» и «бренч» в одном предложении в разных значениях. Мозг автоматически вопринимает эти слова как синонимы :)

    А по сути — спасибо большое. Действительно, подобных статей я не встречал, разобрано именно то, что вегда упускается.
    • 0
      Ммм… Я на самом деле использую эти слова как синонимы. Если где-то получилось предложение, в котором эти слова означают разное — скажите, я постараюсь переформулировать.
      • 0
        В тестовой ветке проверяемый бранч лежит и есть не просит. Когда заказчик доберется до него и утвердит, тогда я снова вытяну этот бранч из рабочего репозитория и солью с актуальной веткой."
        • 0
          Мда. Тут вместо слова «бранч» следовало бы употребить слово «коммит». Но тогда во всех остальных местах получается запутка… Я постараюсь переформулировать, спасибо за толковое замечание.
  • +2
    Но в одном репозитории нельзя разделить доступ к отдельным бранчам, т.е. нельзя разрешить писать в репозиторий новые бранчи и при этом запретить изменять актуальную ветку.

    можно. используя pre-receive хук:

    #!/bin/sh
    while read a; do 
      branch=`echo $a | cut -d" " -f3`
      if [ $branch == "refs/heads/master" -o $branch == "refs/heads/stage" ];  then
        username=`whoami`
        if [ $username != 'superuser1' -a $username != 'superuser2' ];  then
          echo "* You not authorized to commit to $branch branch!!!        *" 1>&2
          exit 1
        fi
      fi
    done
    


    Также можно отослать себе email — с нотификацией, что кто-то хотел залиться в мастер.
    • +1
      Когда проблему с доступом к бранчам курил, нашел продвинутый аналог gitosis — gitolite

      Отличия от gitosis: github.com/sitaramc/gitolite/blob/pu/doc/3-faq-tips-etc.mkd#diff
      • 0
        Спасибо, надо будет почитать.
    • 0
      Да, можно решить хуками. Но я тут рассуждаю так:

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

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

      Поэтому я сразу разделяю главный репозиторий и репозитории отдельных разработчиков. Правда, я все-таки делаю упрощение и репозитории отдельных разработчиков объединяю в один.
      • +1
        Согласен, я лишь хотел заметить, что запретить коммитить в отдельно взятый бранч в одном репозитории возможно.
        А в ядре, насколько я знаю, в основном пулят, а не пушат изменения.
        В принципе если работа происходит в офисе и у суперразработчика есть доступ на все машины по ssh — то можно пулить в свой репозиторий прямо с персональных репозиториев;)
        Но если в комманде есть редиска, который ходит на работу с ноутбуком — то всё становится тяжелее;)
  • 0
    Спасибо, статья вразумительная, однако с git не знаком совершенно. Возник такой, скорее всего, глупый вопрос: где девелоперы пишут код? :-)
    • 0
      Девелоперы вытягивают копию главного репозитория к себе. В свой домашний каталог, или вообще на свой собственный комп. Куда угодно, где им удобно работать. Там и пишут код. А потом отправляют то, что написали, в рабочий репозиторий.
    • 0
      Хочу дополнить ivanych`а, что для разработки web-приложений очень помогают отдельные виртуальные машины с Linux: если что, то можно быстро дать уже готовую и настроенную среду новому разработчику.
  • +2
    спасибо за статью, через недельку расскажу как происходит командная разработка с использованием git в проекте Midnight Commander…
  • 0
    Тоесть вы сами проверяете все изменения разработчиков? У вас нет отдела тестирования и continious integration? Я вот все думаю как заставить Hudson дружить с такой кучей веток.
    • 0
      Нету у меня отдела тестирования…

      (рыдает)
  • 0
    Вот интересно как автор решает проблемы с бинарными файлами в репозитории (если они возникают конечно).
    Поясню, что имею ввиду: хранить бинарники в vcs не очень хорошая идея, но иногда нет выхода. К примеру это может быть файл с ресурсами для флешки, картинки или схожие ресурсы у которых нету текстовых исходников.
    Так вот, если разработка svn-like — то проблемы особо нет — ктото предупреждает остальных, что файл будет им изменен, меняет, заливает и освобождает этот ресурс. Но вот в случае если в мастер принимаются патчи и мёржатся одним человеком — пока он не смержит изменения — никто не может менять файл.
    Я вижу пока только 2 варианта — не хранить файлы в vcs, но тогда дополнительно надо иметь доступ к хранилищу этих файлов (samba, NFS), а также у них не будет исптории. Или хранить в отдельном репозитории с svn-like подходом.
    • 0
      Промахнулся с ответом. Комментарий ниже.
      • 0
        Товарищ описывает ситуацию следующего характера:

        1. Разработчик (дизайнер) A пуллит бинарный файл F1 (например, картинку)
        2. Разработчик (дизайнер) B пуллит бинарный файл F1
        3. Разработчик А коммитит измененный файл F1/A в ветку B1
        4. Разработчик B коммитит измененный файл F1/B в ветку B2
        5. Вам нужны оба изменения на продакшне.

        Ваши действия?
        • 0
          Понял.

          Не знаю, как тут быть. У меня как-то не возникает таких ситуаций, поэтому четкой позиции у меня по этому поводу нет. Как столкнусь — напишу другую статью:)
  • 0
    Честно говоря, не понял сути описанной Вами проблемы.

    У меня есть бинарные файлы. Вообще проект имеет, в основном, веб-интерфейс, но некоторая часть интерфейса, требовательная к графическим возможностям, реализована в виде исполняемого windows-приложения. Исходные коды приложения хранятся в репозитории, это понятно. Где хранить готовый дистрибутив — я тоже долго думал и решил хранить там же, в репозитории. Смысл в том, что в этом случае pull на продакшне автоматически деплоит дистрибутив на сервер, с которого дистрибутив уже могут скачать все пользователи.

    Впрочем, тут рецепта дать не могу, у меня бинарные файлы меняются очень редко и проблем как-то возникает. Вероятно, есть методы хранения более толковые.
  • +1
    Спасибо за рассказ. Только вы немного не поняли смысл децентрализации репозиториев. По вашей схеме вы с таким же успехом могли бы использовать svn, cvs и иже с ними.

    Разница будет как минимум в том, что не девелоперы будут куда-то коммитить свой код, а вы будете pull-ить их код к себе в репозиторий.
    • 0
      Тут можно спорить, конечно. Во всяком случае большое спасибо за подробное описание того, как у вас происходит разработка. Таких статей действительно нехватает. Плюс в карму :-)
    • 0
      Вы о чем? Что не так?
  • +1
    хорошая статья, но у меня есть пару замечаний:

    * «git branch -D» исползуется толко в исключительных случаях т.к. он позволяет потерять данные. в 99% случаев лучше использовать «git branch -d» — ета команда вернёт ошибкы при попытке удаления бранча который не «замерджен» в текущий.
    * также из моего опыта если в команде работают толковые люди то настолько тотальный контроль не обязателен. у нас любой может «мерджить» в master
    * под gitosis обычно используют юзер git а не gituser :)
    * также предложенный порядок ведения бранчей отличается от «канонического» с точностью до наоборот :)
    по идее «master» (или trunk) это место куда сливают всё самое последнее (и куда все могут мерджить),
    а как раз для стабилизации используют staging и production бранчи.
    • 0
      * Нет, "-D" я указал осознанно. Именно с той целью, чтобы не отвлекаться на чтение уведомлений о «неродственности» текущего и удаляемого бранчей. Разработчики никогда не сливают свои бранчи с актуальным, им расхождение удаляемого бранча с актуальным роли не играет. А я всегда в итоге удаляю присланный бранч, не зависимо от того, слил я его с актуальной веткой, или нет, поэтому мне сообщения от флага "-d" тоже не интересны.

      * Я и говорю — тотал контроль не главное, главное — возможность отправлять правки в продакшн по одной, не дожидаясь одобрения заказчиком всего пакета правок, попавшего в master.

      * это я для того, чтобы понятно назвать githost. Согласитесь, название хоста host — не очень говорящее:)

      * это Вы про другую схему рассказываете. Я именно отказался от такой схемы, когда все валят все в master. Моя схема более универсальна и позволяет, если хочется, все-таки валить все в master на рабочем репозитории.
  • 0
    Ну вот, наконец-то внятная грамотная статья от поклонника git, где описан правильный процесс контроля версий в рамках командной разработки. А то как ни статья — так одни восторги, эпитеты и простое перечисление команд из мануала. Здесь же показан пример грамотной СМ-политики для команды. Причем, именно политики, а не разрозненых сведений.

    Одним словом, респект.

    В моей SCM-копилке есть несколько ссылок на политики ведения групповой разработки — как с использованием классических подходов, так и agile-методик (без привязки к инструментам). Теперь вот есть куда отдельно указать любителям DVCS.

  • 0
    спасибо, хорошая статья
  • 0
    Хоть статья уже и старая, но всё же рискну поднять вопрос.
    В данный момент мы у себя в проекте используем очень похожую схему разработки. Но проблема в том, что у нас очень много программистов и процесс проведения веток на актуальную версию (продакшн) занимает очень много времени.
    Может быть есть какие-то системы автоматизации мержа многих веток на мастер, пуш в мастер, а потом пулл на мастере и пр?
    • 0
      Средств подобной автоматизации не знаю, как-то не возникало такой необходимости. Но так вот сходу я бы сказал, что это задача не техническая, а организационная. Я бы выделил несколько ответственных программистов, которым поручил бы сборку крупных частей проекта из мелких веток. А потом уж эти крупные ветки сливал бы в мастер.
      • 0
        Та вот как раз и проблема в том, что в этом случае люди будут заниматься рутинной и «хомячковой» работой по сливанию веток в мастер. Это занимает много времени, которые можно было бы потратить на реализацию программистских задач.
        • 0
          Но Вы не можете поступить иначе. Какая бы ни была автоматизация, но кто-то должен принять ответственность за принятие кода в продакшен. Это не «хомячковая» работа, наоборот, это едва ли не более важная работа, чем собственно написание кода.

          Если ответственному человеку приходится выполнять много однотипных действий, то их, конечно, следует автоматизировать. Но принимать решения все-равно кто-то должен.
          • 0
            Да-да, я понимаю. Речь идёт о моменте, когда задача оттестирована и уже на 100% готова в продакшн. И нужно её довести как можно меньшими человекозатратами. Приходится, к примеру, 2 раза в день выводить по по 15-20 веток в продакшн. И вот проводящему это совсем не в кайф, тратить столько времени.
            • 0
              Каждая задача на 100% оттестирована? И возможность взаимных конфликтов всех 15-20 веток протестирована?

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

              Если же тестированием у вас занимается автоматизированная система, то на выходе у нее уже должна быть готовая ветка для продакшена, со всеми протестированными и слитыми ветками.
  • 0
    Пост порядком запылился ) Но все же мне интересно. Вы пишете, что нужно 2 репо. Я сейчас работаю с проектом на bitbucket, и там можно настроить ограничение на коммиты в конкретную ветку. Например, сделать так, чтобы в эту ветку могли отправлять коммиты (и удалять ее тоже) только отдельные пользователи. Я не знаю, это допилили сами разработчики bitbucket или такой функционал уже встроен в гит, но в этом случае держать 2 репо бесмысленно. Работа ведется с ветками так же, как у Вас с 2 репо.
    Хотя, конечно, могу предположить, что это фича именно bitbucket, иначе бы вы не писали про 2 репо)
    • 0
      Пост был написан, когда Гитхаб еще только-только появился, а Гитлаб ещё вообще не появился. В тех условиях работать более чем с одним репозиторием было весьма заморочно, а настраивать один репозиторий для доступа было невозможно или тоже сложно. Поэтому работа с двумя репозиториями была неким компромиссом.

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

      Так что, да, пост порядком запылился:) Но спасибо, вы навели меня на мысль написать новую версию статьи, с учетом текущих реалий.
      • 0
        Не совсем понимаю, чем работа с отдельными репозиториями отличается от работы с отдельными ветками в одном репозитории, объясните пожалуйста разницу. Единственный плюс (а в некоторых случаях скорее минус), который я вижу — изолирование разрабов друг от друга.
        • 0
          > изолирование разрабов друг от друга.

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

          Есть и дополнительные плюшки — например, свой репозиторий можно утащить с собой в лес и там разрабатывать в тишине и медитации.
          • 0
            А как таким образом решается вопрос с код ревью или, например, совместной работой над каким-то кодом? Простой пример. Есть некая фича, достаточно массивная. Делим на отдельные части, даем каждому разрабу отдельную часть. Когда части закончены, нужно выполнить их подключение друг к другу. Как показывает опыт, очень часто бывает, что нужно допиливать напильником уже вместе, а не по отдельности. И вот тут может очень пригодиться код другого разработчика. Если репо один, таких проблем не возникает. А как быть в этом случае, если у каждого разраба свой репо?
            • 0
              Происходит обмен кодом с другими репозиториями. В том и суть распределенной системы — не огородить всех неприступной стеной, а сделать сеть, с удобным доступом друг к другу.

              Простите, я не готов в рамках комментария это описывать, это Вам лучше почитать в целом о Гите и пулл-реквестах.
              • 0
                Про пулл-реквесты я в курсе, только не знал, что их можно выполнять в другие репо. В целом, я понял, в чем профит от такого подхода, спасибо.
        • 0
          Касательно веток — у каждого разраба в своем репозитории могут быть ветки с каким угодно названием. Если все разрабы будут работать в одном репозитории, неминуемо будет конфликт имен — Вася назвал ветку «check» и Петя тоже так назвал — и привет, иди ругайся, кто тут главный.

          Разнесение по разным репозиториям — это, в частности, разнесение по разным пространствам имен.
          • 0
            У нас такая проблема решается просто дописыванием в начале имени и фамилии разраба, например, вот так i_ivanov_название_ветки. Пока проблем нет. Хотя проект небольшой, возможно поэтому особых проблем пока не испытываем.
            • 0
              Это костыль, добавление префикса какбэ и намекает Вам, что нужны разные пространства имен:)

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.