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

480

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

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

ripper234
источник
4
Лучшее обсуждение здесь .
cdunn2001
1
@MEM Мне больше нравится этот ответ, но любой из них работает ... stackoverflow.com/a/5377989/11236
ripper234
2
@ ripper234 - Да. Я был в той же ситуации, и я просто сделал эти шаги, и никаких проблем. Все чисто и красиво. Я думаю, это вопрос предпочтений, суть в том, что оба работают, как вы заявляете. Приветствия.
MEM
1
Это так безумие, что нет чистого способа добиться этого, так полезно, когда вы хотите клонировать проект в подключенную общую папку.
Томас Деко
1
Возможный дубликат Как мне клонировать в непустую директорию?
Тобиас Кинцлер

Ответы:

559

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

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

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

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

amicitas
источник
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
alexwenzel
источник
2
Это отличный ответ, позволяющий избежать путаницы в файловой системе.
user151841
1
Это должен быть принятый ответ, так как это не взлом.
php_nub_qq
5
На самом деле это делает именно то, чего ОП (и мне) не хотят, то есть перезаписывает локальные изменения.
Аджан
Мое возражение указывает на то, что это помогло МНЕ, но не является лучшим ответом на вопрос ОП.
TecBrat
2
Может кто-нибудь объяснить, почему -tздесь используется флаг?
JFowkes
38

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

jhwist
источник
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
user1055643
источник
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
return1.at
источник
7
Использование git reset --hardобнулит изменения локального файла, в частности, НЕ то, что запрашивал этот OP. --mixedследует использовать вместо
Калеб
4

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

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

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

okTalk
источник
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каталог метаданных уже существует в каталоге, который вы хотите превратить в рабочую копию.

ThorSummoner
источник
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: путь назначения '.' уже существует и не является пустым каталогом.
Тристан ШАРБОНЬЕР