Как переместить существующий подмодуль Git в репозиторий Git?

Я хотел бы изменить имя каталога подмодуля Git в моем суперпроекте Git.

Предположим, у меня есть следующая запись в моем .gitmodules файле:

[submodule ".emacs.d/vimpulse"]  
path = .emacs.d/vimpulse  
url = git://gitorious.org/vimpulse/vimpulse.git

Что мне нужно ввести, чтобы переместить каталог .emacs.d/vimpulse в .emacs.d/vendor/vimpulse, не удаляя его сначала (объяснено здесь и здесь), а затем повторно добавить его.

Действительно ли Git нужен весь путь в теге подмодуля?

[submodule ".emacs.d/vimpulse"]

или можно также сохранить только название подпроекта?

[submodule "vimpulse"]

person thisch    schedule 05.01.2011    source источник
comment
ПРИМЕЧАНИЕ: OP отвечает на свой вопрос командой git mv прямо в вопросе.   -  person Dan Rosenstark    schedule 15.04.2014
comment
ОДНАКО, вы не можете использовать git mv так. Используйте deinit, затем rm, как указано stackoverflow.com/a/18892438/8047.   -  person Dan Rosenstark    schedule 15.04.2014
comment
@Yar: по крайней мере, на git 2.0.0, git mv просто работает и для подмодулей, больше ничего не нужно.   -  person Pedro Romano    schedule 26.06.2014
comment
Начиная с Git 1.8.5 перемещение подмодулей поддерживается изначально с помощью команды git mv (из примечаний к выпуску, первая ссылка на которые предоставлена ​​самим @thisch). Также ответил здесь   -  person Dennis van der Schagt    schedule 29.11.2014
comment
git mv действительно перемещает подмодуль в рабочую область и правильно обновляет файлы подмодуля .git, но подпапка в папке .git / modules родительского репо остается прежней - это нормально? (Я использую git 2.19.0 в Windows)   -  person yoyo    schedule 14.01.2020


Ответы (10)


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

Начиная с git 1.8.5, git mv old/submod new/submod работает должным образом и выполняет всю работу за вас. Возможно, вы захотите использовать git 1.9.3 или новее, потому что он включает исправления для перемещения подмодуля.


Этот процесс аналогичен удалению подмодуля (см. Как удалить подмодуль?):

  1. Отредактируйте .gitmodules и соответствующим образом измените путь к подмодулю и поместите его в индекс с помощью git add .gitmodules.
  2. При необходимости создайте родительский каталог для нового местоположения подмодуля (mkdir -p new/parent).
  3. Переместите все содержимое из старого каталога в новый (mv -vi old/parent/submodule new/parent/submodule).
  4. Убедитесь, что Git отслеживает этот каталог (git add new/parent).
  5. Удалите старый каталог с помощью git rm --cached old/parent/submodule.
  6. Переместите каталог .git/modules/old/parent/submodule со всем его содержимым в .git/modules/new/parent/submodule.
  7. Отредактируйте файл .git/modules/new/parent/config, убедитесь, что элемент рабочего дерева указывает на новые местоположения, поэтому в этом примере это должно быть worktree = ../../../../../new/parent/module. Обычно в этом месте прямого пути должно быть на два .. больше, чем каталогов.
  8. Отредактируйте файл new/parent/module/.git, убедитесь, что путь в нем указывает на правильное новое место в папке .git основного проекта, поэтому в этом примере gitdir: ../../../.git/modules/new/parent/submodule.

    git status для меня результат выглядит так:

    # On branch master
    # Changes to be committed:
    #   (use "git reset HEAD <file>..." to unstage)
    #
    #       modified:   .gitmodules
    #       renamed:    old/parent/submodule -> new/parent/submodule
    #
    
  9. Наконец, зафиксируйте изменения.

person Axel Beckert    schedule 10.06.2011
comment
после этого вам нужно вручную очистить ваши [подмодули] .git / config, верно? Или есть команда, которая это делает? - person thisch; 12.06.2011
comment
Это все еще предлагаемый способ? - person Drake Guan; 11.07.2011
comment
FWIW, мне не удалось заставить это работать - возможно, пропущен шаг, о котором я не знаю? - person Allen George; 10.08.2011
comment
При обновлении .gitmodules убедитесь, что вы обновили и эту path конфигурацию, и имя подмодуля. Например, при перемещении foo / module в bar / module вы должны изменить в .gitmodules раздел [submodule "foo/module"] на [submodule "bar/module"] и в том же разделе path = foo/module на path = bar/module. Кроме того, вы должны изменить в .git / config раздел [submodule "foo/module"] на [submodule "bar/module"]. - person wilhelmtell; 12.11.2011
comment
Для меня это тоже не сработало ... ближайшее решение, которое я нашел, - это удалить подмодуль (боль), а затем повторно добавить его в другом месте. - person Pablo Olmos de Aguilera C.; 06.12.2011
comment
Как ни странно, следуя тем же инструкциям, но клонируя новый репозиторий вместо перемещения файлов, я обнаружил, что они работают для некоторых подмодулей. Например: я получаю некоторые из них renamed: plugins/foo -> plugins/asd/bar для других, он не понимает, что они перемещаются: new file: plugins/another_dir/new и deleted: plugins/old (вместо renamed: plugins/old -> plugins/another_dir/new. У меня много подмодулей, каждый изменен на .gitmodules. Так что я не Не понимаю, почему он действует случайным образом: S - person Pablo Olmos de Aguilera C.; 07.12.2011
comment
Очень-очень важное замечание: если вы получили fatal: 'git status --porcelain' failed in..., просто удалите все файлы или каталоги .git в подмодуле. - person antitoxic; 11.03.2012
comment
У меня сработало, спасибо. Единственное, что git add new/parent ничего не сделал для меня, поскольку git не отслеживает каталоги. Вместо этого мне нужно `git add new / parent / submodule`. - person Savageman; 30.03.2012
comment
Порядок шагов был для меня неправильным. git add new/parent ничего не делал после mkdir, что имеет смысл, потому что Git не может отслеживать пустые каталоги. Мне пришлось git add new/parent после перемещения каталога подмодуля с помощью mv. - person Rory O'Kane; 27.08.2012
comment
.git/modules/MODULENAME/config необходимо обновить, чтобы он указывал на новый путь. - person Erik Kaplun; 14.10.2012
comment
Похоже, в этом посте пропущены несколько шагов, таких как редактирование .git/modules/old/parent/submodule, его перемещение в новое место, обновление gitdir в _3 _... - person szx; 28.03.2013
comment
К сожалению, у меня это тоже не сработало. Я продолжал получать fatal: Not a git repository: ../.git/modules/foobar, b / c Я думаю, что не хватает шагов в этом ответе. Я вообще-то не думаю, что есть смысл копаться в сантехнике Git без нужных инструментов. Вот почему я думаю, что лучший ответ - это тот, который использует инструменты Git для удаления и клонирования нового подмодуля. - person Mark Mikofski; 19.09.2013
comment
Ненавижу этот ответ. Обновите свой клиент git и используйте ´git submodule deinit´ evgeny- goldin.com/blog/3-ways-install-git-linux-ubuntu - person Michael Cole; 07.02.2014
comment
Или лучший способ: sudo add-apt-repository ppa: git-core / ppa sudo apt-get update sudo apt-get install git - person Michael Cole; 07.02.2014
comment
Начиная с git 1.8.5, git mv old/submod new/submod работает должным образом и выполняет всю работу за вас. Вероятно, вы захотите использовать git 1.9.3+, потому что он включает исправления для перемещения подмодулей. - person Valloric; 14.05.2014
comment
@Valloric Использует 2.2.1, но все равно нужно вручную изменить имя в parent/submodule/.git, потому что оно ссылается на старое имя, и удалить .git/modules/parent/old. Может потому, что я тоже его переименовал с помощью git mv parent/old parent/new. - person Karsten S.; 27.03.2015
comment
Как упоминалось в нескольких других комментариях, решение stackoverflow.com/a/24767348/262379 (ниже) намного лучше - person Dinis Cruz; 08.06.2015
comment
Хороший человек! На шаге 4 я получил фатальный: не репозиторий git: ../../, поэтому мне пришлось отредактировать старый / parent / submodule / .git, чтобы отразить новое местоположение - person Indio; 09.06.2015
comment
Я думал, что запись old/submod сбивает с толку. Вы можете использовать обычный синтаксис mv. В примере / указывает, что старое расположение submod находилось в папке old. /, Таким образом, имеет обычное значение разделителя каталогов. - person Nino van Hooff; 06.04.2016

Самый современный ответ, взятый из комментария Валлорика выше:

  1. Выполните обновление до Git 1.9.3 (или 2.18, если подмодуль содержит вложенные подмодули < / а>)
  2. git mv old/submod new/submod
  3. Впоследствии .gitmodules и каталог подмодулей уже подготовлены для фиксации (вы можете проверить это с помощью git status.)
  4. Зафиксируйте изменения с помощью git commit, и все готово!

Сделанный!

person phatmann    schedule 15.07.2014
comment
Это действительно работало с 1.9.3 за исключением для подмодуля внутри перемещенного подмодуля. Это потребовало некоторой ручной очистки. - person Pascal; 05.09.2014
comment
Этот ответ должен получить 1000 голосов, я почти запутал свое репо, выполнив шаги, описанные выше, действительно, StackOverflow должен иметь вариант использования для этой ситуации. - person MGP; 13.03.2015
comment
Вау, это сработало как шарм (git 1.9.5), я бы хотел, чтобы это был выбранный ответ. - person Alex Ilyaev; 22.03.2015
comment
Это кажется твердым. git mv old/submod new/submod определенно можно было бы лучше объяснить массам. - person sheriffderek; 24.04.2015
comment
Да, я тоже просто использовал эту git mv технику, и она отлично сработала. - person Dinis Cruz; 08.06.2015
comment
Я могу повторить то, что сказал @Pascal. Я использую версию 2.7.0.windows.1 - person Gregory Kuhn; 10.01.2016
comment
Единственное, чего он не делает, это то, что он не меняет начальную метку для подмодуля. Если вы проверите файл .gitmodules, old/submod по-прежнему будет использоваться в качестве метки для подмодуля, хотя путь был изменен. Чтобы изменить метку, похоже, вам нужно переместить путь к каталогу модулей внутри .git, а затем вручную изменить метку в .gitmodules. - person CMCDragonkai; 07.01.2017
comment
Выполнение этого в Git Bash внутри VSCode сначала у меня не сработало (ошибка Permission denied) - вероятно, VSCode блокирует файлы .git. Запуск в отдельном Git Bash работал нормально. - person Toivo Säwén; 30.01.2020
comment
git mv работал у меня. Поскольку папка назначения пуста, мне пришлось вызвать дополнительный git submodule update --init, чтобы снова увидеть подмодули в папке назначения. Они снова появляются с тем же хешем фиксации в оригинале. - person eigenfield; 05.06.2020

В моем случае я хотел переместить подмодуль из одного каталога в подкаталог, например «AFNetworking» -> «ext / AFNetworking». Я выполнил следующие шаги:

  1. Отредактируйте .gitmodules, изменив имя и путь подмодуля на "ext / AFNetworking"
  2. Переместите каталог git подмодуля из ".git / modules / AFNetworking" в ".git / modules / ext / AFNetworking"
  3. Перенести библиотеку из AFNetworking в ext / AFNetworking
  4. Отредактируйте ".git / modules / ext / AFNetworking / config" и исправьте строку [core] worktree. Мой изменен с ../../../AFNetworking на ../../../../ext/AFNetworking
  5. Отредактируйте "ext / AFNetworking / .git" и исправьте gitdir. Мой изменен с ../.git/modules/AFNetworking на ../../git/modules/ext/AFNetworking
  6. git add .gitmodules
  7. git rm --cached AFNetworking
  8. git submodule add -f <url> ext/AFNetworking

Наконец, я увидел в статусе git:

matt$ git status
# On branch ios-master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   modified:   .gitmodules
#   renamed:    AFNetworking -> ext/AFNetworking

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

person Matt Connolly    schedule 28.04.2012
comment
Спасибо, Мэтт. Я не понял принятого ответа. Спасибо за то, что охватили не только базовый вариант. Это сработало как шарм. - person Andrew Hubbs; 22.01.2013
comment
Вам не нужно перетасовывать пути .git / modules или изменять имя подмодуля (как упоминают arand и Боб Белл). Хотя это может сделать вещи чище. - person gatoatigrado; 26.03.2013
comment
Не забудьте выполнить шаги 2, 3, 4 и 5 рекурсивно для любых подмодулей. - person herzbube; 05.10.2013

[Обновление: 2014-11-26] Как прекрасно резюмирует Яр, прежде чем что-либо делать, убедитесь, что вы знаете URL-адрес подмодуля. Если он неизвестен, откройте .git/.gitmodules и проверьте ключ submodule.<name>.url.

Что сработало для меня, так это удалить старый подмодуль с помощью git submodule deinit <submodule>, за которым следует git rm <submodule-folder>. Затем снова добавьте подмодуль с новым именем папки и выполните фиксацию. Проверка статуса git перед фиксацией показывает, что старый подмодуль переименован в новое имя и изменен .gitmodule.

$ git submodule deinit foo
$ git rm foo
$ git submodule add https://bar.com/foo.git new-foo
$ git status
renamed:    foo -> new-foo
modified:   .gitmodules
$ git commit -am "rename foo submodule to new-foo"
person Mark Mikofski    schedule 19.09.2013
comment
Для этого требуется git 1.8.3 или выше. См. Этот пост для обновления вашего git: evgeny-goldin.com / блог / 3-способа-установка-git-linux-ubuntu - person Michael Cole; 07.02.2014
comment
Или, что лучше: sudo add-apt-repository ppa: git-core / ppa sudo apt-get update sudo apt-get install git - person Michael Cole; 07.02.2014
comment
@MichaelCole Спасибо! Вы правы! См. примечания к выпуску Git-1.8.3. К вашему сведению: Ubuntu-13.10 (Saucy Salamander) имеет Git-1.8.3.2, но это полезно знать есть ppa. Кроме того, IMHO стратегия слияния поддеревьев git - лучший подход; Я отказался от субмодулей для своих собственных проектов. По-прежнему хорошо разбираться в существующих проектах. - person Mark Mikofski; 07.02.2014
comment
Я пробовал несколько решений, но ваше лучшее. Используйте только командную строку, поэтому вам не нужно (и не следует) изменять какой-либо файл git. Спасибо! - person nahung89; 31.07.2019

Кажется, уловка заключается в понимании того, что каталог .git для подмодулей теперь хранится в главном репозитории под .git/modules, и каждый подмодуль имеет файл .git, указывающий на него. Вот процедура, которая вам сейчас нужна:

  • Переместите субмодуль в его новый дом.
  • Отредактируйте файл .git в рабочем каталоге подмодуля и измените путь, который он содержит, так, чтобы он указывал на правильный каталог в каталоге .git/modules главного репозитория.
  • Войдите в каталог .git/modules главного репозитория и найдите каталог, соответствующий вашему подмодулю.
  • Отредактируйте файл config, обновив путь worktree, чтобы он указывал на новое расположение рабочего каталога подмодуля.
  • Отредактируйте файл .gitmodules в корне главного репозитория, обновив путь к рабочему каталогу подмодуля.
  • git add -u
  • git add <parent-of-new-submodule-directory> (Важно, чтобы вы добавляли родительский элемент, а не сам каталог подмодуля.)

Несколько примечаний:

  • Строки [submodule "submodule-name"] в .gitmodules и .git/config должны совпадать друг с другом, но не соответствовать ничему другому.
  • Рабочий каталог подмодуля и каталог .git должны правильно указывать друг на друга.
  • Файлы .gitmodules и .git/config должны быть синхронизированы.
person Paul Gideon Dann    schedule 14.11.2012

Строка в кавычках после «[подмодуль» не имеет значения. Вы можете изменить его на "foobar", если хотите. Он используется для поиска соответствующей записи в ".git / config".

Следовательно, если вы внесете изменения до того, как запустите «git submodule init», все будет нормально. Если вы внесете изменение (или получите изменение путем слияния), вам нужно будет либо вручную отредактировать .git / config, либо снова запустить «git submodule init». Если вы сделаете последнее, у вас останется безобидная "застрявшая" запись со старым именем в .git / config.

person Bob Bell    schedule 05.01.2011
comment
Это действительно раздражает, но вы правы. Хуже всего то, что если вы просто измените URL-адрес, запуск git init, похоже, не обновит его, вам придется отредактировать .git / config вручную. - person crimson_penguin; 07.01.2012
comment
в этом случае git submodule sync автоматически распространяет изменение на .git/config - person CharlesB; 26.04.2012

Вы можете просто добавить новый подмодуль и удалить старый подмодуль с помощью стандартных команд. (должен предотвратить любые случайные ошибки внутри .git)

Пример настройки:

mkdir foo; cd foo; git init; 
echo "readme" > README.md; git add README.md; git commit -m "First"
## add submodule
git submodule add git://github.com/jquery/jquery.git
git commit -m "Added jquery"
## </setup example>

Например, переместите jquery в vendor / jquery / jquery:

oldPath="jquery"
newPath="vendor/jquery/jquery"
orginUrl=`git config --local --get submodule.${oldPath}.url`

## add new submodule
mkdir -p `dirname "${newPath}"`
git submodule add -- "${orginUrl}" "${newPath}"

## remove old submodule
git config -f .git/config --remove-section "submodule.${oldPath}"
git config -f .gitmodules --remove-section "submodule.${oldPath}"
git rm --cached "${oldPath}"
rm -rf "${oldPath}"              ## remove old src
rm -rf ".git/modules/${oldPath}" ## cleanup gitdir (housekeeping)

## commit
git add .gitmodules
git commit -m "Renamed ${oldPath} to ${newPath}"

Бонусный метод для больших подмодулей:

Если подмодуль большой и вы предпочитаете не дожидаться клона, вы можете создать новый подмодуль, используя старый в качестве источника, а затем переключить источник.

Пример (используйте тот же пример настройки)

oldPath="jquery"
newPath="vendor/jquery/jquery"
baseDir=`pwd`
orginUrl=`git config --local --get submodule.${oldPath}.url`

# add new submodule using old submodule as origin
mkdir -p `dirname "${newPath}"`
git submodule add -- "file://${baseDir}/${oldPath}" "${newPath}"

## change origin back to original
git config -f .gitmodules submodule."${newPath}".url "${orginUrl}"
git submodule sync -- "${newPath}"

## remove old submodule
...
person Lance Rushing    schedule 18.12.2012
comment
Если вы не используете head, вам также может потребоваться проверить правильную версию модуля на newPath. - person paulmelnikow; 29.11.2013

Данное решение у меня не сработало, но похожая версия сработала ...

Это с клонированным репозиторием, поэтому репозитории git подмодулей содержатся в директории верхнего уровня репозиториев .git. Все катионы из верхнего репозитория:

  1. Отредактируйте .gitmodules и измените параметр "path =" для рассматриваемого подмодуля. (Не нужно ни изменять метку, ни добавлять этот файл в индекс.)

  2. Отредактируйте .git / modules / name / config и измените параметр "worktree =" для рассматриваемого подмодуля.

  3. бегать:

    mv submodule newpath/submodule
    git add -u
    git add newpath/submodule
    

Интересно, имеет ли это значение, если репозитории являются атомарными или относительными подмодулями, в моем случае это было относительным (подмодуль / .git - это ссылка на topproject / .git / modules / submodule)

person arand    schedule 25.04.2012

Просто используйте сценарий оболочки git-submodule-move.

person Flimm    schedule 22.07.2013
comment
Хех, я снова поискал этот вопрос и использовал один из ответов с более высоким рейтингом, и теперь мне жаль, что я прокрутил вниз и увидел свой предыдущий ответ, о котором я забыл. - person Flimm; 19.05.2014

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

  1. Убедитесь, что подмодуль зарегистрирован и отправлен на свой сервер. Вам также необходимо знать, на какой ветке он находится.
  2. Вам нужен URL-адрес вашего подмодуля! Используйте more .gitmodules, потому что после удаления подмодуля его больше не будет.
  3. Теперь вы можете использовать deinit, rm, а затем submodule add

ПРИМЕР

КОМАНДЫ

    git submodule deinit Classes/lib/mustIReally
    git rm foo
    git submodule add http://developer.audiob.us/download/SDK.git lib/AudioBus

    # do your normal commit and push
    git commit -a 

ПРИМЕЧАНИЕ. git mv этого не делает. Вообще.

person Dan Rosenstark    schedule 15.04.2014
comment
Хорошее резюме. +1 git mv должно быть лучше в самых последних версиях Git. - person VonC; 15.04.2014
comment
@VonC Я тестировал git 1.8.5, почти уверен, что он так же хорош, как и для mv. Спасибо! - person Dan Rosenstark; 01.06.2014