Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
en:git:git-subtree [2012/01/14 08:38]
alex
en:git:git-subtree [2012/08/27 09:42] (current)
alex
Line 1: Line 1:
 ====== git-subtree ====== ====== git-subtree ======
  
-Sometimes projects can have complex relationships. ​ Perhaps a project develops a utility or libary internally that ends up becoming its own separate project. ​ Perhaps a project uses a particular library, but adds some features to it in their own repository. ​ How are these commits reconciled? ​ One method is the use of the script [[github.com/​apenwarr/​git-subtree|git-subtree]]. ​ It is a very handy tool that allows for a repository to be associated with a directory or subtree of a different repository, yet allow for bi-directional transfer of commits. ​ In Arch Linux, git-subtree is in the AUR as ''​git-subtree-git''​ so it can be installed with yaourt with ''​yaourt -S git-subtree-git''​.  ​+Sometimes projects can have complex relationships. ​ Perhaps a project develops a utility or libary internally that ends up becoming its own separate project. ​ Perhaps a project uses a particular library, but adds some features to it in their own repository. ​ How are these commits reconciled? ​ One method is the use of the script [[http://github.com/​apenwarr/​git-subtree|git-subtree]]. ​ It is a very handy tool that allows for a repository to be associated with a directory or subtree of a different repository, yet allow for bi-directional transfer of commits. ​ In Arch Linux, git-subtree is in the AUR as ''​git-subtree-git''​ so it can be installed with yaourt with ''​yaourt -S git-subtree-git''​.  ​
  
 Some time ago, I started working on a project that involved using XBee ZigBee radios from Digi.  Unfortunately,​ the software provided is windows-only and is lacking some very important features, like packet generation and decoding. ​ As a part of the project, I worked on a cross-platform open source re-implementation of a ZigBee terminal that can talk to the XBee radios in packet mode and create and decode packets with a nice interface. ​ The application evolved to the point where it would be nice to split it off into its own repository. ​ So, I installed git-subtree and went to work.  Or not.  The documentation is really bad if you're not a git expert. ​ After consulting the oracle of google, I discovered a very good [[http://​psionides.eu/​2010/​02/​04/​sharing-code-between-projects-with-git-subtree/​|blog post]] on the matter. ​ Please see the link for the details as Jakub does a much better job of explaining it than myself.  ​ Some time ago, I started working on a project that involved using XBee ZigBee radios from Digi.  Unfortunately,​ the software provided is windows-only and is lacking some very important features, like packet generation and decoding. ​ As a part of the project, I worked on a cross-platform open source re-implementation of a ZigBee terminal that can talk to the XBee radios in packet mode and create and decode packets with a nice interface. ​ The application evolved to the point where it would be nice to split it off into its own repository. ​ So, I installed git-subtree and went to work.  Or not.  The documentation is really bad if you're not a git expert. ​ After consulting the oracle of google, I discovered a very good [[http://​psionides.eu/​2010/​02/​04/​sharing-code-between-projects-with-git-subtree/​|blog post]] on the matter. ​ Please see the link for the details as Jakub does a much better job of explaining it than myself.  ​
Line 83: Line 83:
  
 Slick. ​ Now that that's taken care of, time to get back to the real engineering... Slick. ​ Now that that's taken care of, time to get back to the real engineering...
 +
 +===== Helper Script =====
 +
 +As I have been using the commands listed here quite often, I decided to put together a helper script for managing these subtrees. ​ Take the script below, modify it to match your repository configuration,​ and include it in your repository alongside the subtree. ​ Then you can call it with no arguments or with a single argument of '​pull'​ to pull from the remote subtree repository, or add '​push'​ to push to the remote subtree repository. ​ As is, the script performs the exact commands listed in the above section, aside from the splitting off of the subdirectory in the process of creating a separate repository.  ​
 +
 +<code sh>
 +#!/bin/bash
 +
 +# Git subtree manager
 +# Alex Forencich <​alex@alexforencich.com>​
 +# This script facilitates easy management of subtrees
 +# included in larger repositories as this script can
 +# be included in the repository itself.
 +
 +# Note:
 +# Requires git-subtree
 +# https://​github.com/​apenwarr/​git-subtree
 +
 +# Settings
 +# uncomment to use --squash
 +#​squash="​yes"​
 +# Remote repository
 +repo="​git@github.com:​alexforencich/​zigbee-terminal.git"​
 +# Remote name
 +remote="​zbt"​
 +# Subdirectory to store code in
 +subdir="​zigbee-terminal"​
 +# Remote branch
 +branch="​master"​
 +# Backport branch name (only used for pushing)
 +backportbranch="​${remote}backport"​
 +# Add commit message
 +addmsg="​added ${subdir} as a subproject"​
 +# Merge commit message
 +mergemsg="​merged changes in ${subdir}"​
 +
 +# Usage
 +# add - adds subtree
 +# pull - default, pulls from remote
 +# push - pushes to remote
 +
 +squashflag=""​
 +
 +if [ $squash ]; then
 +  squashflag="​--squash"​
 +fi
 +
 +action="​pull"​
 +
 +cd $(git rev-parse --show-toplevel)
 +
 +if [ ! -d "​$subdir"​ ]; then
 +    action="​add"​
 +fi
 +
 +if [ -n "​$1"​ ]; then
 +    action="​$1"​
 +fi
 +
 +# array contains value
 +# usage: contains array value
 +function contains() {
 +    local n=$#
 +    local value=${!n}
 +    for ((i=1;i < $n;i++)) {
 +        if [ "​${!i}"​ == "​${value}"​ ]; then
 +            echo "​y"​
 +            return 0
 +        fi
 +    }
 +    echo "​n"​
 +    return 1
 +}
 +
 +case "​$action"​ in
 +  add)
 +    if [ $(contains $(git remote) "​$remote"​) != "​y"​ ]; then
 +      git remote add "​$remote"​ "​$repo"​
 +    fi
 +    git fetch "​$remote"​
 +    git subtree add -P "​$subdir"​ $squashflag -m "​$addmsg"​ "​$remote/​$branch"​
 +    ;;
 +  pull)
 +    if [ $(contains $(git remote) "​$remote"​) != "​y"​ ]; then
 +      git remote add "​$remote"​ "​$repo"​
 +    fi
 +    git fetch "​$remote"​
 +    git subtree merge -P "​$subdir"​ $squashflag -m "​$mergemsg"​ "​$remote/​$branch"​
 +    ;;
 +  push)
 +    if [ $(contains $(git remote) "​$remote"​) != "​y"​ ]; then
 +      git remote add "​$remote"​ "​$repo"​
 +    fi
 +    git subtree split -P "​$subdir"​ -b "​$backportbranch"​
 +    git push "​$remote"​ "​$backportbranch:​$branch"​
 +    ;;
 +  *)
 +    echo "​Error:​ unknown action!"​
 +    exit 1
 +esac
 +
 +exit 0
 +
 +</​code>​