Git Subtree в деталях
Принимая решение об использовании того или иного средства в собственных проектах, инженеру приходится не только изучать сопроводительную документацию, но и проводить серию экспериментов для того, чтобы избежать потенциальных проблем в будущем. Если же речь идет о CM-политике, рассчитанной на длительную перспективу, цена ошибки выбора становится достаточно высока.
Целью настоящей работы является практическое изучение средства управления поддеревьями Git.
tags
Начиная с ревизии 1.7.11 upstream-репозиторий Git, в каталоге contrib/subtree, содержит средство автоматизации работы с поддеревьями.
Сервис git-subtree(1) фактически является полезной надстройкой, использующей функции git-read-tree(1) и git-write-tree(1). Поэтому ссылки в командах git-subtree(1) add/pull/push:
git subtree add --prefix=<subdir> <remote> <ref>
могут представлять собой, как имена веток, так и имена тегов удаленного репозитория.
Кроме того, если заранее добавить удаленный репозиторий в конфигурационный файл локального репозитория .git/config, с помошью команды:
bash-4.4$ git remote add build-system ../../remote/build-system.git
где build-system является именем удаленного репозитория ../../remote/build-system.git, то в дальнейшем, при использовании команд git-subtree(1) add/pull/push, мы сможем ссылаться на upstream-репозиторий remote/build-system.git по имени.
На данный момент git-subtree(1) практически не развивается, а лишь поддерживается в актуальном состоянии для текущей степени развития проекта Git.
Однако git-subtree(1) является наиболее популярным и мощным средством работы с поддеревьями.
Тестовое окружение
В предыдущей статье, посвященной git-subrepo(1), мы использовали простую структуру каталогов с тестовыми репозиториями для демонстрации работы функций на практике. Воспроизведем и теперь такое окружение:
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$ chmod a+x ./_init.sh bash-4.4$ ./_init.sh bash-4.4$
Здесь,
В качестве целей изучения возможностей git-subtree(1) мы будем рассматривать всё те же задачи, о которых мы говорили в статье Git Subrepo, но с учетом различий между этими двумя средствами.
Подключение поддерева
Запомним текущее состояние репозитория remote/platform.git:
bash-4.4$ bash-4.4$ cd owner/platform/ bash-4.4$ git log commit 7fad4becbd13258216fb95cbe9d987dd33f0be6d (HEAD -> master, origin/master) Author: user <___@_______> Date: Thu Nov 1 20:16:33 2018 +0300 init platform master 1.0.0 bash-4.4$
и подключим master-ветку upstream-репозитория remote/build-system.git в каталог build-system:
bash-4.4$ bash-4.4$ git subtree add --prefix=build-system ../../remote/build-system.git/ master git fetch ../../remote/build-system.git/ master warning: no common commits remote: Enumerating objects: 3, done. remote: Counting objects: 100% (3/3), done. remote: Total 3 (delta 0), reused 0 (delta 0) Unpacking objects: 100% (3/3), done. From ../../remote/build-system * branch master -> FETCH_HEAD Added dir 'build-system' bash-4.4$
Рассмотрим новое состояние локальной копии репозитория remote/platform.git:
bash-4.4$ bash-4.4$ git log --graph * commit 47905bcb80be6f7cb3030513986fad4df548f812 (HEAD -> master) |\ Merge: 7fad4be 783c6d5 | | Author: user <___@_______> | | Date: Thu Nov 1 20:20:20 2018 +0300 | | | | Add 'build-system/' from commit '783c6d5af1100e9665f930c818c861ff011bed19' | | | | git-subtree-dir: build-system | | git-subtree-mainline: 7fad4becbd13258216fb95cbe9d987dd33f0be6d | | git-subtree-split: 783c6d5af1100e9665f930c818c861ff011bed19 | | git-subtree-repo: ../../remote/build-system.git/ | | git-subtree-ref: master | | | * commit 783c6d5af1100e9665f930c818c861ff011bed19 | Author: user <___@_______> | Date: Thu Nov 1 20:16:33 2018 +0300 | | init build-system master 1.0.0 | * commit 7fad4becbd13258216fb95cbe9d987dd33f0be6d (origin/master) Author: user <___@_______> Date: Thu Nov 1 20:16:33 2018 +0300 init platform master 1.0.0 bash-4.4$
Здесь следует обратить внимание на сообщение, которое оставила команда git-subtree(1) add. Фактически, с помощью данной команды, в репозиторий platform мы поставили разность:
bash-4.4$ bash-4.4$ git diff 7fad4becbd13258216fb95cbe9d987dd33f0be6d 47905bcb80be6f7cb3030513986fad4df548f812 diff --git a/build-system/README b/build-system/README new file mode 100644 index 0000000..73a41c7 --- /dev/null +++ b/build-system/README @@ -0,0 +1,3 @@ + +[master] build-system 1.0.0 + bash-4.4$
Далее, когда история изменений уйдет несколько дальше, мы более подробно изучим детали подключения поддеревьев, а сейчас поставим наши изменения в upstream-репозиторий remote/platform.git:
bash-4.4$ bash-4.4$ git push Enumerating objects: 6, done. Counting objects: 100% (6/6), done. Delta compression using up to 4 threads Compressing objects: 100% (3/3), done. Writing objects: 100% (5/5), 582 bytes | 582.00 KiB/s, done. Total 5 (delta 0), reused 0 (delta 0) To ../../remote/platform.git 7fad4be..47905bc master -> master bash-4.4$
и еще раз посмотрим на сообщение команды git-subtree(1) add:
Add 'build-system/' from commit '783c6d5af1100e9665f930c818c861ff011bed19' git-subtree-dir: build-system git-subtree-mainline: 7fad4becbd13258216fb95cbe9d987dd33f0be6d git-subtree-split: 783c6d5af1100e9665f930c818c861ff011bed19 git-subtree-repo: ../../remote/build-system.git/ git-subtree-ref: master
Эти сообщения полезны для того, чтобы, в случае необходимости, можно было найти историю подключения и текущее состояние поддерева. Оригинальная команда git-subtree(1) не добавляет последние две строки сообщения. Мы немного доработали эту утилиту для того, чтобы было легче искать информацию о том, когда и от какой именно ветки удаленного репозитория было создано то или иное поддерево нашего проекта.
Полный diff-файл наших изменений вы можете получить следующим образом:
bash-4.4$ bash-4.4$ git clone https://github.com/radix-platform/git.git bash-4.4$ cd git bash-4.4$ git checkout git-subtree-2.19.1 bash-4.4$ git diff v2.19.1 > ../git-subtree-2.19.1.patch bash-4.4$
Для придания нашим примерам более реалистичного характера, сделаем изменения в upstream-репозитории remote/build-system.git:
bash-4.4$ bash-4.4$ cd owner/build-system/ bash-4.4$ vim README bash-4.4$ cat README [master] build-system 1.0.1 bash-4.4$
Сохраним эти изменения:
bash-4.4$ bash-4.4$ git add README bash-4.4$ git commit -m "update build-system version to 1.0.1" [master e5c5446] update build-system version to 1.0.1 1 file changed, 1 insertion(+), 1 deletion(-) bash-4.4$
и передадим их в upstream-репозиторий remote/build-system.git:
bash-4.4$ bash-4.4$ git push Enumerating objects: 5, done. Counting objects: 100% (5/5), done. Writing objects: 100% (3/3), 274 bytes | 274.00 KiB/s, done. Total 3 (delta 0), reused 0 (delta 0) To ../../remote/build-system.git 783c6d5..e5c5446 master -> master bash-4.4$
Итак, ревизия репозитория build-system изменилась с 783c6d5 на e5c5446:
bash-4.4$ bash-4.4$ git log commit e5c5446967599065dc02a269d8fcfc2c1d3c4f65 (HEAD -> master, origin/master) Author: user <___@_______> Date: Thu Nov 1 20:26:52 2018 +0300 update build-system version to 1.0.1 commit 783c6d5af1100e9665f930c818c861ff011bed19 Author: user <___@_______> Date: Thu Nov 1 20:16:33 2018 +0300 init build-system master 1.0.0 bash-4.4$
Запомним это состояние и перейдем к работе с репозиторием-контейнером remote/platform.git.
Получение изменений из upstream-репозитория поддерева
Допустим, что мы еще не знаем об изменениях в upstream-репозитории поддерева и работаем над усовершенствованием кода platform:
bash-4.4$ bash-4.4$ cd owner/platform/ bash-4.4$ vim README bash-4.4$ cat README [master] platform 1.0.1 bash-4.4$ bash-4.4$ git add README bash-4.4$ git commit -m "update platform version to 1.0.1" [master 442c9e9] update platform version to 1.0.1 1 file changed, 1 insertion(+), 1 deletion(-) bash-4.4$ bash-4.4$ git push Enumerating objects: 5, done. Counting objects: 100% (5/5), done. Delta compression using up to 4 threads Compressing objects: 100% (2/2), done. Writing objects: 100% (3/3), 306 bytes | 306.00 KiB/s, done. Total 3 (delta 0), reused 0 (delta 0) To ../../remote/platform.git 47905bc..442c9e9 master -> master bash-4.4$
В результате нашей работы мы получили следующее состояние репозитория remote/platform.git:
bash-4.4$ bash-4.4$ git log --graph * commit 442c9e94c9890032fb2f3123661345d465e2849f (HEAD -> master, origin/master) | Author: user <___@_______> | Date: Thu Nov 1 20:41:40 2018 +0300 | | update platform version to 1.0.1 | * commit 47905bcb80be6f7cb3030513986fad4df548f812 |\ Merge: 7fad4be 783c6d5 | | Author: user <___@_______> | | Date: Thu Nov 1 20:20:20 2018 +0300 | | | | Add 'build-system/' from commit '783c6d5af1100e9665f930c818c861ff011bed19' | | | | git-subtree-dir: build-system | | git-subtree-mainline: 7fad4becbd13258216fb95cbe9d987dd33f0be6d | | git-subtree-split: 783c6d5af1100e9665f930c818c861ff011bed19 | | git-subtree-repo: ../../remote/build-system.git/ | | git-subtree-ref: master | | | * commit 783c6d5af1100e9665f930c818c861ff011bed19 | Author: user <___@_______> | Date: Thu Nov 1 20:16:33 2018 +0300 | | init build-system master 1.0.0 | * commit 7fad4becbd13258216fb95cbe9d987dd33f0be6d Author: user <___@_______> Date: Thu Nov 1 20:16:33 2018 +0300 init platform master 1.0.0 bash-4.4$
Теперь, было бы не плохо узнать, что происходило в upstream-репозитории поддерева build-system в то время, пока мы занимались совершенствованием кода в основном репозитории нашего проекта. Пролистаем сначала поддеревья с помощью команды git subtree --list:
bash-4.4$ bash-4.4$ git subtree --list build-system ../../remote/build-system.git/ branch master HEAD bash-4.4$
Данная команда, в простом формате, предстваляет каталог-поддерева, URL upstream-репозитория поддерева, тип ссылки (ветка или тэг), название ссылки, а также ревизию указанной ветки или тэга репозитория, код которого мы поместили в наше поддерево. Однако мы помним, что разработка подпроекта build-system ушла вперед и указание на голову master-ветки уже не действительно. Скорее это сообщение о том, что бы мы хотели иметь в нашем репозитории, а не действительное положение дел.
Для того, чтобы узнать, насколько продвинулся код в upstream-репозитории поддерева, нам необходимо так же пролистать поддеревья, но с использованием опции -d:
bash-4.4$ bash-4.4$ git subtree -d --list Looking for externals... Commit: 47905bcb80be6f7cb3030513986fad4df548f812 build-system ../../remote/build-system.git/ branch master HEAD The 'build-system' subtree seems not updated: original revision: 783c6d5af1100e9665f930c818c861ff011bed19 remote revision: e5c5446967599065dc02a269d8fcfc2c1d3c4f65 You can update 'build-system' subtree by following command: git subtree pull --prefix=build-system ../../remote/build-system.git/ master bash-4.4$
Теперь, полученный вывод говорит о том, что пока мы работали над кодом основного репозитория, master-ветка upstream-репозитория поддерева build-system ушла вперед. Кроме того, команда git subtree -d --list вывела подсказку о том, что мы можем получить изменения upstream-репозитория поддерева следующим образом:
bash-4.4$ bash-4.4$ git subtree pull --prefix=build-system ../../remote/build-system.git/ master 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 ../../remote/build-system * branch master -> FETCH_HEAD hint: Waiting for your editor to close the file...
данная команда, поскольку мы не задали -m "commit message", открывает редактор с текстом сообщения:
Merge commit 'e5c5446967599065dc02a269d8fcfc2c1d3c4f65' # Please enter a commit message to explain why this merge is necessary, # especially if it merges an updated upstream into a topic branch. # # Lines starting with '#' will be ignored, and an empty message aborts # the commit.
Заменим этот текст на более информативный:
Pull changes from master of upstream build-system.git repository:
Merge commit 'e5c5446967599065dc02a269d8fcfc2c1d3c4f65'
После сохранения данного сообщения и закрытия редактора, мы получим следующий вывод:
Merge made by the 'recursive' strategy. build-system/README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) bash-4.4$
То есть, мы получили изменения upstream-репозитория remote/build-system.git и сохранили их в поддереве build-system локальной копии основного репозитория remote/platform.git.
Проверим статус локального репозитория:
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$
Для того, чтобы остальные пользователи проекта смогли получить эти изменения, мы должны поставить их в upstream-репозиторий remote/platform.git:
bash-4.4$ bash-4.4$ git push Enumerating objects: 9, done. Counting objects: 100% (8/8), done. Delta compression using up to 4 threads Compressing objects: 100% (3/3), done. Writing objects: 100% (5/5), 583 bytes | 583.00 KiB/s, done. Total 5 (delta 0), reused 0 (delta 0) To ../../remote/platform.git 442c9e9..ea52eab master -> master bash-4.4$
Посмотрим, что теперь содержит локальная копия репозитория platform, а также upstream-репозиторий remote/platform.git:
bash-4.4$ bash-4.4$ git log --graph * commit ea52eabd5910159efabd80adcf522f22bf6a2af2 (HEAD -> master, origin/master) |\ Merge: 442c9e9 e5c5446 | | Author: user <___@_______> | | Date: Thu Nov 1 20:48:05 2018 +0300 | | | | Pull changes from master of upstream build-system.git repository. | | | | Merge commit 'e5c5446967599065dc02a269d8fcfc2c1d3c4f65' | | | * commit e5c5446967599065dc02a269d8fcfc2c1d3c4f65 | | Author: user <___@_______> | | Date: Thu Nov 1 20:26:52 2018 +0300 | | | | update build-system version to 1.0.1 | | * | commit 442c9e94c9890032fb2f3123661345d465e2849f | | Author: user <___@_______> | | Date: Thu Nov 1 20:41:40 2018 +0300 | | | | update platform version to 1.0.1 | | * | commit 47905bcb80be6f7cb3030513986fad4df548f812 |\ \ Merge: 7fad4be 783c6d5 | |/ Author: user <___@_______> | | Date: Thu Nov 1 20:20:20 2018 +0300 | | | | Add 'build-system/' from commit '783c6d5af1100e9665f930c818c861ff011bed19' | | | | git-subtree-dir: build-system | | git-subtree-mainline: 7fad4becbd13258216fb95cbe9d987dd33f0be6d | | git-subtree-split: 783c6d5af1100e9665f930c818c861ff011bed19 | | git-subtree-repo: ../../remote/build-system.git/ | | git-subtree-ref: master | | | * commit 783c6d5af1100e9665f930c818c861ff011bed19 | Author: user <___@_______> | Date: Thu Nov 1 20:16:33 2018 +0300 | | init build-system master 1.0.0 | * commit 7fad4becbd13258216fb95cbe9d987dd33f0be6d Author: user <___@_______> Date: Thu Nov 1 20:16:33 2018 +0300 init platform master 1.0.0 bash-4.4$
Мы видим, что начальное состояние репозитория remote/build-system.git, в момент подключения его в качестве поддерева платформы, было равно 783c6d5af1100e9665f930c818c861ff011bed19. Однако пока мы работали над кодом в репозитории platform, состояние репозитория изменилось и стало равным e5c5446967599065dc02a269d8fcfc2c1d3c4f65.
Начальное состояние build-system (783c6d5af1100e9665f930c818c861ff011bed19) уже было в истории репозитория platform, когда он находился в точке 442c9e94c9890032fb2f3123661345d465e2849f. Следовательно, нам надо взять состояние platform в точке 442c9e94c9890032fb2f3123661345d465e2849f и состояние build-system в точке e5c5446967599065dc02a269d8fcfc2c1d3c4f65, вычислить разность между ними, и наложить полученную разность на master-ветку репозитория platform.
Это стандартная операция слияния веток, суть которой можно выразить формулой
p[n] = p[n-1] + diff(p[n-1], b[n])
где,
p[n] = ea52eabd5910159efabd80adcf522f22bf6a2af2, p[n-1] = 442c9e94c9890032fb2f3123661345d465e2849f, b[n] = e5c5446967599065dc02a269d8fcfc2c1d3c4f65.
Здесь p выступает в роли master-ветки, а b, – играет роль ветки, отделившейся ранее от master с целью создания новой функциональности.
Рассмотрим еще раз сообщение, которое для нас приготовила утилита git-subtree(1) во время выполнения команды git-subtree-pull:
git subtree pull --prefix=build-system ../../remote/build-system.git/ master
Merge commit 'e5c5446967599065dc02a269d8fcfc2c1d3c4f65' # Please enter a commit message to explain why this merge is necessary, # especially if it merges an updated upstream into a topic branch. # # Lines starting with '#' will be ignored, and an empty message aborts # the commit.
В этом сообщении есть существенная для нас информация, а именно состояние
b[n] = e5c5446967599065dc02a269d8fcfc2c1d3c4f65
в котором находилась master-ветка репозитория remote/build-system.git перед "заливкой" на master-ветку репозитория platform.
Конечно, не очень удобно при выполнении команды git-subtree-pull вручную редактировать commit message, однако, другого способа передать нам состояние
b[n] = e5c5446967599065dc02a269d8fcfc2c1d3c4f65
у утилиты git-subtree(1), в данном случае, просто не существует.
Если бы мы воспользовались управлением -m
git subtree pill -m "Our own message" ...
то мы бы потеряли значение состояния b[n] и, наш коментарий оказался не информативным, и, стало быть, совершенно бесполезным.
Следует заметить, что после того, как состояние master-ветки репозитория build-system сдвинулось с изначальной точки монтирования 47905bcb80be6f7cb3030513986fad4df548f812, мы всегда будем получать уведомление об изменениях в remote/build-system.git во время просмотра списка подключенных поддеревьев. Иными словами, использование опции -d в команде:
git subtree -d --list
будет всегда приводить к выводу сообщения, подобного следующему:
bash-4.4$ bash-4.4$ git subtree -d --list Looking for externals... Commit: 47905bcb80be6f7cb3030513986fad4df548f812 build-system ../../remote/build-system.git/ branch master HEAD The 'build-system' subtree seems not updated: original revision: 783c6d5af1100e9665f930c818c861ff011bed19 remote revision: e5c5446967599065dc02a269d8fcfc2c1d3c4f65 You can update 'build-system' subtree by following command: git subtree pull --prefix=build-system ../../remote/build-system.git/ master bash-4.4$
Происходить это будет по тому, что вся информация о подключенном поддереве находится в сообщении, сопроводившим коммит 47905bcb80be6f7cb3030513986fad4df548f812:
bash-4.4$ bash-4.4$ git show 47905bcb80be6f7cb3030513986fad4df548f812 commit 47905bcb80be6f7cb3030513986fad4df548f812 Merge: 7fad4be 783c6d5 Author: user <___@_______> Date: Thu Nov 1 20:20:20 2018 +0300 Add 'build-system/' from commit '783c6d5af1100e9665f930c818c861ff011bed19' git-subtree-dir: build-system git-subtree-mainline: 7fad4becbd13258216fb95cbe9d987dd33f0be6d git-subtree-split: 783c6d5af1100e9665f930c818c861ff011bed19 git-subtree-repo: ../../remote/build-system.git/ git-subtree-ref: master diff --cc build-system/README index 0000000,0000000..73a41c7 new file mode 100644 --- /dev/null +++ b/build-system/README @@@ -1,0 -1,0 +1,3 @@@ ++ ++[master] build-system 1.0.0 ++ bash-4.4$
и нет никакого другого хранилища данной информации.
Единственно, теперь после каждого обновления master-ветки репозитория remote/build-system.git, на стороне platform, при выполнении команды
git subtree -d --list
будет меняться лишь значение строки
remote revision: e5c5446967599065dc02a269d8fcfc2c1d3c4f65
и нам самим будет необходимо принимать решения о том, нужны ли нам новые изменения поддерева build-system или, на данный момент, не нужны.
Однако нам не составит труда выполнять команду pull так часто, как нам это будет необходимо, поскольку если репозиторий remote/build-system.git не имел актуальных изменений, команда:
git subtree pull --prefix=build-system ../../remote/build-system.git/ master
выдаст адекватное сообщение:
bash-4.4$ bash-4.4$ git subtree pull --prefix=build-system ../../remote/build-system.git/ master From ../../remote/build-system * branch master -> FETCH_HEAD Already up to date. bash-4.4$
Получение кода пользователями
Теперь все пользователи upstream-репозитория remote/platform.git могут получить полностью настроенное дерево исходного кода с помощью одной команды git-pull(1):
bash-4.4$ bash-4.4$ cd user/platform/ bash-4.4$ bash-4.4$ git pull remote: Enumerating objects: 15, done. remote: Counting objects: 100% (15/15), done. remote: Compressing objects: 100% (8/8), done. remote: Total 13 (delta 0), reused 0 (delta 0) Unpacking objects: 100% (13/13), done. From ../../remote/platform 7fad4be..ea52eab master -> origin/master Updating 7fad4be..ea52eab Fast-forward README | 2 +- build-system/README | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 build-system/README bash-4.4$
Кроме того, пользователи смогут отслеживать историю развития не только основного репозитория проекта, но и всех его поддеревьев:
bash-4.4$ bash-4.4$ git log -3 --graph * commit ea52eabd5910159efabd80adcf522f22bf6a2af2 (HEAD -> master, origin/master, origin/HEAD) |\ Merge: 442c9e9 e5c5446 | | Author: user <___@_______> | | Date: Thu Nov 1 20:48:05 2018 +0300 | | | | Pull changes from master of upstream build-system.git repository. | | | | Merge commit 'e5c5446967599065dc02a269d8fcfc2c1d3c4f65' | | | * commit e5c5446967599065dc02a269d8fcfc2c1d3c4f65 | | Author: user <___@_______> | | Date: Thu Nov 1 20:26:52 2018 +0300 | | | | update build-system version to 1.0.1 | | * | commit 442c9e94c9890032fb2f3123661345d465e2849f | | Author: user <___@_______> | | Date: Thu Nov 1 20:41:40 2018 +0300 | | | | update platform version to 1.0.1 bash-4.4$
Поставка изменений поддерева в upstream-репозиторий
Запомним состояние файлов, а также самого репозитория platform:
bash-4.4$ bash-4.4$ git log -3 --graph * commit ea52eabd5910159efabd80adcf522f22bf6a2af2 (HEAD -> master, origin/master, origin/HEAD) |\ Merge: 442c9e9 e5c5446 | | Author: user <___@_______> | | Date: Thu Nov 1 20:48:05 2018 +0300 | | | | Pull changes from master of upstream build-system.git repository. | | | | Merge commit 'e5c5446967599065dc02a269d8fcfc2c1d3c4f65' | | | * commit e5c5446967599065dc02a269d8fcfc2c1d3c4f65 | | Author: user <___@_______> | | Date: Thu Nov 1 20:26:52 2018 +0300 | | | | update build-system version to 1.0.1 | | * | commit 442c9e94c9890032fb2f3123661345d465e2849f | | Author: user <___@_______> | | Date: Thu Nov 1 20:41:40 2018 +0300 | | | | update platform version to 1.0.1 bash-4.4$
Внесем изменения в поддерево build-system. Для этого отредактируем файл platform/build-system/README:
bash-4.4$ bash-4.4$ cd owner/platform/ bash-4.4$ bash-4.4$ vim build-system/README bash-4.4$ cat build-system/README [master] build-system 1.0.2 bash-4.4$ bash-4.4$ git add build-system/README bash-4.4$ git commit -m "build-system is updated to version 1.0.2 from platform side" [master abaa2c5] build-system is updated to version 1.0.2 from platform side 1 file changed, 1 insertion(+), 1 deletion(-) bash-4.4$
Но не будем заносить эти изменения в origin/master репозитория platform. То есть не будем выполнять команду git-push(1), а выполним git-subtree-push напямую в origin репозиторий remote/build-system.git:
bash-4.4$ bash-4.4$ git subtree push --prefix=build-system ../../remote/build-system.git/ master git push using: ../../remote/build-system.git/ master Enumerating objects: 5, done. Counting objects: 100% (5/5), done. Writing objects: 100% (3/3), 290 bytes | 290.00 KiB/s, done. Total 3 (delta 0), reused 0 (delta 0) To ../../remote/build-system.git/ e5c5446..0673142 0673142942ccf53514a276e855a98514952bb713 -> master bash-4.4$
Пролистаем поддеревья и убедимся в том, что HEAD master-ветки оригинального репозитория remote/build-system.git ушел вперед:
bash-4.4$ bash-4.4$ git subtree -d --list Looking for externals... Commit: 47905bcb80be6f7cb3030513986fad4df548f812 build-system ../../remote/build-system.git/ branch master HEAD The 'build-system' subtree seems not updated: original revision: 783c6d5af1100e9665f930c818c861ff011bed19 remote revision: 0673142942ccf53514a276e855a98514952bb713 You can update 'build-system' subtree by following command: git subtree pull --prefix=build-system ../../remote/build-system.git/ master bash-4.4$
Кроме того, посмотрим на состояние локальной копии репозитория platform, помня о том, что последний коммит еще не поставлен нами в upstream-репозиторий:
bash-4.4$ bash-4.4$ git log -4 --graph * commit abaa2c5edd49dd0cf395c99877b4711d0170af37 (HEAD -> master) | Author: user <___@_______> | Date: Thu Nov 1 21:48:40 2018 +0300 | | build-system is updated to version 1.0.2 from platform side | * commit ea52eabd5910159efabd80adcf522f22bf6a2af2 (origin/master) |\ Merge: 442c9e9 e5c5446 | | Author: user <___@_______> | | Date: Thu Nov 1 20:48:05 2018 +0300 | | | | Pull changes from master of upstream build-system.git repository. | | | | Merge commit 'e5c5446967599065dc02a269d8fcfc2c1d3c4f65' | | | * commit e5c5446967599065dc02a269d8fcfc2c1d3c4f65 | | Author: user <___@_______> | | Date: Thu Nov 1 20:26:52 2018 +0300 | | | | update build-system version to 1.0.1 | | * | commit 442c9e94c9890032fb2f3123661345d465e2849f | | Author: user <___@_______> | | Date: Thu Nov 1 20:41:40 2018 +0300 | | | | update platform version to 1.0.1 bash-4.4$
Правильный путь поставки изменений в upstream-репозиторий основного проекта, состоит в том, чтобы все наши изменения поддерева не попадали непосредственно в основной репозиторий, а приходили из upstream-репозитория поддерева так, как будто мы их получали с помощью команды git-subtree-pull. Далее мы поясним смысл наших действий, а сейчас, для того, чтобы избежать последующих неприятностей, сделаем revert последнего коммита (abaa2c5edd49dd0cf395c99877b4711d0170af37) в локальную копию репозитория platform:
bash-4.4$ bash-4.4$ git reset --hard HEAD^ HEAD is now at ea52eab Pull changes from master of upstream build-system.git repository. bash-4.4$
чтобы затем "снять" этот же самый коммит обратно, но уже из оригинального upstream-репозитория remote/build-system.git. Но прежде убедимся в том, что мы удалили последний коммит abaa2c5edd49dd0cf395c99877b4711d0170af37:
bash-4.4$ bash-4.4$ git log -3 --graph * commit ea52eabd5910159efabd80adcf522f22bf6a2af2 (HEAD -> master, origin/master) |\ Merge: 442c9e9 e5c5446 | | Author: user <___@_______> | | Date: Thu Nov 1 20:48:05 2018 +0300 | | | | Pull changes from master of upstream build-system.git repository. | | | | Merge commit 'e5c5446967599065dc02a269d8fcfc2c1d3c4f65' | | | * commit e5c5446967599065dc02a269d8fcfc2c1d3c4f65 | | Author: user <___@_______> | | Date: Thu Nov 1 20:26:52 2018 +0300 | | | | update build-system version to 1.0.1 | | * | commit 442c9e94c9890032fb2f3123661345d465e2849f | | Author: user <___@_______> | | Date: Thu Nov 1 20:41:40 2018 +0300 | | | | update platform version to 1.0.1 bash-4.4$
Да, мы действительно вернулись к нашему предыдущему состоянию ea52eabd5910159efabd80adcf522f22bf6a2af2 и теперь мы можем получить обратно те изменения, которые мы недавно отправили в оригинальный репозиторий remote/build-system.git. Для этого нам, как обычно, необходимо выполнить команду git-subtree-pull:
bash-4.4$ bash-4.4$ git subtree pull --prefix=build-system ../../remote/build-system.git/ master From ../../remote/build-system * branch master -> FETCH_HEAD hint: Waiting for your editor to close the file...
Далее, нам будет предложено отредактировать сообщение о коммите:
Merge commit '0673142942ccf53514a276e855a98514952bb713' # Please enter a commit message to explain why this merge is necessary, # especially if it merges an updated upstream into a topic branch. # # Lines starting with '#' will be ignored, and an empty message aborts # the commit.
которое мы заменим на:
Pull changes from master of origin remote/build-system repository.
Merge commit '0673142942ccf53514a276e855a98514952bb713'
и наконец, в качестве продолжения предыдущего вывода, получим:
Merge made by the 'recursive' strategy. build-system/README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) bash-4.4$
Теперь мы имеем нормальную историю и, что более важно, мы избежали нетривиального мержа изменений из remote/build-system.git на какой-либо из будущих стадий развития проекта. Произошло это по тому, что мы не оставляли изменений поддерева build-system в локальном репозитории platform, а получили их путем передачи через оригинальный репозиторий remote/build-system.git:
bash-4.4$ bash-4.4$ git log --graph * commit 04a13bac91d1c445994ffc19db8b479d5e644e17 (HEAD -> master) |\ Merge: ea52eab 0673142 | | Author: user <___@_______> | | Date: Thu Nov 1 21:59:45 2018 +0300 | | | | Pull changes from master of origin remote/build-system repository. | | | | Merge commit '0673142942ccf53514a276e855a98514952bb713' | | | * commit 0673142942ccf53514a276e855a98514952bb713 | | Author: user <___@_______> | | Date: Thu Nov 1 21:48:40 2018 +0300 | | | | build-system is updated to version 1.0.2 from platform side | | * | commit ea52eabd5910159efabd80adcf522f22bf6a2af2 (origin/master) |\ \ Merge: 442c9e9 e5c5446 | |/ Author: user <___@_______> | | Date: Thu Nov 1 20:48:05 2018 +0300 | | | | Pull changes from master of upstream build-system.git repository. | | | | Merge commit 'e5c5446967599065dc02a269d8fcfc2c1d3c4f65' | | | * commit e5c5446967599065dc02a269d8fcfc2c1d3c4f65 | | Author: user <___@_______> | | Date: Thu Nov 1 20:26:52 2018 +0300 | | | | update build-system version to 1.0.1 | | * | commit 442c9e94c9890032fb2f3123661345d465e2849f | | Author: user <___@_______> | | Date: Thu Nov 1 20:41:40 2018 +0300 | | | | update platform version to 1.0.1 | | * | commit 47905bcb80be6f7cb3030513986fad4df548f812 |\ \ Merge: 7fad4be 783c6d5 | |/ Author: user <___@_______> | | Date: Thu Nov 1 20:20:20 2018 +0300 | | | | Add 'build-system/' from commit '783c6d5af1100e9665f930c818c861ff011bed19' | | | | git-subtree-dir: build-system | | git-subtree-mainline: 7fad4becbd13258216fb95cbe9d987dd33f0be6d | | git-subtree-split: 783c6d5af1100e9665f930c818c861ff011bed19 | | git-subtree-repo: ../../remote/build-system.git/ | | git-subtree-ref: master | | | * commit 783c6d5af1100e9665f930c818c861ff011bed19 | Author: user <___@_______> | Date: Thu Nov 1 20:16:33 2018 +0300 | | init build-system master 1.0.0 | * commit 7fad4becbd13258216fb95cbe9d987dd33f0be6d Author: user <___@_______> Date: Thu Nov 1 20:16:33 2018 +0300 init platform master 1.0.0 bash-4.4$
На данном этапе, ни в коем случае нельзя забывать о том, что мы должны поставить произошедшие изменения из локальной копии в upstream-репозиторий remote/platform.git.
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: 9, done. Counting objects: 100% (8/8), done. Delta compression using up to 4 threads Compressing objects: 100% (3/3), done. Writing objects: 100% (5/5), 600 bytes | 600.00 KiB/s, done. Total 5 (delta 0), reused 0 (delta 0) To ../../remote/platform.git ea52eab..04a13ba master -> master bash-4.4$
В противном случае, когда пользователи самостоятельно выполнят команду git-subtree-pull, у них будут большие неприятности. Дело в том, что если автор не выполнит команду git-push(1), то другие участники проекта, при наличии соответствующих прав, смогут сделать это раньше автора.
Действительно, поскольку upstream-репозиторий remote/platform.git так и не перешел в состояние 04a13bac91d1c445994ffc19db8b479d5e644e17, но репозиторий remote/build-system.git уже обновился, следовательно, после выполнения команды git-subtree-pull, любой участник проекта сможет поставить изменения в upstream-репозиторий remote/platform.git, а это приведет к рассогласованности upstream-репозитория remote/platform.git и его локальной копии на стороне автора (owner/platform).
Использование утилиты git-format-patch
Если, в своей работе, мы используем git-subtre, основными нашими помощниками будут команды:
git log -- . ":(exclude)build-system" git log -- build-system
которые позволяют видеть изменения, либо основного репозитория, либо поддерева соответственно.
А вот утилитой git-format-patch следует пользоваться осторожно.
Так, например, если мы попытаемся сформировать серию patch-файлов от состояния ea52eabd5910159efabd80adcf522f22bf6a2af2, с помощью утилиты git-format-patch:
bash-4.4$ bash-4.4$ git format-patch ea52eabd5910159efabd80adcf522f22bf6a2af2 --stdout From 0673142942ccf53514a276e855a98514952bb713 Mon Sep 17 00:00:00 2001 From: user <___@_______> Date: Thu, 1 Nov 2018 21:48:40 +0300 Subject: [PATCH] build-system is updated to version 1.0.2 from platform side --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index 629b3f4..4fbbbaf 100644 --- a/README +++ b/README @@ -1,3 +1,3 @@ -[master] build-system 1.0.1 +[master] build-system 1.0.2 -- 2.19.1 bash-4.4$
мы увидим, что разность состояний файла build-system/README рассматривается относительно каталога build-system/, а не от корня дерева исходного кода:
--- a/README +++ b/README
В это же время, рассчитав разность между состояниями того же файла с помощью команды git-diff:
bash-4.4$ bash-4.4$ git diff ea52eabd5910159efabd80adcf522f22bf6a2af2 04a13bac91d1c445994ffc19db8b479d5e644e17 diff --git a/build-system/README b/build-system/README index 629b3f4..4fbbbaf 100644 --- a/build-system/README +++ b/build-system/README @@ -1,3 +1,3 @@ -[master] build-system 1.0.1 +[master] build-system 1.0.2 bash-4.4$
мы получим правильный абсолютный путь в patch-файле:
--- a/build-system/README +++ b/build-system/README
Параметры команды git-diff(1), в предылущем примере, мы определили исходя из списка изменений, сделанных в основном репозитории platform.
Политики
Наличие подпроектов накладывает дополнительные требования к CM-политике и требует введения некоторых правил, соблюдение которых всеми участниками проекта позволит избежать конфликтов и непредвиденных затрат времени. Самыми простыми из этих правил могут быть, например, следующие:
- создавать новые ветки в upstream-репозиториях подпроектов имеет ограниченный круг разработчиков;
- никто не должен иметь возможности изменять код upstream-репозитория, если он подключен к основному проекту по тэгу.
Для того, чтобы рассмотреть подобные ограничения нам необходимо несколько доработать содержимое наших тестовых репозиториев.
Зафиксируем, для начала, текуще состояние upstream-репозитория remote/build-system.git:
bash-4.4$ bash-4.4$ cd owner/build-system/ bash-4.4$ cat README [master] build-system 1.0.2 bash-4.4$
Допустим теперь, что автор upstream-репозитория remote/build-system.git решил внести в проект изменения, которые, согласно его версионной политике, должны повысить minor компонент текущей версии 1.0.2. Для этого ему необходимо создать новую ветку проекта с именем build-system-1.1.x и далее, по мере разработки, фиксировать состояния тегами: 1.1.0, 1.1.1, 1.1.2, и так далее.
Создадим новую ветку:
bash-4.4$ bash-4.4$ git checkout -b build-system-1.1.x Switched to a new branch 'build-system-1.1.x' bash-4.4$ git branch * build-system-1.1.x master bash-4.4$
Повысим версию, записанную в файле README до версии 1.1.0:
bash-4.4$ bash-4.4$ vim README bash-4.4$ cat README [master] build-system 1.1.0 bash-4.4$ bash-4.4$ git commit -a -m "Move on to developing 1.1.x functionality" [build-system-1.1.x f6d79c1] Move on to developing 1.1.x functionality 1 file changed, 1 insertion(+), 1 deletion(-) bash-4.4$
и внесем изменения в upstream-репозиторий remote/build-system.git:
bash-4.4$ bash-4.4$ git push --set-upstream origin build-system-1.1.x Enumerating objects: 5, done. Counting objects: 100% (5/5), done. Writing objects: 100% (3/3), 280 bytes | 280.00 KiB/s, done. Total 3 (delta 0), reused 0 (delta 0) To ../../remote/build-system.git * [new branch] build-system-1.1.x -> build-system-1.1.x Branch 'build-system-1.1.x' set up to track remote branch 'build-system-1.1.x' from 'origin'. bash-4.4$
Теперь допустим, что, по мере разработки, мы продвинулись до версии 1.1.1:
bash-4.4$ bash-4.4$ vim README bash-4.4$ cat README [master] build-system 1.1.1 bash-4.4$ bash-4.4$ git commit -a -m "Update build-system version to 1.1.1" [build-system-1.1.x f9544a4] Update build-system version to 1.1.1 1 file changed, 1 insertion(+), 1 deletion(-) bash-4.4$ bash-4.4$ git push Enumerating objects: 5, done. Counting objects: 100% (5/5), done. Writing objects: 100% (3/3), 276 bytes | 276.00 KiB/s, done. Total 3 (delta 0), reused 0 (delta 0) To ../../remote/build-system.git f6d79c1..f9544a4 build-system-1.1.x -> build-system-1.1.x bash-4.4$
и зафиксировали данное состояние тэгом:
bash-4.4$ bash-4.4$ git tag -a 1.1.1 -m "Created tag for release (version 1.1.1)" bash-4.4$ git push origin 1.1.1 Enumerating objects: 1, done. Counting objects: 100% (1/1), done. Writing objects: 100% (1/1), 170 bytes | 170.00 KiB/s, done. Total 1 (delta 0), reused 0 (delta 0) To ../../remote/build-system.git * [new tag] 1.1.1 -> 1.1.1 bash-4.4$
После этого в upstream-репозитории remote/build-system.git мы можем наблюдать следующие ссылки:
bash-4.4$ bash-4.4$ cd remote/build-system.git/ bash-4.4$ tree refs refs ├── heads │ ├── build-system-1.1.x │ └── master └── tags └── 1.1.1 2 directories, 3 files bash-4.4$
Тем временем, разработчики проекта platform получили задачу стабилизировать сборку с использованием новой версии build-system. Естественно, для выполнения поставленной задачи, они создали новую ветку, например, platform-1.0.2:
bash-4.4$ bash-4.4$ cd user/platform/ bash-4.4$ git branch * master bash-4.4$ git pull Already up to date. bash-4.4$ bash-4.4$ git checkout -b platform-1.0.2 Switched to a new branch 'platform-1.0.2' bash-4.4$ vim README bash-4.4$ cat README [master] platform 1.0.2 bash-4.4$ git commit -a -m "Сreated platform-1.0.2 branch for the transition to the system 1.1.1" [platform-1.0.2 00a1250] Сreated platform-1.0.2 branch for the transition to the system 1.1.1 1 file changed, 1 insertion(+), 1 deletion(-) bash-4.4$
И подключили к ней, в качестве поддерева, уже не мастер-ветку репозитория remote/build-system.git, а тэг 1.1.1:
bash-4.4$ bash-4.4$ git rm -rf build-system/ rm 'build-system/README' bash-4.4$ git commit -a -m "Removed subtre based on build-system/master" [platform-1.0.2 7db0f54] Removed subtre based on build-system/master 1 file changed, 3 deletions(-) delete mode 100644 build-system/README bash-4.4$ bash-4.4$ bash-4.4$ git push --set-upstream origin platform-1.0.2 Enumerating objects: 7, done. Counting objects: 100% (7/7), done. Delta compression using up to 4 threads Compressing objects: 100% (3/3), done. Writing objects: 100% (5/5), 550 bytes | 550.00 KiB/s, done. Total 5 (delta 0), reused 0 (delta 0) To ../../remote/platform.git/ * [new branch] platform-1.0.2 -> platform-1.0.2 Branch 'platform-1.0.2' set up to track remote branch 'platform-1.0.2' from 'origin'. bash-4.4$ bash-4.4$ bash-4.4$ git subtree add --prefix=build-system ../../remote/build-system.git/ 1.1.1 git fetch ../../remote/build-system.git/ 1.1.1 remote: Enumerating objects: 9, done. remote: Counting objects: 100% (9/9), done. remote: Compressing objects: 100% (3/3), done. remote: Total 7 (delta 0), reused 0 (delta 0) Unpacking objects: 100% (7/7), done. From ../../remote/build-system * tag 1.1.1 -> FETCH_HEAD Added dir 'build-system' bash-4.4$
Итак мы имеем новое состояние подпроекта build-system и должны внести эти изменения в upstream-репозиторий remote/platform.git:
bash-4.4$ bash-4.4$ git push Enumerating objects: 12, done. Counting objects: 100% (12/12), done. Delta compression using up to 4 threads Compressing objects: 100% (4/4), done. Writing objects: 100% (8/8), 889 bytes | 889.00 KiB/s, done. Total 8 (delta 0), reused 0 (delta 0) To ../../remote/platform.git/ 7db0f54..6f1a50e platform-1.0.2 -> platform-1.0.2 bash-4.4$
Проверим историю:
bash-4.4$ bash-4.4$ git log -3 --graph * commit 6f1a50e249e01f69c54f343b65747d28abc6456d (HEAD -> platform-1.0.2, origin/platform-1.0.2) |\ Merge: 7db0f54 f9544a4 | | Author: user <___@_______> | | Date: Fri Nov 2 18:24:54 2018 +0300 | | | | Add 'build-system/' from commit 'f045926542e9f685034545a45317093383fddf99' | | | | git-subtree-dir: build-system | | git-subtree-mainline: 7db0f5452e67086dc4e381a0ccb14f25d48ecf0b | | git-subtree-split: f045926542e9f685034545a45317093383fddf99 | | git-subtree-repo: ../../remote/build-system.git/ | | git-subtree-ref: 1.1.1 | | | * commit f9544a4cc2650a83b96f400fdfc95ba64a38ec6e | | Author: user <___@_______> | | Date: Fri Nov 2 17:59:43 2018 +0300 | | | | Update build-system version to 1.1.1 | | | * commit f6d79c12ada29438454739fe6f6db9592d413be2 | | Author: user <___@_______> | | Date: Fri Nov 2 17:54:35 2018 +0300 | | | | Move on to developing 1.1.x functionality bash-4.4$
Мы действительно подключили нужный нам тэг и, теперь задача CM-инженера состоит в том, чтобы разработчики проекта platform, работающие на ветке platform-1.0.2 даже не пытались править build-system. Это было бы не логично и, более того, так как поддерево build-system ссылается на тэг, совершенно недопустимо.
Для того, чтобы запретить изменения в upstream-репозитории со стороны поддерева build-system проекта platform, необходимо разработать pre-receive хук и поместить его в файл
remote/build-system.git/hooks/pre-receive
Займемся созданием простого скрипта, запрещающего коммиты в том случае, если совершается попытка изменить состояние тэга:
#!/bin/sh zero_commit="0000000000000000000000000000000000000000" LC_COLLATE='C' allowed_users=(habr habrahabr) while read oldrev newrev refname; do # # git-subtree(1) push имеет в своем распоряжении только имя ссылки, # которую вы пытаетесь изменить. Поэтому нам надо проверить два # факта: # # 1) не пытаетесь ли вы создать новую ветку, а если пытаетесь, то # 2) не яляется ли это имя фактической ссылкой на tag, но так как # имя задано вами без указания полного пути, то есть, например, # не 'refs/tags/1.1.1', а '1.1.1', утилита git-subtree(1) # могла ошибиться и передать его как 'refs/heads/1.1.1', # то есть как имя ветки. # : if [[ $oldrev == $zero_commit && $refname =~ ^refs/heads/ ]]; then refbase=$(basename $refname) refpath=$(git show-ref $refbase | cut -f2 -d' ') if [[ $refpath =~ ^refs/tags/.*$ ]]; then echo "" echo "ERROR: Trying to change TAG named as '$refpath'." echo "" exit 1 fi if [[ ! ${allowed_users[*]} =~ $USER ]]; then echo "" echo "ERROR: Trying to create NEW BRANCH with name '$refname'." echo "" exit 1 fi fi done exit 0
Данный скрипт требует пояснений. Наверное странно видеть, что сначала мы проверяем, не является ли ссылка веткой, а затем снова пытаемся проверить, не представляет ли она, фактически, тэг. Все дело в том, что функция, реализующая команду:
git subtree push --prefix=<subdir> <remote> <ref>
не анализирует параметр <ref> и не сверяется с историей сообщений, сохраненных на этапе подключения поддерева в каталог <subdir> и, поэтому ссылки, заданные не полностью (refs/tags/1.1.1), а кратко (1.1.1) поступают на вход upstream-репозитория как полные имена веток (в нашем случае: refs/heads/1.1.1).
Существующее положение дел можно поправить, если доработать функциональность git-subtree(1). Однако сейчас мы не будем этого делать и продолжим наши рассуждения.
Итак, для проверки скрипта pre-receive, внесем изменения в файл user/platform/build-system/README:
bash-4.4$ bash-4.4$ cd user/platform/ bash-4.4$ vim build-system/README bash-4.4$ cat build-system/README [master] build-system 1.1.1 Try to change. bash-4.4$ bash-4.4$ git commit -a -m "Try to change the tag of build-system" [platform-1.0.2 34e7970] Try to change the tag of build-system 1 file changed, 2 insertions(+) bash-4.4$
и попробуем доставить их в upstream-репозиторий remote/build-system.git.
К сожалению ...
Ссылка на ревизию upstream-репозитория является обязательным параметром команды
git subtree push --prefix=<subdir> <remote> <ref>
Поэтому, для того чтобы вспомнить, каким образом мы подключали поддерево, нам будет необходимо уточнить имя сылки с помощью команды:
bash-4.4$ git subtree -d --list Looking for externals... Commit: 6f1a50e249e01f69c54f343b65747d28abc6456d build-system ../../remote/build-system.git/ tag 1.1.1 f045926542e9f685034545a45317093383fddf99 bash-4.4$
Итак, вспомнив имя тэга, мы наконец можем попробовать доставить наши изменения в upstream-репозиторий remote/build-system.git:
bash-4.4$ bash-4.4$ git subtree push --prefix=build-system ../../remote/build-system.git/ 1.1.1 git push using: ../../remote/build-system.git/ 1.1.1 Enumerating objects: 5, done. Counting objects: 100% (5/5), done. Writing objects: 100% (3/3), 293 bytes | 293.00 KiB/s, done. Total 3 (delta 0), reused 0 (delta 0) remote: remote: ERROR: Trying to change TAG named as 'refs/tags/1.1.1'. remote: To ../../remote/build-system.git/ ! [remote rejected] c3a7333aaa818a7d7a0d501d4b69db1c6a01d40f -> 1.1.1 (pre-receive hook declined) error: failed to push some refs to '../../remote/build-system.git/' bash-4.4$
Поскольку, созданный заранее, хук pre-receive отработал правильно, нам не удалось доставить наши изменения. Вместо этого мы получили сообщение об ошибке:
remote: remote: ERROR: Trying to change TAG named as 'refs/tags/1.1.1'. remote:
и нам, так или иначе, придется откатить, сделанные нами, изменения:
bash-4.4$ bash-4.4$ git reset --hard HEAD^ HEAD is now at 6f1a50e Add 'build-system/' from commit 'f045926542e9f685034545a45317093383fddf99' bash-4.4$
вернув, тем самым, предыдущее состояние ветки platform-1.0.2:
bash-4.4$ bash-4.4$ git log -3 --graph * commit 6f1a50e249e01f69c54f343b65747d28abc6456d (HEAD -> platform-1.0.2, origin/platform-1.0.2) |\ Merge: 7db0f54 f9544a4 | | Author: user <___@_______> | | Date: Fri Nov 2 18:24:54 2018 +0300 | | | | Add 'build-system/' from commit 'f045926542e9f685034545a45317093383fddf99' | | | | git-subtree-dir: build-system | | git-subtree-mainline: 7db0f5452e67086dc4e381a0ccb14f25d48ecf0b | | git-subtree-split: f045926542e9f685034545a45317093383fddf99 | | git-subtree-repo: ../../remote/build-system.git/ | | git-subtree-ref: 1.1.1 | | | * commit f9544a4cc2650a83b96f400fdfc95ba64a38ec6e | | Author: user <___@_______> | | Date: Fri Nov 2 17:59:43 2018 +0300 | | | | Update build-system version to 1.1.1 | | | * commit f6d79c12ada29438454739fe6f6db9592d413be2 | | Author: user <___@_______> | | Date: Fri Nov 2 17:54:35 2018 +0300 | | | | Move on to developing 1.1.x functionality bash-4.4$
Выводы
В отличие от git-subrepo, где история основного репозитория остается линейной, а подпроекты подключаются как squashed-коммиты, git-subtree(1) представляется более мощным средством, позволяющим реализовать практически любые сценарии работы.
С точки зрения доработки существующих средств под нужды собственного проекта или просто с целью их усовершенствования, необходимо учитывать следующее. Проект git-subrepo развивается и команда разработчиков открыта для предложений. С другой стороны, git-subtree более прост в реализации и любые его изменения не составят большого труда, однако, команда разработчиков Git с трудом принимает предложения, поскольку ее практически не интересует совершенствование данного инструмента и, с наибольшей вероятностью, вам придется накладывать собственные изменения каждый раз при переходе на новую версию Git.