tags:

views:

4136

answers:

5

Let's say I've got a setup that look something like

phd/code/
phd/figures/
phd/thesis/

For historical reasons, these all have their own git repositories. But I'd like to combine them into a single one to simplify things a little. For example, right now I might make two sets of changes and have to do something like

cd phd/code
git commit 
cd ../figures
git commit

It'd be (now) nice to just to perform

cd phd
git commit

There seems to be a couple of ways of doing this using submodules or pulling from my sub-repositories, but that's a little more complex than I'm looking for. At the very least, I'd be happy with

cd phd
git init
git add [[everything that's already in my other repositories]]

but that doesn't seem like a one-liner. Is there anything in git that can help me out?

+2  A: 

The sequence you suggested

git init
git add *
git commit -a -m "import everything"

will work, but you will lose your commit history.

Patrick_O
Losing the history isn't so bad, but since the repository is for my own work (i.e., it's private) there's a lot of stuff in there that I don't want versioned or that isn't versioned yet.
Will Robertson
+20  A: 

git-stitch-repo will process the output of git-fast-export --all --date-order on the git repositories given on the command-line, and create a stream suitable for git-fast-import that will create a new repository containing all the commits in a new commit tree that respects the history of all the source repositories.

Aristotle Pagaltzis
Ah, thanks! I was hoping there's be a command to do this, but, well, it's sometimes hard to know the full extent of git's features :)
Will Robertson
Uh, it’s a third-party tool, not part of git… :-)
Aristotle Pagaltzis
Indeed, now you tell me :) Oh well, I suppose I had to learn how to install CPAN packages one day…
Will Robertson
I can't believe they even have a command like this. This is extremely cool!
kizzx2
Thanks for pointing that command out. Just been using it to help in moving a few repos from SVN to Git.
signine
+12  A: 

Here's a solution I gave here:

  1. First do a complete backup of your phd directory: I don't want to be held responsible for your losing years of hard work! ;-)

    $ cp -r phd phd-backup
    
  2. Move the content of phd/code to phd/code/code, and fix the history so that it looks like it has always been there (this uses git's filter-branch command):

    $ cd phd/code
    $ git filter-branch --index-filter \
        'git ls-files -s | sed "s-\t-&code/-" |
         GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
         git update-index --index-info &&
         mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE' HEAD
    
  3. Same for the content of phd/figures and phd/thesis (just replace code with figures and thesis).

    Now your directory structure should look like this:

    phd
      |_code
      |    |_.git
      |    |_code
      |         |_(your code...)
      |_figures
      |    |_.git
      |    |_figures
      |         |_(your figures...)
      |_thesis
           |_.git
           |_thesis
                |_(your thesis...)
    
  4. Then create a git repository in the root directory, pull everything into it and remove the old repositories:

    $ cd phd
    $ git init
    
    
    $ git pull code
    $ rm -rf code/code
    $ rm -rf code/.git
    
    
    $ git pull figures
    $ rm -rf figures/figures
    $ rm -rf figures/.git
    
    
    $ git pull thesis
    $ rm -rf thesis/thesis
    $ rm -rf thesis/.git
    

    Finally, you should now have what you wanted:

    phd
      |_.git
      |_code
      |    |_(your code...)
      |_figures
      |    |_(your figures...)
      |_thesis
           |_(your thesis...)
    

One nice side to this procedure is that it will leave non-versioned files and directories in place.

Hope this helps.


Just one word of warning though: if your code directory already has a code subdirectory or file, things might go very wrong (same for figures and thesis of course). If that's the case, just rename that directory or file before going through this whole procedure:

$ cd phd/code
$ git mv code code-repository-migration
$ git commit -m "preparing the code directory for migration"

And when the procedure is finished, add this final step:

$ cd phd
$ git mv code/code-repository-migration code/code
$ git commit -m "final step for code directory migration"

Of course, if the code subdirectory or file is not versioned, just use mv instead of git mv, and forget about the git commits.

MiniQuark
Thanks for this snippet -- it did exactly what I needed (once I accounted for Mac OS X sed not processing "\t" (I had to use ^V^I instead).
Craig Trader
+1  A: 

Perhaps, simply (similarly to the previous answer, but using simpler commands) making in each of the separate old repositories a commit that moves the content into a suitably named subdir, e.g.:

$ cd phd/code
$ mkdir code
# This won't work literally, because * would also match the new code/ subdir, but you understand what I mean:
$ git mv * code/
$ git commit -m "preparing the code directory for migration"

and then merging the three separate repos into one new, by doing smth like:

$ cd ../..
$ mkdir phd.all
$ cd phd.all
$ git init
$ git pull ../phd/code
...

Then you'll save your histories, but will go on with a single repo.

imz
This worked swimmingly for me.
William Pietri
+1  A: 

The git-filter-branch solution works well, but note that if your git repo comes from a SVN import it may fail with a message like:

Rewrite 422a38a0e9d2c61098b98e6c56213ac83b7bacc2 (1/42)mv: cannot stat `/home/.../wikis/nodows/.git-rewrite/t/../index.new': No such file or directory

In this case you need to exclude the initial revision from the filter-branch - i.e. change the HEAD at the end to [SHA of 2nd revision]..HEAD - see:

http://www.git.code-experiments.com/blog/2010/03/merging-git-repositories.html

Snafu