5

Extracting a blob (file) from an arbitrary revision is easy with git show, e.g.:

 git show master:src/hello-world.c > /tmp/hello.c

However, I'd like to know if is there a similar way in git to extract a tree (directory) and everything under it recursively?

I've written a small script that does this, so I'll add that as a possible answer. It seems that this is the kind of thing that may well be built in to git, but I just don't know how to find it...

Mark Longair
  • 446,582
  • 72
  • 411
  • 327

3 Answers3

13

You can use git archive for this.

git archive master:src/ | tar -C destination -x
CB Bailey
  • 755,051
  • 104
  • 632
  • 656
8

You can use read-tree and checkout-index with a temporary index file:

GIT_INDEX_FILE=.tmp.index { git read-tree master:src &&
                            git checkout-index -a --prefix=dest/; 
                            rm -f .tmp.index; }

(Line breaks added for clarity, but it's really a one-liner.)

For a bare repository you have to pretend that a working tree exists and that you are in it:

GIT_INDEX_FILE=.tmp.index GIT_DIR=/path/to/repo.git GIT_WORK_TREE=. {
    git read-tree master:src &&
    git checkout-index -a --prefix=/path/to/dest/; 
    rm -f .tmp.index; }

If run from inside the bare repository you can omit setting GIT_DIR.

CB Bailey
  • 755,051
  • 104
  • 632
  • 656
  • Clever :) Is there any particular reason to prefer that answer to your `git archive` answer, other than not depending on tar? – Mark Longair Jul 29 '10 at 16:16
  • @Mark Longair: This one's more 'low level'; the archive solution is more of a user command. I've no idea if this one performs better or worse. I kept the answers separate as I'm genuinely interested to know which one is more popular. – CB Bailey Jul 29 '10 at 16:26
  • As cxreg alludes to, with a bare repository and git 1.7.0.4 the "git checkout-index" step fails with "fatal: This operation must be run in a work tree". (This seems somewhat strange in the case where GIT_INDEX_FILE is set and --prefix is used, I think.) So I'll accept the other answer, since the bare repository case is important for me, but this very useful to know about - thanks for both. – Mark Longair Aug 02 '10 at 06:40
  • @DavidSchmitt: I don't understand your edit. Perhaps I don't understand the use case, checking out into a subdirectory of a bare repository seems a slightly bizarre thing to want to do. Why do we need `$(pwd)` and why do we need `-f` to be passed to `checkout-index`? I think you've completely changed the intent of my answer but I'm not really sure. – CB Bailey Jun 04 '12 at 22:19
  • @Charles: sorry, coding late. the intent was that GIT_WORK_TREE and GIT_INDEX_FILE have to be absolute paths, else you get the error Mark commented on. I changed it to dummy values now. Hopefully this is less obscure. Actually this now should be able to run independent of the cwd and check out the src/ directory from master in $GIT_DIR into $GIT_WORK_TREE. – David Schmitt Jun 05 '12 at 07:31
  • I really, really don't like recommending exporting the `GIT_*` environment variables. It's too easy to forget to unset them and end up doing crazy things lated. I think you are trying to give a solution for a different situation. Perhaps your script should be its own answer? – CB Bailey Jun 05 '12 at 07:34
  • @DavidSchmitt: I've just tested and I'm pretty sure that using a full path for `GIT_WORK_TREE` is not important. What is important is whether the current directory is in the path specified by `GIT_WORK_TREE`. – CB Bailey Jun 05 '12 at 09:53
0

I'm doing this at the moment with this script:

http://gist.github.com/498447

... which parses the output of git ls-tree -r -z <tree-ish>. You can pass it anything that git ls-tree can understand as a tree, e.g:

extract-tree-from-git.py master:src/tests/ /tmp/extracted-tests/
extract-tree-from-git.py HEAD^ /tmp/parent-of-head/
Mark Longair
  • 446,582
  • 72
  • 411
  • 327