185

I want to use something similar to:

git checkout -- <path>/<file> 

but I want to checkout the file to some folder I choose, rather than the overwriting the local <path>/<file>.

Any idea?

1

11 Answers 11

248

Another solution which is a bit cleaner - just specify a different work tree.

To checkout everything from your HEAD (not index) to a specific out directory:

git --work-tree=/path/to/outputdir checkout HEAD -- . 

To checkout a subdirectory or file from your HEAD to a specific directory:

git --work-tree=/path/to/outputdir checkout HEAD -- subdirname 
Sign up to request clarification or add additional context in comments.

12 Comments

Minor note - you do need an absolute path as shell tilde expansion doesn't occur, i.e. --work-tree=/home/thomasg/okcopy rather than --work-tree=~/okcopy (possibly using a relative path while sitting inside the same git tree works too, but that way lies madness and git status outputs in R'lyehian)
It works as expected with old commits too (e.g. give a SHA in place of HEAD), however git status then shows a lot of mods (presumably because the index now matches the other directory and not the untouched normal work tree). git reset got it back to a good state.
Same here git status shows a lot of mods, and git reset doesn't help. I had to git checkout -f HEAD to restore the state of my repo.
FYI: you need to create the directory by yourself, otherwise you get this error: fatal: This operation must be run in a work tree
This disastrously modifies the index of the main working tree, which is typically bad. As @TomGoodfellow suggests, git reset suffices to restore the main working tree to sanity. To safely export repository subdirectories at any SHA1, branch, or tag without modifying the main working tree, see Charles Bailey's infamous git archive solution. Likewise, to safely checkout multiple branches at the same time, the new git worktree add subcommand is your friend.
|
65

As per Do a "git export" (like "svn export")?

You can use git checkout-index for that, this is a low level command, if you want to export everything, you can use -a,

git checkout-index -a -f --prefix=/destination/path/ 

To quote the man pages:

The final "/" [on the prefix] is important. The exported name is literally just prefixed with the specified string.

If you want to export a certain directory, there are some tricks involved. The command only takes files, not directories. To apply it to directories, use the 'find' command and pipe the output to git.

find dirname -print0 | git checkout-index --prefix=/path-to/dest/ -f -z --stdin 

Also from the man pages:

Intuitiveness is not the goal here. Repeatability is.

4 Comments

Sadly this won't work from a bare git repository, even with the --prefix set :-( (tested with git 1.9.1)
if you want to check out a branch/commit of a bare git repository, use GIT_WORK_TREE=../path/to/place git checkout
git worktree (see below) imho is the canonical answer today and might be added here.
agree with @geek-merlin here is the official git documentation for that feature git-scm.com/docs/git-worktree I have been using it in work for the last year and had been very useful allows me to be on top of different features and answer questions for the team faster or put on hold some others to give priority to other things.
59

If you're working under your feature and don't want to checkout back to master, you can run:

cd ./myrepo git worktree add ../myrepo_master master git worktree remove ../myrepo_master 

It will create ../myrepo_master directory with master branch commits, where you can continue work

5 Comments

Best answer - simple, and unlike git --work-tree=/path/to/outputdir checkout HEAD -- . it doesn't do anything to the index, just copies the selected branch to the specified location (with the addition of a .git file).
And how would I undo this change?
@ScottP.just remove myrepo_master directory
undoing this is a subcommand from worktree: git worktree remove ../myrepo_master
the first command adds / creates a working tree of the WHOLE repository, while the question was about checking out a specific file or a folder (a PART of the repository) into a specific place
39

For a single file:

git show HEAD:abspath/to/file > file.copy 

1 Comment

+1 and to clarify on the "certain previous commit" (instead of HEAD): It refers to the SHA1 ID that can easily be found via gitk. If I only need to "checkout" that file to a temporary location (i.e. not reverting), then I would use the show subcommand: git show 82e54378856215ef96c5db1ff1160a741b5dcd70:MyProj/proguard/mapping.txt > myproj_mapping.txt
22

The above solutions didn't work for me because I needed to check out a specific tagged version of the tree. That's how cvs export is meant to be used, by the way. git checkout-index doesn't take the tag argument, as it checks out files from index. git checkout <tag> would change the index regardless of the work tree, so I would need to reset the original tree. The solution that worked for me was to clone the repository. Shared clone is quite fast and doesn't take much extra space. The .git directory can be removed if desired.

git clone --shared --no-checkout <repository> <destination> cd <destination> git checkout <tag> rm -rf .git 

Newer versions of git should support git clone --branch <tag> to check out the specified tag automatically:

git clone --shared --branch <tag> <repository> <destination> rm -rf <destination>/.git 

3 Comments

git --work-tree=/path/to/outputdir checkout <tag> -- . didn't work for you?
No, it doesn't. The actual file in the original work directory is unchanged, but the staged version is lost and replaced with the version from the tag. It's especially bad if the staged version contained a carefully picked set of changes to be committed. I don't want the export command to touch my index, period.
I also copy .git/config before git checkout to do autocrlf (and possible other) content changes like the source worktree does.
13

Adrian's answer threw "fatal: This operation must be run in a work tree." The following is what worked for us.

git worktree add <new-dir> --no-checkout --detach cd <new-dir> git checkout <some-ref> -- <existing-dir> 

Notes:

  • --no-checkout Do not checkout anything into the new worktree.
  • --detach Do not create a new branch for the new worktree.
  • <some-ref> works with any ref, for instance, it works with HEAD~1.
  • Cleanup with git worktree prune.

1 Comment

+1 for commenting on how to cleanup - everyone else is happy to make a mess of the current repo. only this one has no side-effects.
4

Use git archive branch-index | tar -x -C your-folder-on-PC to clone a branch to another folder. I think, then you can copy any file that you need

1 Comment

git archive <commit> <path to extract> | tar -xvC <dest dir>
2

Addition to @hasen's answer. You might want to use git ls-files instead of find to list files to checkout like:

git ls-files -z *.txt | git checkout-index --prefix=/path-to/dest/ -f -z --stdin 

git ls-files ignores uncommitted files.

1 Comment

Thank you for properly using -z! Nice that you provide script that's not vulnerable to certain kinds of injection attacks.
1

I'm using this alias for checking out a branch in a temporary directory:

[alias] cot = "!TEMP=$(mktemp -d); f() { git worktree prune && git worktree add $TEMP $1 && zsh -c \"cd $TEMP; zsh\";}; f" # checkout branch in temporary directory 

Usage:

git cot mybranch 

You are then dropped in a new shell in the temporary directory where you can work on the branch. You can even use git commands in this directory.

When you're done, delete the directory and run:

git worktree prune 

This is also done automatically in the alias, before adding a new worktree.

Comments

0

I defined an git alias to achieve just this (before I found this question).

It's a short bash function which saves the current path, switch to the git repo, does a checkout and return where it started.

git checkto develop ~/my_project_git

This e.g. would checkout the develop branch into "~/my_project_git" directory.

This is the alias code inside ~/.gitconfig:

[alias] checkTo = "!f(){ [ -z \"$1\" ] && echo \"Need to specify branch.\" && \ exit 1; [ -z \"$2\" ] && echo \"Need to specify target\ dir\" && exit 2; cDir=\"$(pwd)\"; cd \"$2\"; \ git checkout \"$1\"; cd \"$cDir\"; };f" 

Comments

0

If you are working in mydir, why not simply cp -r mydir mydir2 and then cd mydir2; git checkout commit#

1 Comment

Except that this procedure produces a different result when mydir2 already exists, I like this pragmatic approach just because of having less git stuff to memorize. I just would consider using also git clean in mydir2. Depending on use case detaching from remote or removing .git directory might also be an idea.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.