Our Git repositories started out as parts of a single monster SVN repository where the individual projects each had their own tree like so:
project1/branches /tags /trunk project2/branches /tags /trunk
Obviously, it was pretty easy to move files from one to another with
svn mv. But in Git, each project is in its own repository, and today I was asked to move a subdirectory from
project1. I did something like this:
$ git clone project2 $ cd project2 $ git filter-branch --subdirectory-filter deeply/buried/java/source/directory/A -- --all $ git remote rm origin # so I don't accidentally overwrite the repo ;-) $ mkdir -p deeply/buried/different/java/source/directory/B $ for f in *.java; do > git mv $f deeply/buried/different/java/source/directory/B > done $ git commit -m "moved files to new subdirectory" $ cd .. $ $ git clone project1 $ cd project1 $ git remote add p2 ../project2 $ git fetch p2 $ git branch p2 remotes/p2/master $ git merge p2 # --allow-unrelated-histories for git 2.9+ $ git remote rm p2 $ git push
But that seems pretty convoluted. Is there a better way to do this sort of thing in general? Or have I adopted the right approach?
Note that this involves merging the history into an existing repository, rather than simply creating a new standalone repository from part of another one (as in an earlier question).
Yep, hitting on the
filter-branch was key. The fact that you used it essentially proves there’s no easier way – you had no choice but to rewrite history, since you wanted to end up with only a (renamed) subset of the files, and this by definition changes the hashes. Since none of the standard commands (e.g.
pull) rewrite history, there’s no way you could use them to accomplish this.
You could refine the details, of course – some of your cloning and branching wasn’t strictly necessary – but the overall approach is good! It’s a shame it’s complicated, but of course, the point of git isn’t to make it easy to rewrite history.
Answered By – Cascabel