172

I want to clone a GIT repo and NOT end up with a .git directory. In other words I just want the files. Is there a way to do this?

git clone --no-checkout did the exact opposite of what I want (gave me just the .git directory).

I am trying to do that for a remote repo, not a local one, meaning this is not a duplicate of "How to do a “git export” (like “svn export”)" (even though the solution might end up being the same).

Community
  • 1
  • 1
Dan Rosenstark
  • 68,471
  • 58
  • 283
  • 421
  • 6
    possible duplicate of [How to do a "git export" (like "svn export")](http://stackoverflow.com/questions/160608/how-to-do-a-git-export-like-svn-export) – Greg Hewgill Oct 16 '10 at 00:56
  • @Greg Hewgill I'm trying to do this from a remote repo. Not sure if that makes this question unique, though. – Dan Rosenstark Oct 16 '10 at 18:07
  • 1
    Though this is a newer question, but I think this is worth to check out: http://stackoverflow.com/questions/11497457/git-clone-without-git-directory – eonil May 25 '15 at 15:06
  • 1
    See my [update answer](https://stackoverflow.com/a/3946745/6309): `git archive` is now (Q4 2017) more precise and won't include empty folders. – VonC Sep 28 '17 at 20:49
  • 1
    You are welcome. Apparently, your comment was flagged and removed... https://chat.stackoverflow.com/transcript/134259?m=39402889#39402889 – VonC Oct 01 '17 at 04:30

8 Answers8

88

The git command that would be the closest from what you are looking for would by git archive.
See backing up project which uses git: it will include in an archive all files (including submodules if you are using the git-archive-all script)

You can then use that archive anywhere, giving you back only files, no .git directory.

git archive --remote=<repository URL> | tar -t

If you need folders and files just from the first level:

git archive --remote=<repository URL> | tar -t --exclude="*/*"

To list only first-level folders of a remote repo:

git archive --remote=<repository URL> | tar -t --exclude="*/*" | grep "/"

Note: that does not work for GitHub (not supported)

So you would need to clone (shallow to quicken the clone step), and then archive locally:

git clone --depth=1 git@github.com:xxx/yyy.git
cd yyy
git archive --format=tar aTag -o aTag.tar

Another option would be to do a shallow clone (as mentioned below), but locating the .git folder elsewhere.

git --git-dir=/path/to/another/folder.git clone --depth=1 /url/to/repo

The repo folder would include only the file, without .git.

Note: git --git-dir is an option of the command git, not git clone.


Update with Git 2.14.X/2.15 (Q4 2017): it will make sure to avoid adding empty folders.

"git archive", especially when used with pathspec, stored an empty directory in its output, even though Git itself never does so.
This has been fixed.

See commit 4318094 (12 Sep 2017) by René Scharfe (``).
Suggested-by: Jeff King (peff).
(Merged by Junio C Hamano -- gitster -- in commit 62b1cb7, 25 Sep 2017)

archive: don't add empty directories to archives

While git doesn't track empty directories, git archive can be tricked into putting some into archives.
While that is supported by the object database, it can't be represented in the index and thus it's unlikely to occur in the wild.

As empty directories are not supported by git, they should also not be written into archives.
If an empty directory is really needed then it can be tracked and archived by placing an empty .gitignore file in it.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • 6
    This worked for me. I would add one more thing. If you don't care about the .git folder at all, then I would use this command: `git --git-dir=/dev/null clone --depth=1 /url/to/repo` – HumanSky Nov 13 '15 at 00:59
  • 2
    This does not remove the .git folder – aliasav Mar 16 '16 at 12:28
  • @VonC I tried: git --git-dir=/dev/null clone --depth=1 /url/to/repo – aliasav Mar 17 '16 at 05:33
  • @aliasav what version of git did you used? And what version of git is used on the remote server side? – VonC Mar 17 '16 at 07:54
  • 1
    `git --git-dir=/dev/null clone --depth=1 /url/to/repo` not working. I'm using git version 2.6.4 (Apple Git-63). check details with running `GIT_TRACE_SETUP=true` – Bhavik Mar 17 '16 at 12:02
  • @Bhavik then I guess my answer stands: specify a path which is outside local path of the repo your are cloning. – VonC Mar 17 '16 at 12:22
  • yeah. /dev/null was the first thing that occured to me while reading this (hence one of the upvotes), but unfortunately it doesn't work `git version 2.5.4 (Apple Git-61)` – tishma Nov 02 '16 at 14:08
  • 1
    @andrew " In git version 2.11 there is no `--git-dir` option for `clone` command. There is `--separate-git-dir`.": no `--git-dir` is an option of `git`, not `git clone` – VonC Oct 05 '17 at 13:39
  • 1
    Running `git archive --remote=https://github.com/pornel/dssim.git @ | tar -t` I get `tar: This does not look like a tar archive`. Doesn't it work with GitHub? Also, what does the `@` mean? – André Werlang Dec 18 '17 at 15:43
  • 2
    @AndréWerlang 7 years later... I am not too sure of the `@`: I have removed it. Also GitHub does not support a remote `git archive`: I have edited the answer to propose an alternative. – VonC Dec 18 '17 at 16:20
65
git archive --format=tar --remote=<repository URL> HEAD | tar xf -

taken from here

Community
  • 1
  • 1
Jon Penn
  • 659
  • 5
  • 3
50

You can create a shallow clone to only get the last few revisions:

 git clone --depth 1 git://url

then either simply delete the .git directory or use git archive to export your tree.

knittl
  • 246,190
  • 53
  • 318
  • 364
  • Howt o prevent this error when I update it by repeating the clone: " fatal: destination path 'XYZ' already exists and is not an empty directory." – Sohail Si Sep 11 '15 at 16:59
  • 1
    @SohailSi: either clone to a new location or remove the old directory. You're probably better off just fetching the new revisions, if you want to update your local copy. – knittl Sep 11 '15 at 19:25
  • @Sohail First time you get files using `clone` then every time you need to update always use `pull`. – MMJ Dec 30 '22 at 12:27
8

Why not perform a clone and then delete the .git directory so that you just have a bare working copy?

Edit: Or in fact why use clone at all? It's a bit confusing when you say that you want a git repo but without a .git directory. If you mean that you just want a copy of some state of the tree then why not do cp -R in the shell instead of the git clone and then delete the .git afterwards.

Andrew
  • 2,943
  • 18
  • 23
  • Thanks for that. The files are in a git repo. I was hoping to be able to direct Mac users to get a copy of the repo in one line, without it becoming a GIT repo. – Dan Rosenstark Oct 15 '10 at 22:35
  • You shouldn't have people directly getting code from the repo if they can't use it (ie don't have the Git repository). – alternative Oct 16 '10 at 00:17
  • @Amoss Releasing a tarball so that people aren't constantly grabbing the latest code? – alternative Oct 16 '10 at 14:19
  • 3
    @mathepic: and to release a tarball you need a way of getting a clean working copy out of the repository - which is exactly the question that was posed. – Andrew Oct 16 '10 at 20:10
  • @Amoss it sounds like he wants to have the user download it with git then delete the .git repository. In any case, this is the wrong thing to do anyway. For example, I wouldn't check ./configure in to the source control because its autogenerated with configure.ac, but you want to distribute it with ./configure. – alternative Oct 16 '10 at 22:02
  • 1
    The .git folder is HUGE. I don't need to be spending all that extra disk usage copying .git. I just need the files. I'm sure there's a way to do this.... – trusktr May 02 '13 at 18:04
  • 1
    Reading the answer below and then doing a bit of googling led to another question: http://stackoverflow.com/questions/160608/how-to-do-a-git-export-like-svn-export If you take a look at the use of git archive --remote then it does exactly what you (and the original poster) are looking for. Edit: which is what Jon answered lower down. – Andrew May 23 '13 at 10:53
5

git checkout -f

There's another way to do this by splitting the repo from the working tree.

This method is useful if you need to update these git-less git files on a regular basis. For instance, I use it when I need to check out source files and build an artifact, then copy the artifact into a different repo just for deployment to a server, and I also use it when pushing source code to a server when I want the source code to checkout and build into the www directory.

We'll make two folders, one for the git one for the working files:

mkdir workingfiles
mkdir barerepo.git

initialize a bare git repo:

cd barerepo.git
git --bare init 

Then create a post-receive hook:

touch hooks/post-receive
chmod ug+x hooks/post-receive

Edit post-receive in your favorite editor:

GIT_WORK_TREE=/path/to/workingfiles git checkout -f
# optional stuff:
cd down/to/some/directory
[do some stuff]

Add this as a remote:

git remote add myserver ssh://user@host:/path/to/barerepo.git

Now every time you push to this bare repo it will checkout the working tree to /workingfiles/. But /workingfiles/ itself is not under version control; running git status in /workingfiles/ will give the error fatal: Not a git repository (or any parent up to mount point /data). It's just plain files.

Unlike other solutions rm -r .git command is not needed, so if /workingfiles/ is some other git repo you don't have to worry about the command used removing the other repo's git files.

Community
  • 1
  • 1
Slam
  • 3,125
  • 1
  • 15
  • 24
4

No need to use git at all, just append "/zipball/master/" to URL (source).

Downloading

This solution is the closest to "Download ZIP" button on github page. One advantage is lack of .git directory. The other one - it downloads single ZIP file instead of each file one by one, and this can make huge difference. It can be done from command line by wget: wget -O "$(basename $REPO_URL)".zip "$REPO_URL"/zipball/master/. The only problem is, that some repositories might not have master branch at all. If this is the case, "master" in URL should be replaced by appropriate branch.

Unzipping

Once the ZIP is there, the final unzipped directory name may still be pretty weird and unexpected. To fix this, name can be extracted by this script, and mv-ed to basename of the URL. Final script.sh could look something like (evals for dealing with spaces):

#Script for downloading from github. If no BRANCH_NAME is given, default is "master".
#usage: script.sh URL [BRANCH_NAME]
__repo_name__='basename "$1"'
__repo_name__="$(eval $__repo_name__)"
__branch__="${2:-master}"
#downloading
if [ ! -e ./"$__repo_name__"".zip" ] ; then
wget -O "$__repo_name__"".zip" "$1""/zipball/$__branch__/"
fi
#unpacking and renaming
if [ ! -e ./"$__repo_name__" ] ; then
unzip "$__repo_name__"".zip" && 
__dir_name__="$(unzip -qql $__repo_name__.zip | sed -r '1 {s/([ ]+[^ ]+){3}\s+//;q}')" &&
rm "$__repo_name__"".zip" &&
mv "$__dir_name__" "$__repo_name__"
fi

Maintaining

This approach shoud do the work for "just the files", and it is great for quick single-use access to small repositories.

However. If the source is rather big, and the only possibility to update is to download and rebuild all, then (to the best of my knowledge) there is no possibility to update .git-less directory, so the full repo has to be downloaded again. Then the best solution is - as VonC has already explained - to stick with shallow copy git clone --depth 1 $REPO_URL. But what next? To "check for updates" see link, and to update see great wiki-like answer.

Przemek
  • 240
  • 2
  • 8
  • Great answer! About the `Maintaining` section, full repo has not to be downloaded again. How about first time you download using `clone --depth 1` then every time you need to update always use `pull`, right? – MMJ Dec 30 '22 at 12:47
2
git --work-tree=/tmp/files_without_dot_git clone --depth=1 \
  https://git.yourgit.your.com/myawesomerepo.git \
  /tmp/deleteme_contents_of_dot_git

Both the directories in /tmp are created on the fly. No need to pre-create these.

Manoj
  • 93
  • 1
  • 9
  • 1
    Could you describe how the command works? – Roger Lindsjö Jan 14 '21 at 11:00
  • It will clone the contents of the repo to the folder `/tmp/files_without_dot_git` except the `.git` folder and the .git folder content will go to the folder `/tmp/deleteme_contents_of_dot_git` which you can delete later. So you can do `git init` in `/tmp/files_without_dot_git` folder to create a brand new repo. – Manoj Jan 15 '21 at 00:12
0

It sounds like you just want a copy of the source code. If so why not just copy the directory and exclude the .git directory from the copy?

JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • 10
    That's what I'm asking: how to do that with git... I can already tell that there's no built-in way to do it from the answers that I'm getting, though. Thanks anyway! – Dan Rosenstark Oct 15 '10 at 22:36