Как лучше всего «скопировать» в существующую папку?


480

У меня есть рабочая копия проекта, без каких-либо метаданных контроля версий. Теперь я хотел бы сделать эквивалент git-clone в эту папку и сохранить свои локальные изменения.

git-clone не позволяет мне клонировать в существующую папку. Какова лучшая практика здесь?


4
Лучшее обсуждение здесь .
— cdunn2001

1
@MEM Мне больше нравится этот ответ, но любой из них работает ... stackoverflow.com/a/5377989/11236
— ripper234

2
@ ripper234 - Да. Я был в той же ситуации, и я просто сделал эти шаги, и никаких проблем. Все чисто и красиво. Я думаю, это вопрос предпочтений, суть в том, что оба работают, как вы заявляете. Приветствия.
— MEM

1
Это так безумие, что нет чистого способа добиться этого, так полезно, когда вы хотите клонировать проект в подключенную общую папку.
— Томас Деко

Ответы:


559

Это можно сделать путем клонирования в новый каталог, а затем переместить .gitкаталог в существующий каталог.

Если ваш существующий каталог называется «код».

git clone https://myrepo.com/git.git temp
mv temp/.git code/.git
rm -rf temp

Это также можно сделать без проверки во время выполнения команды клонирования; Более подробную информацию можно найти здесь .


25
Обратите внимание, что это именно то предложение от @ChrisJohnsen, которое он оставил в комментариях. Я нашел это полезным и хотел превратить его в реальный ответ. Крис, если ты в итоге положишь ответ, я с радостью его удалю.
— amicitas

2
Спасибо! Хотя здесь не хватает такого шага, как «git checkout -». как он думает все файлы удалены, верно?
— mrooney

2
Нет, если вы используете git cloneв качестве первой команды, дальнейшая команда извлечения не требуется. Если вместо этого вы используете что-то похожее git clone --no-checkoutна этом первом шаге, то после перемещения каталога .git необходимо git reset HEADбудет указать git, что файлы не были удалены.
— amicitas

3
Я бы добавил это в качестве третьего шага: mv temp / .gitignore code / .gitignore
— Даниэль Аранда

1
@KalpeshSoni, да, git будет знать об измененных файлах, и можно будет увидеть изменения, используя обычные команды git, такие как git status.
— amicitas

284

Не клонируйте, принесите вместо этого. В репо:

git init
git remote add origin $url_of_clone_source
git fetch origin
git checkout -b master --track origin/master # origin/master is clone's default

Затем вы можете сбросить дерево, чтобы получить коммит, который вы хотите:

git reset origin/master # or whatever commit you think is proper...

и ты как клонированный.

Интересный вопрос здесь (и тот, на котором нет ответа): как узнать, на каком коммите было основано ваше голое дерево, и, следовательно, на какую позицию сбросить.


7
Я не фанат этого - для каждой установки github «Совет. Помощник по учетным данным работает только при клонировании URL-адреса хранилища HTTPS». Я использовал помощник по учету, и это привело меня в длинную, довольно бесплодную кроличью нору.
— Андрей

5
'git checkout --track origin / master' также хорошо работает вместо 'git checkout -b master --track origin / master'. Сброс не нужен.
— felipecrp

1
Я получаю сообщение об ошибке "Ошибка Git: следующие неотслеживаемые файлы рабочего дерева будут перезаписаны извлечением", поэтому я добавляю эту команду: git clean -d -fx ""
— shakaran

1
определенно не рекомендуется во всех ситуациях, но это именно то, что мне нужно.
— Хаим Элия

1
@AndreasKrey Ваш оригинальный ответ (который я вошел в историю редактирования, чтобы увидеть) делает именно то, что нужно для вопроса (и меня). Измененный ответ barfs на кассе без использования -f, который отбрасывает локальные изменения и это именно то, чего я не хочу. Если бы я был тобой, я бы хотел вернуться к твоему первоначальному ответу.
— Аджан

78

Следующее, что я сделал, чтобы оформить основную ветку в существующем каталоге:

git init
git remote add origin [my-repo]
git fetch
git checkout origin/master -ft

2
Это отличный ответ, позволяющий избежать путаницы в файловой системе.
— user151841

1
Это должен быть принятый ответ, так как это не взлом.
— php_nub_qq

5
На самом деле это делает именно то, чего ОП (и мне) не хотят, то есть перезаписывает локальные изменения.
— Аджан

Мое возражение указывает на то, что это помогло МНЕ, но не является лучшим ответом на вопрос ОП.
— TecBrat

2
Может кто-нибудь объяснить, почему -tздесь используется флаг?
— JFowkes

38

Я бы перешел git cloneв новый каталог и скопировал содержимое существующего каталога в новый клон.


4
если вы это сделаете, убедитесь, что вы просмотрели diff перед фиксацией очень тщательно - это абсолютный классический случай, когда вы можете случайно отменить изменения, которые были сделаны в исходном репо с тех пор, как вы получили свою рабочую копию - потому что не хватает информации в рабочей копии, чтобы выяснить, какие изменения вы внесли по сравнению с тем, что было до того, как вы начали вносить изменения, объединить их с другими изменениями, сделанными в репо. Я видел, как это случалось снова и снова в этой ситуации, до такой степени, что я "сильно разочаровывал" себя и людей, с которыми я работал, когда-либо делал это.
— Бен Клиффорд

72
git clone wherever tmp && git mv tmp/.git . && rm -rf tmpДругими словами, перемещение .gitдиректории из временного клона кажется более простым, чем очистка рабочего дерева клона и копирование туда существующих файлов.
— Крис Джонсен

1
@ChrisJohnsen: вы должны были сделать это в ответ, это определенно лучший способ сделать это imho
— Стефано

2
@ChrisJohnsen git mv tmp/.git .возвращается fatal: cannot move directory over file, source=tmp/.git, destination=.gitза мной. Кто-нибудь знает, в чем проблема?
— Деннис

6
@ Dennis, это опечатка: эта команда должна быть простой mv, а не git mv; хотя это не объясняет, почему у вас уже есть .gitфайл (содержащий gitdir: some/path/to/a/git-dir«gitfile»; если бы его там не было, вы бы fatal: Not a git repository (or any of the parent directories): .gitвместо этого видели ).
— Крис Джонсен

34

Использование временного каталога - это нормально, но это сработает, если вы хотите избежать этого шага. Из корня вашего рабочего каталога:

$ rm -fr .git
$ git init
$ git remote add origin your-git-url
$ git fetch
$ git reset --mixed origin/master

20
git reset --hard origin/masterудалит все локальные файлы.
— Муад Деббар

1
Чтобы добавить к тому, что уже было указано выше, разница между hardи в mixedтом, что смешанный, сохранит локальные изменения (поэтому, если вы позже попытаетесь вытащить его, он покажет вам, например, Невозможно вытащить с ребазой: у вас есть неподготовленные изменения. Передайте или сохраните их ) , хотя hard откажется от этих локальных изменений
— aexl

Ты неправильно записал пульт.
— Гленн Дейтон

10
git clone your_repo tmp && mv tmp/.git . && rm -rf tmp && git reset --mixed

7
Использование git reset --hardобнулит изменения локального файла, в частности, НЕ то, что запрашивал этот OP. --mixedследует использовать вместо
— Калеб

4

Чтобы клонировать git-репо в пустой существующий каталог, сделайте следующее:

cd myfolder
git clone https://myrepo.com/git.git . 

Обратите внимание .на в конце вашей git cloneкоманды. Это загрузит репо в текущий рабочий каталог.


4
fatal: destination path '.' already exists and is not an empty directory.
— Роланд Кофлер

Каталог должен быть пустым.
— okTalk

4
ОП спрашивает, как клонировать в существующий проект, заявляя, что git clone жалуется. Плохой ответ
— mix3d

Это работает, только когда вы создаете новый каталог, запускайте вышеуказанные команды без использования «git init»
— Билал Ахмед

3

Множество ответов уже сделано так, как задал ОП. Но стоит отметить, что сделать это наоборот гораздо проще:

git clone repo-url tmp/
cp -R working/ tmp/

Теперь у вас есть желаемое целевое состояние - свежий клон + локальные изменения.


2

Есть два подхода к этому. Там, где это возможно, я бы начал с чистой папки для вашего нового рабочего каталога git, а затем скопировал вашу версию вещей позже. Это может выглядеть примерно так: *

mv $dir $dir.orig
git clone $url $dir
rsync -av --delete --exclude '.git' $dir.orig/ $dir/
rm -rf $dir.orig

На этом этапе у вас должна быть довольно чистая рабочая копия с вашей предыдущей рабочей папкой в ​​качестве текущего рабочего каталога, поэтому любые изменения, включая удаление файлов, будут отображаться на радаре, если вы запустите git status.

С другой стороны, если вам действительно нужно сделать это наоборот, вы можете получить тот же результат с помощью чего-то вроде этого:

cd $dir
git clone --no-checkout $url tempdir
mv tempdir/.git .
rmdir tempdir
git reset --mixed HEAD

В любом случае, первое, что я хотел бы сделать, это запустить что-то вроде git stashполучения копии всех ваших локальных изменений, отложенных в сторону, затем вы можете повторно применить их и определить, какие из них вы хотите зафиксировать.

* В обоих примерах предполагается, что вы начинаете с оболочки в родительском каталоге вашего проекта.


2

Это лучший из всех методов, с которыми я сталкивался

Клонируйте только папку .git репозитория (исключая файлы, в которых они уже находятся existing-dir) в пустой временный каталог

  1. git clone --no-checkout repo-path-to-clone existing-dir/existing-dir.tmp // может потребоваться --no-hardlinks для клонирования локального репо

Переместите папку .git в каталог с файлами. Это делает existing-dirgit-репо.

  1. mv existing-dir/existing-dir.tmp/.git existing-dir/

Удалить временный каталог

  1. rmdir existing-dir/existing-dir.tmp

  2. cd existing-dir

Git думает, что все файлы удалены, и это возвращает состояние репо в HEAD.

ВНИМАНИЕ: любые локальные изменения файлов будут потеряны.

  1. git reset --mixed HEAD

1
Аппаратный сброс кажется нежелательным в 99% случаев, когда вам нужно это сделать.
— Стефан Фабиан

0

Если вы используете хотя бы git 1.7.7 (который научил cloneэтой --configопции), чтобы превратить текущий каталог в рабочую копию:

git clone example.com/my.git ./.git --mirror --config core.bare=false

Это работает:

  • Клонирование репозитория в новую .gitпапку
  • --mirrorпревращает новый клон в папку с метаданными, как это .gitнеобходимо
  • --config core.bare=falsecountermands неявное bare=trueиз --mirrorопции, тем самым позволяя хранилище иметь соответствующий рабочий каталог и действовать как обычный клон

Это, очевидно, не будет работать, если .gitкаталог метаданных уже существует в каталоге, который вы хотите превратить в рабочую копию.


1
Обратите внимание, что эта техника приведет к [core]разделу локальной конфигурации, включая оба bare = true и bare = false . Более проблематичным является то, что он будет иметь неправильные значения для originудаленного, с [remote "origin"]включенным разделом mirror = trueи спецификацией выборки, которая не будет работать должным образом с рабочей копией. После исправления этих проблем клонирование в нормальном режиме и перемещение новой рабочей копии .gitбудет более эффективным.
— Араксия

0

Обычно я сначала клонирую исходный репозиторий, а затем перемещаю все в существующей папке в исходный репозиторий. Это работает каждый раз.

Преимущество этого метода в том, что вы не пропустите ничего из исходного репозитория, включая README или .gitignore.

Вы также можете использовать команду ниже, чтобы завершить шаги:

$ git clone https://github.com/your_repo.git && mv existing_folder/* your_repo

0

Вы можете сделать это, набрав следующие командные строки рекурсивно:

mkdir temp_dir   //  Create new temporary dicetory named temp_dir
git clone https://www...........git temp_dir // Clone your git repo inside it
mv temp_dir/* existing_dir // Move the recently cloned repo content from the temp_dir to your existing_dir
rm -rf temp_dir // Remove the created temporary directory

0

Просто используйте. в конце git cloneкоманды (находящейся в этом каталоге), вот так:

cd your_dir_to_clone_in/
git clone git@github.com/somerepo/ .

Не работает: fatal: путь назначения '.' уже существует и не является пустым каталогом.
— Тристан ШАРБОНЬЕР
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.