706

I have directory A with files matching directory B. Directory A may have other needed files. Directory B is a git repo.

I want to clone directory B to directory A but git-clone won't allow me to since the directory is non-empty.

I was hoping it would just clone .git and since all the files match I could go from there?

I can't clone into an empty directory because I have files in directory A that are not in directory B and I want to keep them.

Copying .git is not an option since I want refs to push/pull with and I don't want to set them up manually.

Is there any way to do this?

Update: I think this works, can anyone see any problems? -->

cd a
git clone --no-hardlinks --no-checkout ../b a.tmp 
mv a.tmp/.git .
rm -rf a.tmp
git unstage # apparently git thinks all the files are deleted if you don't do this
svick
  • 236,525
  • 50
  • 385
  • 514
Dale Forester
  • 18,145
  • 10
  • 27
  • 27
  • 1
    Just wondering what would happen if '--no-checkout' would be omitted except that the temporary clone consumes more disc space and time. Would 'git unstage' or something else still be necessary? – grenix May 25 '21 at 15:09
  • Maybe [git-force-clone](https://github.com/tj/git-extras/blob/master/man/git-force-clone.md)? – Sparkler Sep 29 '21 at 04:51

18 Answers18

852

This worked for me:

git init
git remote add origin PATH/TO/REPO
git fetch
git reset origin/master  # Required when the versioned files existed in path before "git init" of this repo.
git checkout -t origin/master

NOTE: -t will set the upstream branch for you, if that is what you want, and it usually is.

cmcginty
  • 113,384
  • 42
  • 163
  • 163
  • 2
    I use this method, it works great! One note, the -t option should be --track, which isn't in the overview but is in the details of ; git help checkout. http://git-scm.com/docs/git-checkout – AnneTheAgile Mar 01 '14 at 02:10
  • 79
    This does not work in a non-empty directory when the incoming files already exist (as the original question describes). But if you `git reset origin/master` after the `git fetch`, it will work (also preserving any local changes). – Araxia Aug 15 '14 at 00:42
  • 2
    this is the safest and most logical answer. – Fábio Batista Oct 17 '14 at 06:09
  • 9
    fatal: Cannot update paths and switch to branch 'master' at the same time. – Arnold Roa Apr 19 '15 at 23:43
  • 2
    @ArnoldRoa, make sure your `origin/master` branch actually exists (it should show up with a `git branch -a`). I got the same error, turned out my repo on github wasn't completely initialized. – hectorh30 Jun 21 '15 at 06:46
  • Using @Araxia's version, I found I also had to nuke any submodules (i.e. do `rm -rf $(ls -A)` in each), because the `git reset origin/master` step would throw an error that `.git/modules/` didn't exist. – DuBistKomisch Jan 12 '16 at 08:26
  • 9
    This answer doesn't work for me. When I do `git checkout ...` git complains that all my files would be overwritten and I should move them first. When I do ` git reset origin/master/` first the checkout command complains that a branch named master already exists. – Saskia Oct 20 '16 at 17:16
  • I had to use `git checkout -t origin/master -f` to force the issue. – Brian Nov 17 '16 at 01:17
  • 8
    `git checkout master` was a sufficient final step for me. – yoyo Jan 11 '17 at 01:40
  • 6
    `git checkout -t origin/master` gave me the error `fatal: A branch named 'master' already exists.` I didn't manage to fix it, but I seem to be fine anyway. – Daniel Buckmaster Mar 13 '17 at 08:14
  • 26
    All steps worked perfectly but the last one got me: ``fatal: A branch named 'master' already exists``. I think I did not really need it. – Shadi Oct 20 '17 at 11:45
  • In the commands shown above, can we write branch other than `master`, i.e., some underlying branch? I have a sudden need for it, want to initialize from that underlying branch in my folder, as I don't have access to master branch, and the folder is non-empty as well! – Ankur Shah Nov 18 '17 at 06:13
  • Yes, the branch name can be any from the `origin` remote repo, `master` is just the most common. – cmcginty Nov 18 '17 at 06:23
  • Thanks cmcginty, I created a Github gist for this https://gist.github.com/jweston491/45ee193d5a51741188aa903916aa0063 – user3183717 Feb 22 '19 at 19:55
  • I keep getting `fatal: A branch named 'master' already exists`. I don't know what to do about it? It may exist from doing `git init`, but there is nothing in it. – dbinott Apr 01 '19 at 14:14
  • 1
    `git reset origin/master` and `git checkout -t origin/master` did not work for me. I already was on the master branch. And when I tried to push my first commit, I had to perform `git push --set-upstream origin master` instead. My 2 cents :) – Lideln Kyoku Apr 08 '19 at 23:25
  • 2
    a long time late to the thread, but for me all I did was 'git init', 'git remote add origin URL', 'git add .', 'git commit -m ' then 'git push -u origin master'. All my files are pushed and the repositories linked. – Neil Walker Aug 28 '19 at 17:49
  • ugh, I get `fatal: ambiguous argument 'origin/master': unknown revision or path not in the working tree.` on the use of `git reset origin/master` – Jason S Sep 11 '19 at 17:10
  • 13
    Instead of the last `git checkout -t origin/master`, do `git branch --set-upstream-to=origin/master` and `git ls-files -z --deleted | xargs -0 git checkout --`. This does not fail due to "master already exists", and it preserves any locally modified files. – RichardC Mar 05 '20 at 20:03
  • 1
    for me the last step failed also with `fatal: A branch named 'master' already exists` but I could solve it using from the accepted answer `git reset --hard HEAD` – derHugo Mar 10 '20 at 14:59
  • As an addition to @RichardC's comment, if there are also binary files that only exist in the local directory, then instead of the last 'git checkout --', we may need to say 'git restore'. – Yuning Apr 14 '20 at 18:56
  • I'm doing this in a Dockerfile, creating a virtual environment with pipenv as a separate image layer, but in the project directory so I can copy it from an intermediate build and discard the intermediate layers. I had to modify slightly to `RUN git fetch && rm Pipfile Pipfile.lock && git checkout -t origin/master` as the `git reset origin/master` was making all the files show up as deleted, and the checkout then failed. – hlongmore Jun 09 '20 at 19:24
  • 2
    2020's calling, remember to consider using `git reset origin/main` (i.e. `main` instead of `master`). Took me by surprise when following the copy-paste-directions. – Adrian Föder Feb 16 '21 at 18:46
  • `git reset origin/master` put all pre-existing files as unstaged but deleted. Running this next resolved all problems. `git reset --hard HEAD; git branch --set-upstream-to=origin/master` – OldBuildingAndLoan May 22 '23 at 22:13
185

In the following shell commands existing-dir is a directory whose contents match the tracked files in the repo-to-clone git repository.

# Clone just the repository's .git folder (excluding files as they are already in
# `existing-dir`) into an empty temporary directory
git clone --no-checkout repo-to-clone existing-dir/existing-dir.tmp # might want --no-hardlinks for cloning local repo

# Move the .git folder to the directory with the files.
# This makes `existing-dir` a git repo.
mv existing-dir/existing-dir.tmp/.git existing-dir/

# Delete the temporary directory
rmdir existing-dir/existing-dir.tmp
cd existing-dir

# git thinks all files are deleted, this reverts the state of the repo to HEAD.
# WARNING: any local changes to the files will be lost.
git reset --hard HEAD
bob esponja
  • 4,093
  • 3
  • 31
  • 29
Dale Forester
  • 18,145
  • 10
  • 27
  • 27
  • 8
    I needed to do `git reset --hard HEAD` or it wouldn't give up on the "deleted" files. – Dimitar Aug 31 '11 at 18:25
  • 23
    `git reset HEAD` worked fine for me. `git reset --hard HEAD` destroys any changes in your files, so if they are not exactly the same as the files in the repository, you should not do that. – Tgr Dec 19 '12 at 16:58
  • 1
    `git reset HEAD` doesn't seem to have any affect for me. `git reset --hard HEAD` does - but that loses any changes you've made to the files. Is there a better solution? – Jacob Dorman Jul 20 '13 at 01:14
  • 1
    @Casey's answer -- git init/remote add/fetch/checkout -- is cleaner and simpler and doesn't require any temporary folders. – yoyo Jul 25 '14 at 21:03
  • 1
    @Casey's answer didn't work for me when there were already files in folders that needed to remain but that weren't in the git repo. This is useful for updating config after running install scripts where files and directories are created but you need to update/add files on top of the installed items. – soulston Aug 04 '14 at 15:58
  • Just wondering what would happen if '--no-checkout' would be omitted except that the temporary clone consumes more disc space and time. Would 'git reset' or something else still be necessary? – grenix May 25 '21 at 15:14
  • Oh man. This is so great. I have been looking for such a solution for many years. I actually managed to do this using a GUI. GitHub Desktop. Just use the Clone with GitHub Desktop link and choose the empty temporary directory. Then move the .Git folder manually and then when you go back into GitHub Desktop, it will ask you to relocate the .Git folder. Once this has been done, all the untracked files show up in the GUI. – Charles Robertson Dec 06 '22 at 14:50
139

A slight modification to one of the answers that worked for me:

git init
git remote add origin PATH/TO/REPO
git pull origin master

to start working on the master branch straight away.

PaulMest
  • 12,925
  • 7
  • 53
  • 50
mohsaied
  • 2,066
  • 1
  • 14
  • 25
  • 1
    had to do reset HEAD --hard to clean the dirty existing directory, without removing irrelevant files specified in gitignore – Ray Foss Jun 28 '17 at 17:25
  • 1
    This is the one that actually worked for me, as opposed to the @cmcginty's answer. – certainlyakey Sep 07 '17 at 06:18
  • 6
    This is not quite equivalent to a git-clone — what's missing is the upstream information for the master branch. This can be fixed by adding `git branch --set-upstream-to=origin/master master`. – Slaven Rezic Apr 20 '18 at 13:46
  • This version worked for me, just had to do a git reset --hard HEAD – Frédéric Klee Sep 17 '19 at 15:11
52

Warning - this could potentially overwrite files.

git init     
git remote add origin PATH/TO/REPO     
git fetch     
git checkout -t origin/master -f

Modified from @cmcginty's answer - without the -f it didn't work for me

Chris Stryczynski
  • 30,145
  • 48
  • 175
  • 286
JohnFF
  • 723
  • 5
  • 20
28

Here's what I ended up doing when I had the same problem (at least I think it's the same problem). I went into directory A and ran git init.

Since I didn't want the files in directory A to be followed by git, I edited .gitignore and added the existing files to it. After this I ran git remote add origin '<url>' && git pull origin master et voíla, B is "cloned" into A without a single hiccup.

Maciej Łebkowski
  • 3,837
  • 24
  • 32
BjornSnoen
  • 313
  • 3
  • 7
  • 3
    This technique does not work in a non-empty directory when the incoming files already exist (as the original question describes). – Araxia Aug 15 '14 at 00:49
22

Another simple recipe seems to work well for me:

git clone --bare $URL .git
git config --unset core.bare

My main use case for checking out to a directory with existing files is to control my Unix dotfiles with Git. On a new account, the home directory will already have some files in it, possibly even the ones I want to get from Git.

sealor
  • 135
  • 8
Ken Williams
  • 22,756
  • 10
  • 85
  • 147
  • 1
    Bare repositories are setup a little differently and while this does work I would not recommend it. :) – ThorSummoner Feb 17 '16 at 23:54
  • 1
    Can you be more specific? What is different? – Ken Williams Feb 18 '16 at 02:02
  • 1
    Only two differences: 1.) The `.git/config` file indicates that the repos is bare. 2.) Files normally stored in `.git` is stored at the root (which you called `.git`) – mozey Feb 01 '17 at 16:00
  • 10
    Those are exactly the changes that cloning to `.git` and setting `core.bare` to `false` will take care of, so I still feel good about this method. – Ken Williams May 18 '17 at 22:12
  • This works fine, until you realize bare repositories work differently that default ones, e.g. there's no `.git/refs/remotes/` directory – Kipras Melnikovas Jun 28 '23 at 15:57
17

I have used this a few moments ago, requires the least potentially destructive commands:

cd existing-dir
git clone --bare repo-to-clone .git
git config --unset core.bare
git remote rm origin
git remote add origin repo-to-clone
git reset

And voilá!

KuttKatrea
  • 171
  • 1
  • 3
  • which of these commands would still be potentially destructive? I guess 'git reset', but without any option is there still destructive potential? – grenix May 25 '21 at 15:22
  • No command is destructive. `git reset` will only reset the index, but will not modify any file. – KuttKatrea Jul 27 '21 at 19:55
8

This worked for me:

cd existing_folder
git init
git remote add origin path_to_your_repo.git
git add .
git commit
git push -u origin master
Mike6679
  • 5,547
  • 19
  • 63
  • 108
8

I had a similar problem with a new Apache web directory (account created with WHM) that I planned to use as a staging web server. I needed to initially clone my new project with the code base there and periodically deploy changes by pulling from repository.

The problem was that the account already contained web server files like:

.bash_history
.bash_logout
.bash_profile
.bashrc
.contactemail
.cpanel/
...

...that I did not want to either delete or commit to my repository. I needed them to just stay there unstaged and untracked.

What I did:

I went to my web folder (existing_folder):

cd /home/existing_folder

and then:

git init
git remote add origin PATH/TO/REPO
git pull origin master
git status

It displayed (as expected) a list of many not staged files - those that already existed initially from my cPanel web account.

Then, thanks to this article, I just added the list of those files to:

**.git/info/exclude**

This file, almost like the .gitignore file, allows you to ignore files from being staged. After this I had nothing to commit in the .git/ directory - it works like a personal .gitignore that no one else can see.

Now checking git status returns:

On branch master
nothing to commit, working tree clean

Now I can deploy changes to this web server by simply pulling from my git repository. Hope this helps some web developers to easily create a staging server.

Hashim Aziz
  • 4,074
  • 5
  • 38
  • 68
Vlado
  • 3,517
  • 2
  • 26
  • 24
7

The following worked for me. First I'd make sure the files in the a directory are source-controlled:

$ cd a
$ git init
$ git add .
$ git commit -m "..."

Then

$ git remote add origin https://URL/TO/REPO
$ git pull origin master --allow-unrelated-histories
$ git push origin master
Kevin Le - Khnle
  • 10,579
  • 11
  • 54
  • 80
5

Maybe I misunderstood your question, but wouldn't it be simpler if you copy/move the files from A to the git repo B and add the needed ones with git add?

UPDATE: From the git doc:

Cloning into an existing directory is only allowed if the directory is empty.

SOURCE: http://git-scm.com/docs/git-clone

Roberto Aloi
  • 30,570
  • 21
  • 75
  • 112
  • 2
    No, the owner and the files could be arbitrary. This is for a situation with multiple developers. We all have existing directories and only one currently has a git checkout. We all largely have the same subset of files so we want to have the other developers be able to clone while retaining their files. And it should be as elegant and convenient as possible. – Dale Forester Mar 09 '10 at 17:32
  • Honestly, I don't see the point of developing in such a condition. Can't you use branches and merge operations? Or having sub-repositories with external dependencies? Why would you want to rely on a single "git checkout"? – Roberto Aloi Mar 09 '10 at 18:01
  • 6
    A "single git checkout" is not the point of the whole ordeal. It's just that this is the way it is and we need a way to move forward. I updated the original question with a solution that appears to be working. I appreciate the feedback, though. – Dale Forester Mar 09 '10 at 18:14
  • 3
    There are lots of legitimate cases for this -- I have a complex folder tree that has to be setup BEFORE my project's source can be setup, and that folder tree contains licensed works that can't be stored on GitHub for example. – BrainSlugs83 Oct 10 '14 at 05:09
5

Here is what I'm doing:

git clone repo /tmp/folder
cp -rf /tmp/folder/.git /dest/folder/
cd /dest/folder
git checkout -f master
Philip Kirkbride
  • 21,381
  • 38
  • 125
  • 225
4

this is work for me ,but you should merge remote repository files to the local files:

git init
git remote add origin url-to-git
git branch --set-upstream-to=origin/master master
git fetch
git status
RODNEY ZHANG
  • 193
  • 1
  • 9
3

I was looking for something similar, and here's what I came up with:

My situation is one where I have an active web tree and I was trying to create a remote repository for it without moving any of the files in the current web tree. Here's what I did:

  1. Go to the web tree and run git init
  2. Go to the intended location of the repository and run: git clone --bare /path/to/web/repo
  3. Edit the config file in my remote repo and remove the [remote "origin"] section.
  4. Add a [remote "origin"] section to .git/config in the web tree pointing to the new remote repo.
Lendrick
  • 907
  • 6
  • 12
2

I was looking for a different question when I stumbled on this: How to clone into an existent directory where the files weren't there?

At any rate, i did just this recently for some non-source-controlled copies of files on a couple of servers.

cd <target directory>
git init
git remote add origin <repository URI>
git fetch
git branch -f master origin/master
git reset
git show HEAD:.gitignore > .gitignore

This:

  • Initializes an empty repo directory for you
  • Adds a remote for the repository you intend to connect to
  • Retrieves the repository folder contents (/.git)
  • Forces the default branch from git init to track origin/master
  • Unstages all changes created by the fetch (I don't precisely understand the mechanism for staging all the files on fetch)
  • Copies in the repository's .gitignore file (which you'll want if you're going to use it)

For my question, the answer was the git reset --hard HEAD in Dale Forester's answer.

Alternative instructions for arbitrary branches and remote names

git init
git remote add <remotename> <repository URI>
git checkout -b <localbranchname>
git fetch <remotename> <remotebranchname>
git branch -f <localbranchname> <remotename>/<remotebranchname>
git reset
git show HEAD:.gitignore > .gitignore

As above, this does:

  • Initializes an empty repo directory for you
  • Adds a remote for the repository you intend to connect to
  • Sets the local branch name. Optional, but recommended to keep branches straight if you're doing more than one branch on the same environment
  • Retrieves the repository folder contents (/.git)
  • Forces the local branch from git checkout -b <localbranchname> to track <remote>/<remotebranchname>
  • Unstages all changes created by the fetch (I don't precisely understand the mechanism for staging all the files on fetch)
  • Copies in the repository's .gitignore file (which you'll want if you're going to use it)

If you do a git status at the end of this, you'll see unstaged changes for any files in the current directory (the working directory) whether the working directory has anything to do with the repository structure or not.

1

I liked Dale's answer, and I also added

git clone --depth 2 --no-checkout repo-to-clone existing-dir/existing-dir.tmp
git branch dev_new214
git checkout dev_new214
git add .
git commit
git checkout dev
git merge dev_new214

The shallow depth avoided a lot of extra early dev commits. The new branch gave us a good visual history that there was some new code from this server that was placed in. That is the perfect use branches in my opinion. My thanks to the great insight of all the people who posted here.

gdlmx
  • 6,479
  • 1
  • 21
  • 39
Dmitri R117
  • 2,502
  • 23
  • 20
1

I got the same issues when trying to clone to c/code

But this folder contains a whole bunch of projects.

I created a new folder in c/code/newproject and mapped my clone to this folder.

git for desktop then asked of my user and then cloned fine.

Tom
  • 343
  • 2
  • 7
0

This question has a lot of answers, and I don't think any of them cover the option of initializing the A as a Git repo and then pulling from B to A.

# Turn `A` into a Git repo and check in files
git -C A init
git -C A add --all
git -C A commit -m "Add existing files"

# Set `B` as a remote
git -C A remote add local-B file:///B

# Fetch & merge B 'master' to A 'master'
git -C A pull --allow-unrelated local-B master
shadowtalker
  • 12,529
  • 3
  • 53
  • 96