tags:

views:

695

answers:

4

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'. In git, each project is in its own repository, and today I was asked to move a subdirectory from project2 to 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 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 
$ 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?

+1  A: 

That sounds like a reasonable approach to me; I can't think of any obvious way to significantly improve your method. It's nice that Git actually does make this easy (I wouldn't want to try to move a directory of files between different repositories in Subversion, for example).

Greg Hewgill
I also would not want to try moving a directory between two different svn repos! (I'm imagining some nightmare involving svnadmin dump and svn dumpfilter, bleah.)
ebneter
+4  A: 

Yep, hitting on the subdirectory-filter of 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.

Jefromi
+1  A: 

This is something I'm interested in as well. My git-fu isn't as good as your's though, and filter-branch still scares me. I would have done it by generating a set of patches and then applying them, using the --directory argument to git apply. But that way is much more of a pain than what you did.

Oh, have you considered looking into submodules? That might be what you want, although I've never used them myself.

Ibrahim
+1, I've been looking for a solution along this lines, gitmmodule could be just what I'm looking for, many thanks...
Fire Crow
+3  A: 

Take a look at the "coolest merge ever" (just search for that phrase on the Git mailing list). The gitk GUI which is included in Git was originally developed independently, and later merged into Git, preserving all of its history. I routinely re-read how it is done, and I still don't fully understand it, but it's a great example of Git's power.

Jörg W Mittag