Synchronized checkouts of git submodules upon main repo branch change
- Date: 26 Oct 2011
- Category: development
- Tagged with: how-to, git, checkout, and submodule
This tip will be useless for most of all. But if you are involved in porting of something to something better (or at least something you get paid for), for example porting project from LESS to SASS. Well you don’t need anything special for such purpose, but the problem comes out when you want to have exact copy of original repo (with different branches), but with ported sources.
The best explanation of a problem is my port of Twitter’s Bootstrap
CSS framework. As you can see, I’m trying to make my bootstrap.scss exactly
match original sources, but written in SASS. Also I want to have two branches:
master
and 2.0-wip
and keep work on both within same repo, just like
original repo does.
To track changes in original repo more easily, I have decided to add it as a submodule to my repo. And created branches (I wanted to work on) with same names as original ones. So it was something like this:
ixti@msi:~/demo$ git submodule add git://github.com/twitter/bootstrap.git ./src
Cloning into src...
remote: Counting objects: 4664, done.
remote: Compressing objects: 100% (1728/1728), done.
remote: Total 4664 (delta 3046), reused 4408 (delta 2837)
Receiving objects: 100% (4664/4664), 1.20 MiB | 534 KiB/s, done.
Resolving deltas: 100% (3046/3046), done.
ixti@msi:~/demo$ git commit -m 'Added original repo as submodule'
[master 5871d81] Added original repo as submodule
2 files changed, 4 insertions(+), 0 deletions(-)
create mode 100644 .gitmodules
create mode 160000 src
ixti@msi:~/demo$ cd src && git branch -a && cd ..
* master
remotes/origin/2.0-wip
remotes/origin/HEAD -> origin/master
remotes/origin/dev
remotes/origin/gh-pages
remotes/origin/kasperp-dropdown-btn-dev
remotes/origin/master
ixti@msi:~/demo$ git checkout -b 2.0-wip
Switched to a new branch '2.0-wip'
ixti@msi:~/demo$ cd src && git checkout 2.0-wip && cd ..
Branch 2.0-wip set up to track remote branch 2.0-wip from origin.
Switched to a new branch '2.0-wip'
ixti@msi:~/demo$ git commit -am 'Initial start of 2.0-wip branch'
[2.0-wip 659720a] Initial start of 2.0-wip branch
1 files changed, 1 insertions(+), 1 deletions(-)
Everything is cool, except one annoying thing - src
does not tracks your
checkouts in main repo, so when you will checkout to the master branch in your
repo, it will tell you that src
is modified, so you’ll need to manually check
it out:
ixti@msi:~/demo$ git checkout master
M src
Switched to branch 'master'
ixti@msi:~/demo$ cd src && git checkout master && cd ..
Switched to branch 'master'
ixti@msi:~/demo$ git status
# On branch master
nothing to commit (working directory clean)
Fortunately we can automatize this pain with this simple post-checkout
hook:
#!/bin/sh
#file: .git/hooks/post-checkout
# Get active branch name after checkout
BRANCH=$(git branch | grep '^*' | cut -b 3-)
# Silently exit when checked out on specific commit (no branch)
if [ "x(no branch)" = "x$BRANCH" ] ; then exit 0; fi
# Get into our submodule with original repo
cd src
# Silently exit when original repo has no similarly named branch
git branch | grep "$BRANCH" -q || exit 0
# Checkout original repo to be on same branch as we are
git checkout $BRANCH
In order to use it, just put it into your $GIT_DIR/hooks/
directory
(normally it will be .git/hooks/
under root directory of your repo).
For more details on hooks, please man githooks
. Also you might find useful
reading ProGit and Git Book about hooks.