Git: рекурсивное перемещение подмодулей (вложенные подмодули)

У меня есть следующая структура Git

- git-repo a
-- subdirectory 2015
--- git-submodule b
-- git-submodule c
--- git-submodule d

Я хотел бы переместить подмодуль git c в папку 2015. Мне известны "грязные способы" сделать это (которые включают изменение.git/config и изменение gitdir в нескольких файлах в файлах.git/modules).

Я недавно прочитал, что git mv должен уметь это делать, т.е.

git mv c 2015/

Это прекрасно работает для репозиториев, в которых нет вложенного подмодуля (в моем случае - d). Тем не менее, когда я запускаю эту команду в моем каталоге, я получаю ошибки, такие как

fatal: Not a git repository: d/../../.git/modules/c/modules/d
fatal: 'git status --porcelain' failed in submodule 2015/c

(обратите внимание, эта ошибка возникает в состоянии git после выполнения вышеупомянутого перемещения)

Кто-нибудь знает о чистом методе, чтобы сделать этот шаг (то есть тот, который не предполагает ручного изменения путей в файлах.git/modules)?

Изменить: (10/10/2015)

Мое лучшее на данный момент решение, которое не включает в себя модификации ни одного из файлов конфигурации git: (сначала убедитесь, что все изменения в d были зафиксированы и отправлены куда-то)

rm c/d -rf
git mv c 2015
cd 2015/c
git submodule update

Изменить: (10/10/2015)

Еще менее навязчивый обходной путь

git mv c 2015
rm 2015/c/d/.git
cd 2015/c
git submodule update

Изменить: (21/9/2018)

Начиная с версии git 2.19. Это было исправлено и git mv ведет себя как ожидалось.

2 ответа

Решение

Как подтвердил @VonC в /questions/10335918/git-rekursivnoe-peremeschenie-podmodulej-vlozhennyie-podmoduli/10335922#10335922, это ошибка в git mv.

Есть несколько возможных обходных путей. Самый простой не требует сложных модификаций файлов.git (я использую этот с тех пор, как задаю вопрос). Это работает следующим образом:

git mv c 2015
rm 2015/c/d/.git
cd 2015/c
git submodule update

Временно удаляет файл.git в d subsubmodule. Обновление подмодуля git затем исправляет этот файл.git снова.

Другие обходные пути, позволяющие избежать временного удаления gitdir, см. В следующем ответе: /questions/10335918/git-rekursivnoe-peremeschenie-podmodulej-vlozhennyie-podmoduli/10335922#10335922

Обновление Q2 2018 и Git 2.18:

Перемещение субмодуля, в котором есть субмодуль, с помощью " git mv "забыл сделать необходимые настройки для вложенных субмодулей;
теперь кодовый путь научился рекурсировать в подмодули.

См. Сообщение 6856077 (28 марта 2018 г.) Джонатана Тана ( jhowtan )
Смотрите коммит da62f78, коммит 0c89fdd, коммит 3b8fb39, коммит f793b89, коммит 61aad92 (28 марта 2018 г.) от Stefan Beller ( stefanbeller )
(Объединено Юнио С Хамано - gitster - в коммите 0c7ecb7, 08 мая 2018 г.)

подмодуль: исправление вложенных подмодулей после перемещения подмодуля

Поскольку у подмодулей могут быть вложенные подмодули, мы бы также хотели исправить вложенные подмодули, когда их об этом попросят. Добавьте опцию, чтобы входить во вложенные подмодули, а также подключать их.

Поскольку подмодули идентифицируются по их имени (которое определяет их каталог git по отношению к каталогу git их суперпроекта) внутри и по их пути в рабочем дереве суперпроекта, мы должны убедиться, что отображение name <-> path сохраняется нетронутым Мы можем сделать это в git-mv команда, написав .gitmodules сначала файл, а затем принудительная перезагрузка механизма конфигурации субмодуля.


Обновление Q4 2017:

В последней версии Git 2.14.x/2.15 (4 квартал 2017 г.) обнаружена ошибка

См. Коммит c514167 (15 сентября 2017 г.) от Heiko Voigt ( hvoigt )
(Объединено Юнио С Хамано - gitster - в коммите 450b908, 25 сентября 2017 г.)

Когда используешь git-mv с подмодулем он обнаружит это и обновит пути для своих конфигураций (.gitmodules, worktree и gitfile).
Это не работает для рекурсивных подмодулей, где пользователь переименовывает корневой подмодуль.


Оригинальный ответ 2015

Я только что протестировал его с помощью git 2.6.0 (в Windows), и перемещение подмодулей с их собственными вложенными модулями кажется проблематичным:

C:\Users\vonc\prog\git\tests\submove>git clone --recursive a a1
Cloning into 'a1'...
done.
Submodule '2015/b' (C:/Users/vonc/prog/git/tests/submove/b) registered for path '2015/b'
Submodule 'c' (C:/Users/vonc/prog/git/tests/submove/c) registered for path 'c'
Cloning into '2015/b'...
done.
Submodule path '2015/b': checked out 'dc18955ec7b9ad0c04245968e2474646e4d593b2'
Cloning into 'c'...
done.
Submodule path 'c': checked out 'fb4722eaca17ac171b7a2c8c5a1ac1e697f0ee85'
Submodule 'd' (C:/Users/vonc/prog/git/tests/submove/d) registered for path 'd'
Cloning into 'd'...
done.
Submodule path 'c/d': checked out '73cd7b8ff82519720b2fcca18df5ed00dd618b71'

Я имею:

a1
  c
    d
  2015
    b

Если я попытаюсь переместить субмодуль c в подпапке 2015:

C:\Users\vonc\prog\git\tests\submove\a1>git mv c 2015/c

C:\Users\vonc\prog\git\tests\submove\a1>git status
fatal: Not a git repository: d/../../.git/modules/c/modules/d
fatal: 'git status --porcelain' failed in submodule 2015/c

Я обнаружил, что мне нужно изменить 2 вещи во вложенном модуле d:

1 / изменить вручную .git/modules/c/modules/d/config ввести правильный путь:

git config -f .git/modules/c/modules/d/config core.worktree ../../../../../2015/c/d
                                                                           ^^^^

2 / изменить d worktree:

git config -f .git/modules/c/modules/d/config core.worktree ../../../../../2015/c/d

Оттуда git status работает, но мне нравится (чтобы быть уверенным), чтобы добавить git submodule sync --recursive:

C:\Users\vonc\prog\git\tests\submove\a1>git submodule sync --recursive
Synchronizing submodule url for '2015/b'
Synchronizing submodule url for '2015/c'
Synchronizing submodule url for '2015/c/d'

git status действительно показывает ожидаемый результат:

C:\Users\vonc\prog\git\tests\submove\a1>git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   .gitmodules
        renamed:    c -> 2015/c

Я добавляю и фиксирую это изменение:

C:\Users\vonc\prog\git\tests\submove\a1>git add .

C:\Users\vonc\prog\git\tests\submove\a1>git commit -m "move sub c in 2015/c"
[master 8289632] move sub c in 2015/c
 2 files changed, 1 insertion(+), 1 deletion(-)
 rename c => 2015/c (100%)

C:\Users\vonc\prog\git\tests\submove\a1>gl
* 8289632 - (HEAD -> master) move sub c in 2015/c (3 seconds ago) <VonC>
* 7ebb8e0 - (origin/master, origin/HEAD) a with sub c (38 minutes ago) <VonC>

Теперь я клонирую, что репо, чтобы проверить ход, действительно было правильно зарегистрировано:

C:\Users\vonc\prog\git\tests\submove>git clone --recursive a1 a2
Cloning into 'a2'...
done.
Submodule '2015/b' (C:/Users/vonc/prog/git/tests/submove/b) registered for path '2015/b'
Submodule 'c' (C:/Users/vonc/prog/git/tests/submove/c) registered for path '2015/c'
Cloning into '2015/b'...
done.
Submodule path '2015/b': checked out 'dc18955ec7b9ad0c04245968e2474646e4d593b2'
Cloning into '2015/c'...
done.
Submodule path '2015/c': checked out 'fb4722eaca17ac171b7a2c8c5a1ac1e697f0ee85'
Submodule 'd' (C:/Users/vonc/prog/git/tests/submove/d) registered for path 'd'
Cloning into 'd'...
done.
Submodule path '2015/c/d': checked out '73cd7b8ff82519720b2fcca18df5ed00dd618b71'

Как вы видете, c а также c/d в ожидаемом 2015/ вложенная:

C:\Users\vonc\prog\git\tests\submove>cd a2

C:\Users\vonc\prog\git\tests\submove\a2>dir 2015\c

 Directory of C:\Users\vonc\prog\git\tests\submove\a2\2015\c

03/10/2015  18:10    <DIR>          .
03/10/2015  18:10    <DIR>          ..
03/10/2015  18:10                29 .git
03/10/2015  18:10                40 .gitmodules
03/10/2015  18:10    <DIR>          d
               2 File(s)             69 bytes
               3 Dir(s)  23 656 910 848 bytes free

C:\Users\vonc\prog\git\tests\submove\a2>dir 2015\c\d

 Directory of C:\Users\vonc\prog\git\tests\submove\a2\2015\c\d

03/10/2015  18:10    <DIR>          .
03/10/2015  18:10    <DIR>          ..
03/10/2015  18:10                42 .git
03/10/2015  18:10                 3 d.txt
               2 File(s)             45 bytes
               2 Dir(s)  23 656 910 848 bytes free
Другие вопросы по тегам