Новости и статьи

Среда разработки встроенных систем или дистрибутивов на основе GNU/Linux. Здесь вы можете найти новости проекта, статьи и заметки, касающиеся разработки дистрибутива Radix cross Linux.

Git Subrepo

1 ноября 2018 г.

Проект 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$

Здесь,

owner
рабочий каталог автора проектов;
remote
каталог представляющий сервер автора проектов, на котором располагаются upstream-репозитории основного проекта platform.git и подпроекта build-system.git;
user
рабочий каталог пользователя или участника команды разработчиков.

Автор проекта и пользователи имеют собственные копии 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$

Следует упомянуть о том, что оригинальный пакет git-subrepo сохраняет информацию о подпроектах не в файле .gitrepo/config, а в файле .gitrepo. Если вы предпочитаете хранить информацию в скрытом подкаталоге, то можете выбрать ветку git-subrepo-0.3.2 или git-subrepo-0.4.1 дочернего репозитория git-subrepo.

Итак, мы получили последнюю версию 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

не допустимы.

ЛИТЕРАТУРА:

  1. Git – Subtree Merging
  2. Mastering Git subtrees
  3. Mastering Git submodules
  4. Git Subrepo