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
Why not using submodules ?
i didn't know about submodules, but seeing how they work, they seem kind of brittle and laborious.
leave your comment or contact me