Git Subrepo
Проект git-subrepo существует достаточно давно, однако упоминаний о нем незаслуженно мало. Автором git-subrepo является Ingy döt Net.
Если посмотреть на историю комитов master-ветки проекта, то может показаться, что проект остановился в развитии 2 года назад. Однако работы над проектом ведутся и хочется надеяться, что скоро будет выпущена версия 0.4.0.
Важным свойством данного средства является то, что на стороне пользователя нет необходимости устанавливать git-subrepo до тех пор, пока пользователь не решит делать комиты в upstream-репозитории подпроектов. Кроме того, пользователь получает полностью готовое и настроенное дерево исходного кода в момент копирования основного репозитория посредством стандартной команды git-clone(1).
tags
Выбирая средства поддержки подмодулей/поддеревьев/подпроектов основного репозитория-контейнера, разработчик прежде всего определяет спектр возможностей, которое предоставляет тот или иной механизм и дает ответы на следующие вопросы:
- необходимо ли хранить полную историю подпроекта в основном репозитории или достаточно squashed коммитов;
- нужна ли возможность поставки изменений из подпроекта в upstream-репозиторий поддерева;
- существует ли необходимость подключать фиксированные теги upstream-репозитория подпроекта или достаточно возможности подключения веток;
- будет ли необходимо вдальнейшем удалять как сами подпроекты так и, ставшую не нужной, часть истории этих подпроектов;
- должен ли будет пользователь предпринимать какие-либо действия для ручной настройки подпроектов после клонирования репозитория основного проекта;
- насколько трудоемким окажется вопрос анализа истории подключения подпроектов и конкретных ревизий, от которых берет начало подпроект;
- как повлияет то или иное средство на политику управления конфигурациями (Source Configuration Management) и, на сколько данное средство усложнит каждодневный труд инженеров.
Разумеется, данный перечень вопросов не может отразить всю полноту входных параметров, необходимых для правильного выбора, но для предварительного рассмотрения существующих средств, он вполне достаточен и, мы, говоря о проекте git-subrepo, призываем читателя рассматривать данный проект именно с этих позиций.
Инсталляция git-subrepo
Пакет git-subrepo, на стороне разработчика, может быть установлен как локально, в своем домашнем каталоге, так и на системном уровне.
В первом случае, достаточно клонировать репозиторий git-subrepo в нужный каталог, например, ~/bin:
bash-4.4$ cd ~/bin bash-4.4$ git clone https://github.com/ingydotnet/git-subrepo.git
и настроить переменные окружения
bash-4.4$ vim subrepo-env.sh #!/bin/sh export GIT_SUBREPO_ROOT="/home/username/bin/git-subrepo" export PATH="/home/username/bin/git-subrepo/lib:$PATH" export MANPATH="/home/username/bin/git-subrepo/man:$MANPATH" :wq bash-4.4$ source ./subrepo-env.sh
Если посмотреть переменные, определенные в Make-файле git-subrepo:
# Install variables: PREFIX ?= /usr/local INSTALL_LIB ?= $(DESTDIR)$(shell git --exec-path) INSTALL_EXT ?= $(INSTALL_LIB)/$(NAME).d INSTALL_MAN1 ?= $(DESTDIR)$(PREFIX)/share/man/man1
то легко выяснить, что на системном уровне git-subrepo устанавливается в каталог, где располагается Git:
bash-4.4$ bash-4.4$ git --exec-path /usr/libexec/git-core bash-4.4$
Таким образом команда для инсталляции git-subrepo может выглядеть, например, следующим образом:
bash-4.4$ make PREFIX=/usr install
Наличие переменной DESTDIR позволяет без дополнительных усилий (разумеется, если мы находимся не в cross-окружении) сделать пакет для любого дистрибутива Linux, что может быть полезно для DevOps инженеров.
Инсталлируем git-subrepo от имени суперпользователя:
bash-4.4$ bash-4.4$ cd git-subrepo/ bash-4.4$ make PREFIX=/usr install install -C -d -m 0755 /usr/libexec/git-core/ install -C -m 0755 lib/git-subrepo /usr/libexec/git-core/ install -C -d -m 0755 /usr/libexec/git-core/git-subrepo.d/ install -C -m 0755 lib/git-subrepo.d/help-functions.bash lib/git-subrepo.d/bash+.bash /usr/libexec/git-core/git-subrepo.d/ install -C -d -m 0755 /usr/share/man/man1/ install -C -m 0644 man/man1/git-subrepo.1 /usr/share/man/man1/ bash-4.4$
Для анализа возможностей git-subrepo нам понадобится простое тестовое окружение, где мы сможем воспроизвести стандартные сценарии работы.
Тестовое окружение
Создадим три каталога owner, remote, user, в которых разместим модели upstream- и локальных репозиториев разработчика и пользователя.
bash-4.4$ vim _init.sh #!/bin/sh CWD=`pwd` mkdir remote owner user cd remote git init --bare build-system.git git init --bare platform.git cd ../owner git clone $CWD/remote/build-system.git git clone $CWD/remote/platform.git cd build-system echo -e "\n[master] build-system 1.0.0\n" >README git add README git commit -m "init build-system master 1.0.0" git push cd ../platform echo -e "\n[master] platform 1.0.0\n" >README git add README git commit -m "init platform master 1.0.0" git push cd ../../user git clone $CWD/remote/build-system.git git clone $CWD/remote/platform.git cd $CWD :wq bash-4.4$ bash-4.4$ ./_init.sh bash-4.4$
Здесь,
Автор проекта и пользователи имеют собственные копии upstream-репозиториев на своих машинах, представленные в нашем примере в каталогах owner и user соответствено.
Задача автора состоит в том, чтобы включив подпроект builld-system в основное дерево platform обеспечить пользователям и участникам проекта следующие возможности:
- клонировать основной репозиторий с включенным в его состав подпроектом build-system и при этом не заботиться о настройке версиий или ревизий. То есть каждой ветке репозитория platform должна соответствовать определенная ревизия определенной ветки репозитория build-system и пользователь должен получать настроенное дерево исходников за одну операцию git-clone(1), без каких-либо дополнительных действий.
- поставлять свои изменения в upstream репозитории проекта, как в основной, так и во вспомогательный
- получать изменения, сделанные другими участниками проекта или пользователями, разумеется если они имеют соответствующие права.
Рассмотрим действия автора, которые он должен осуществить для реализации данных требований.
Подключение субпроекта
Для подключения нового поддерева следует воспользоваться командой git subrepo clone, которая по своему назначению похожа на команду git-clone(1). Обязательным параметром команды служит URL удаленного репозитория. Также можно указать каталог в котором будет располагаться подпроект и ветку удаленного репозитория. Мы будем работать с master-ветками, поэтому, в нашем примере, мы опускаем ненужные параметры комманд.
Итак, автор проекта, на своей рабочей машине, может подключить подпроект build-system с помощью команды git subrepo clone ../../remote/build-system.git/ build-system :
bash-4.4$ bash-4.4$ cd owner/platform/ bash-4.4$ git subrepo clone ../../remote/build-system.git/ build-system Subrepo '../../remote/build-system.git' (master) cloned into 'build-system'. bash-4.4$
Рассмотрим, какие изменения произошли в локальном репозитории platform:
bash-4.4$ bash-4.4$ git status On branch master Your branch is ahead of 'origin/master' by 1 commit. (use "git push" to publish your local commits) nothing to commit, working tree clean bash-4.4$ bash-4.4$ bash-4.4$ git subrepo status 1 subrepo: Git subrepo 'build-system': Remote URL: ../../remote/build-system.git Upstream Ref: b2f5079 Tracking Branch: master Pulled Commit: b2f5079 Pull Parent: b5e76a7 bash-4.4$
История подпроекта build-system не поставляется в основное дерево, мы имеем лишь один squashed-комит, который сопровождается справочной информацией. Данная информация поступает под версионный контроль в файле ./build-system/.gitrepo/config :
[subrepo] remote = ../../remote/build-system.git branch = master commit = b2f507918f2821cb7dd90c33223ed5cc3c9922a2 parent = b5e76a713f895565b06ee3ccfa29f19131ba06dd method = merge cmdver = 0.4.1
Информацию о подпроектах можно получать с помощью команды git subrepo config, например узнать ревизию upstream-проекта remote/build-system.git, которая только что пришла в основной репозиторий, можно в помощью команды:
bash-4.4$ bash-4.4$ git subrepo config build-system commit Subrepo 'build-system' option 'commit' has value 'b2f507918f2821cb7dd90c33223ed5cc3c9922a2'. bash-4.4$
Итак, мы получили последнюю версию master-ветки upstream-репозитория remote/build-system.git и поместили ее в подкаталог build-system основного проекта platform.
Для поставки этих изменений в upstream-репозиторий remote/platform.git, автору необходимо выполнить команду git push:
bash-4.4$ bash-4.4$ git push Enumerating objects: 7, done. Counting objects: 100% (7/7), done. Delta compression using up to 4 threads Compressing objects: 100% (4/4), done. Writing objects: 100% (6/6), 849 bytes | 849.00 KiB/s, done. Total 6 (delta 0), reused 0 (delta 0) To /home/prog/0.4.1/remote/platform.git b5e76a7..6b831e4 master -> master bash-4.4$
Более подробную информацию о командах git subrepo можно получить из файла ReadMe.pod или в командной строке
bash-4.4$ git subrepo help
например:
bash-4.4$ git subrepo help clone
Рассмотрим теперь все происходящее со стороны пользователя.
Получение кода пользователями
На данный момент, когда пользователь еще не получил обновления upstream-репозитория platform.git, его копия содержит один файл README
bash-4.4$ bash-4.4$ cd user/platform/ bash-4.4$ ls README bash-4.4$
содержащий одну строку:
bash-4.4$ bash-4.4$ cat README [master] platform 1.0.0 bash-4.4$
После снятия изменений upstream-репозитория
bash-4.4$ bash-4.4$ git pull remote: Enumerating objects: 7, done. remote: Counting objects: 100% (7/7), done. remote: Compressing objects: 100% (4/4), done. remote: Total 6 (delta 0), reused 0 (delta 0) Unpacking objects: 100% (6/6), done. From /home/prog/0.4.1/remote/platform b5e76a7..6b831e4 master -> origin/master Updating b5e76a7..6b831e4 Fast-forward build-system/.gitrepo/config | 12 ++++++++++++ build-system/README | 3 +++ 2 files changed, 15 insertions(+) create mode 100644 build-system/.gitrepo/config create mode 100644 build-system/README bash-4.4$
пользователь будет иметь в своем распоряжении код подпроекта build-system именно той ревизии, которую определил автор проекта. Пользователь может в любой момент уточнить текущую ревизию с помощью команды config:
bash-4.4$ bash-4.4$ git subrepo config build-system/ commit Subrepo 'build-system' option 'commit' has value 'b2f507918f2821cb7dd90c33223ed5cc3c9922a2'. bash-4.4$
Примечательно то, что у пользователя нет необходимости осуществлять дополнительные настройки и он может положиться на то, что автор проекта поставил ему именно ту ревизию build-system, которая необходима для работы текущей версии platform.
Именно этого добивался автор проекта.
Поставка изменений в upstream-проект
Допустим теперь, что наш пользователь является участником проекта и ему разрешено поставлять изменения не только в upstream-репозиторий remote/platform.git, но еще и в upstream-репозиторий подпроекта remote/build-system.git.
Тогда, если пользователь сделает изменения:
bash-4.4$ bash-4.4$ cd build-system/ bash-4.4$ vim README bash-4.4$ cat README [master] build-system 1.0.1 bash-4.4$ bash-4.4$ git commit -a -m "update BS version to 1.0.1" [master d30b001] update BS version to 1.0.1 1 file changed, 1 insertion(+), 1 deletion(-) bash-4.4$ bash-4.4$ cd .. bash-4.4$ git log commit d30b001286b08708f5c30c1f5346a90e4339f969 (HEAD -> master) Author: user <___@_____> Date: Tue Oct 30 10:49:32 2018 +0300 update BS version to 1.0.1 . . . bash-4.4$
он сможет поставить их в upstream-репозитории следующим образом:
bash-4.4$ bash-4.4$ git subrepo push build-system/ Subrepo 'build-system' pushed to '../../remote/build-system.git' (master). bash-4.4$
Здесь важно заметить, что ...
Поскольку файлы конфигурации подпроектов .gitrepo/config хранятся под версионным контролем, пользователю необходимо отослать изменения статуса подпроекта в upstream-репозиторий основного проекта remote/platform.git.
То есть пользователь не должен забывать о проверке статуса локального репозитория и вовремя выполнять команду git-push(1).
bash-4.4$ bash-4.4$ git status On branch master Your branch is ahead of 'origin/master' by 2 commits. (use "git push" to publish your local commits) nothing to commit, working tree clean bash-4.4$ bash-4.4$ git push Enumerating objects: 14, done. Counting objects: 100% (14/14), done. Delta compression using up to 4 threads Compressing objects: 100% (7/7), done. Writing objects: 100% (9/9), 992 bytes | 992.00 KiB/s, done. Total 9 (delta 1), reused 0 (delta 0) To /home/prog/0.4.1/remote/platform.git d00be9f..deccb66 master -> master bash-4.4$
В противном случае, при последующем снятии изменений upstream-репозитория, он получит merge-конфликт.
Разумеется, здесь нет ни чего необычного, однако, после выполнения команды git subrepo push ..., легко забыть о состоянии локальной копии основного репозитория.
Непосредственная работа с upstream-репозиторием
Рассмотрим теперь, что произошло в upstream-репозитории remote/build-system.git
bash-4.4$ bash-4.4$ cd owner/build-system/ bash-4.4$ bash-4.4$ git pull remote: Enumerating objects: 5, done. remote: Counting objects: 100% (5/5), done. remote: Total 3 (delta 0), reused 0 (delta 0) Unpacking objects: 100% (3/3), done. From /home/prog/0.4.1/remote/build-system b2f5079..d229920 master -> origin/master Updating b2f5079..d229920 Fast-forward README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) bash-4.4$ bash-4.4$ git log commit d229920c7de34405bc7b8d47f36d420987687908 (HEAD -> master, origin/master) Author: user <___@_____> Date: Tue Oct 30 10:49:32 2018 +0300 update BS version to 1.0.1 commit b2f507918f2821cb7dd90c33223ed5cc3c9922a2 Author: user <___@_____> Date: Tue Oct 30 10:05:30 2018 +0300 init build-system master 1.0.0 bash-4.4$
То есть автор проекта получил изменения, внесенные участником проекта.
Разумеется, автор может вносить изменения непосредственно в upstream-репозиторий проекта build-system:
bash-4.4$ bash-4.4$ cd owner/build-system/ bash-4.4$ bash-4.4$ vim README bash-4.4$ cat README [master] build-system 1.0.2 bash-4.4$ git commit -a -m "update build-system version to 1.0.2" [master 8255f59] update build-system version to 1.0.2 1 file changed, 1 insertion(+), 1 deletion(-) bash-4.4$ git push Enumerating objects: 5, done. Counting objects: 100% (5/5), done. Writing objects: 100% (3/3), 281 bytes | 281.00 KiB/s, done. Total 3 (delta 0), reused 0 (delta 0) To /home/prog/0.4.1/remote/build-system.git d229920..8255f59 master -> master bash-4.4$
И все участники, а также пользователи основного проекта смогут получать эти изменения с помощью команды git subrepo pull
bash-4.4$ bash-4.4$ cd owner/platform/ bash-4.4$ bash-4.4$ git subrepo pull build-system/ Subrepo 'build-system' pulled from '../../remote/build-system.git' (master). bash-4.4$ git status On branch master Your branch is ahead of 'origin/master' by 1 commit. (use "git push" to publish your local commits) nothing to commit, working tree clean bash-4.4$ git push Enumerating objects: 11, done. Counting objects: 100% (11/11), done. Delta compression using up to 4 threads Compressing objects: 100% (4/4), done. Writing objects: 100% (6/6), 670 bytes | 670.00 KiB/s, done. Total 6 (delta 1), reused 0 (delta 0) To /home/prog/0.4.1/remote/platform.git 6b831e4..b6f4a7b master -> master bash-4.4$
Выводы
Если у разработчика нет необходимости хранить истории подпроектов в основном репозитории и, при поставке кода он оперирует ветками, а не фиксированными тегами, то git-subrepo вполне подходит для организации повседневной работы.
Условно, к числу недостатков git-subrepo можно отнести то обстоятельство, что операция git subrepo clone возможна только по отношению к веткам подпроекта. Иными словами, пользователь не может подключить подпроект ссылаясь на его фиксированный тэг или определенную ревизию, то есть команды типа
bash-4.4$ git subrepo clone ../../remote/build-system.git build-system -t 1.0.1 bash-4.4$ git subrepo clone ../../remote/build-system.git build-system 7f5d1113eb0bc6
не допустимы.