How to use git subtree split with tags?
Git is a fantastic VCS and I use it at home, at work, every days.
I have a library (BeSimpleSoap) that contains parts of Server, Client, Common, Wsdl and the Bundle for Symfony2. But if you have a project who needs just the SoapClient part, you are forced to download other parts of the library (with vendors if you use Composer).
Fortunately with Git there is always a solution! From Git v1.7.11 a new command is available and it's git-subtree.
The documentation of this command says:
NAME
----
git-subtree - Merge subtrees together and split repository into subtrees
Split all libraries into other repositories with all branches#
I use it mainly to split the BeSimpleSoap repository:
#!/bin/bash
# BeSimpleSoapSplitter.sh
git fetch origin
# find branches named master or `x.x` on origin
BRANCHES=( `git branch --remotes | grep '^ *origin/\([0-9]\.[0-9]\|master\)'` )
# iterate on branchesx
for branch in ${BRANCHES[@]} ; do
# remove "origin/" on branch name
branch=`echo $branch | sed -e 's/origin\/\([0-9]\.[0-9]\|master\)/\1/'`
# create/reset branch based on remote
git checkout -B subtree_$branch origin/$branch &>/dev/nul
# iterate on libraries
for repoName in `ls -1 src/BeSimple` ; do
# use subtree to split library into new branch
git subtree split --prefix=src/BeSimpleSoap/$repoName -b subtree_${repoName}_$branch
# add remote identified by $repoName
git remote add $repoName git@github.com:BeSimple/BeSimple$repoName.git &>/dev/null
# push local branch on remote
git push $repoName subtree_${repoName}_$branch:$branch
done
done
Okay good. With script I can split all libraries into other repositories with all branches (master and x.x branches).
But tags are not added on subtrees.
Compute tags on demand#
In a Git repository, a tag name can to exist just once.
In my case I create a new branch from a specified tag and I split libraries. After I deduce that last commit of each subtree is the position of tag.
#!/bin/bash
# BeSimpleSoapSplitter.sh [tag]
# eg: BeSimpleSoapSplitter.sh v0.2.0
function splitRepository() {
# iterate on libraries
for repoName in `ls -1 src/BeSimple` ; do
# use subtree to split library into new branch
git subtree split --prefix=src/BeSimpleSoap/$repoName -b subtree_${repoName}_$1
# add remote identified by $repoName
git remote add $repoName git@github.com:BeSimple/BeSimple$repoName.git &>/dev/null
if [ -z "$2" ] ; then
# push local branch on remote
git push $repoName subtree_${repoName}_$branch:$branch
else
# create tag on last commit of subtree
git tag $2 subtree_${repoName}_$1
# push new tag on remote
git push $repoName --tags
# delete tag to create on other subtree
git tag -d $2
fi
done
}
git fetch origin
# test if a tag has been specified
if [ -n "$1" ] ; then
TAG=$1 ; fi
# test if tag exist
git tag -l | grep $TAG &>/dev/null
if [ 1 -eq "$?" ] ; then
echo "TAG \"$TAG\" does not exist"
exit 1
fi
# create/reset branch based on tag
git checkout -B subtree_tag_$TAG $TAG &>/dev/null
# delete tag because it's not possible to have 2 tags with same name
git tag -d $TAG
# call splitRepository function with branch name and the name of tag
splitRepository tag_$TAG $TAG
# fetch origin to recreate the tag
git fetch origin
exit 0
fi
# find branches named master or `x.x` on origin
BRANCHES=( `git branch --remotes | grep '^ *origin/\([0-9]\.[0-9]\|master\)'` )
# iterate on branches
for branch in ${BRANCHES[@]} ; do
# remove "origin/" on branch name
branch=`echo $branch | sed -e 's/origin\/\([0-9]\.[0-9]\|master\)/\1/'`
# create/reset branch based on remote
git checkout -B subtree_$branch origin/$branch &>/dev/nul
# call splitRepository function with branch name
splitRepository $branch
done
Enjoy!