posted to this is not a weblog
on jan 27th, 2010 at 22:26

last updated about 1 year later on sunday, april, 3rd 2011 at 11:36

tagged git, nerd
and commented on twice

share this page

update: this behavior is now supported natively in git with subtree merging.

for a project i'm working on, i need to host a local copy of a remote git repository inside of my project's git tree, but rooted in a subdirectory. it wasn't as straightforward as i was hoping, so i'm writing this so someone else can find it.

i needed to do this because the two codebases need to be bundled together while still allowing me to keep local changes to that remotely-maintained code in my own tree, yet still occasionally merge upstream changes from it as well. i want to retain all of the upstream repository metadata, so that individual commits are tracked and so on, without having added history to each of those files showing that they were renamed.

if i didn't need to keep it in a subdirectory, a normal git pull ... would work, and basically merge in the tree on top of mine. but since it has to be in a different path inside my tree, it involves rewriting all of the change history in order to make it look as if the files were always in that subdirectory from the remote repository. to do this requires a bit of work, so i have a shell script doing it for me now:

#!/bin/sh

cd ~/code/ && \
rm -rf php-activerecord && \
git clone git://github.com/kla/php-activerecord.git && \
cd php-activerecord && \
git filter-branch --index-filter 'git ls-files -s | sed "s,\t,&lib/php-activerecord/," |
    GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info && \
    mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE' HEAD
note: that is a literal tab character in place of the \t in the sed expression.

this clones the remote repository into a fresh directory (~/code/php-activerecord/), then rewrites the history by renaming each file from its normal path to its path with lib/php-activerecord/ prepended to it. when it's done, all of the files have been moved to ~/code/php-activerecord/lib/php-activerecord.

then from my original project tree i just do a git pull --no-commit ~/code/php-activerecord master and it merges that repo into the lib/php-activerecord/ directory of my project. i use --no-commit because i want to change the auto-generated commit message to say it was merged from the original repo location, not ~/code/php-activerecord (otherwise it will auto commit and git commit --amend is needed).

two comments

benoitc (not authenticated) on february 1st, 2010 at 11:30:48:

Why not using submodules ?

joshua (authentic) on february 1st, 2010 at 12:11:48:

i didn't know about submodules, but seeing how they work, they seem kind of brittle and laborious.


leave your comment or contact me

if you want to be able to mark your comment as authentic or delete it later, include your e-mail address (it won't be shown on the site). you'll be e-mailed instructions with a copy of your comment.

basic html allowed; be nice
required


optional, gravatar-ized


optional