Ответ 1
Ваша история выглядит примерно так:
---X A
\
Y B
git ls-tree A
показывает (например):
040000 tree 48770cdc854cc14fecc71029180be7a979f4baa1 S
100644 blob beac6e189b7c69b249271b52cd2db5e418c05a50 file
git ls-tree A:S
показывает (например):
100644 blob 6357df9903460c9e8b43311aff3c7a6fd7fe6aa1 somefile
git ls-tree B
показывает (например):
100644 blob 1f8556335163a2bcbcc366a17d08d1f8e0540e6f .gitmodules
160000 commit 234871cd6f0c1f9109e483383d7712dd8a1986e5 S
100644 blob beac6e189b7c69b249271b52cd2db5e418c05a50 file
(cd S; git ls-tree HEAD)
показывает (например):
100644 blob abccc3958be33be4b93f56efae1b60820545aad2 somefile
Вы хотите перейти от фиксации Y (или более поздней) к фиксации X (или ранее) или наоборот.
Если ваша активная ветвь - B, то git checkout A
говорит (например):
error: The following untracked working tree files would be overwritten by checkout:
S/somefile
Please move or remove them before you can switch branches.
Aborting
Git очень сложно никогда не потерять данные, если вы не скажете об этом (например, с параметрами "force" ). Проблема Git находит и сообщает здесь, что ветвь A имеет различное содержимое для S/somefile
, а затем рабочее дерево. Поскольку S/somefile
не отслеживается (с точки зрения суперпроекта), Git отказывается заменить файл и, таким образом, отказывается переключать ветки/фиксации.
Git мог бы быть разумнее об этом (заметив, что файл отслеживается в подмодуле, поэтому он не должен считаться невоспроизводимым при переключении ветвей в суперпроекте), но это ограничение текущей реализации. Существует проект Google Summer of Code 2011 для Git, который направлен на решение некоторых областей поддержки подмодулей, но мне не ясно, будет ли эта точная проблема будет рассмотрена.
Вы могли бы, как вы полагаете, переписать свою историю, чтобы S
всегда казался подмодулем. Это наверняка представит гладкую поверхность для будущих коммутаторов commit, но это осложняется тем фактом, что вам нужно будет убедиться в том, что вы совершили фиксацию в исходном репозитории подмодулей, которые отражают каждое историческое состояние каталога S
в исходных коммитах. Если у вас много разных деревьев S
(т.е. Вы сделали некоторые локальные изменения в S
до преобразования его в подмодуль), то это может быть сложный процесс /script.
Простым обходным решением может быть временная проверка "пустой ветки" в подмодуле перед переключением на коммит, который имеет его как каталог.
-
Создайте "пустую ветвь" в подмодуле.
git checkout --orphan empty git rm -r --cached . git commit --allow-empty -mempty
Вы можете опубликовать эту "ветку" в репозитории оригиналов подмодулей, чтобы никто другой не нуждался в том, чтобы воссоздать его сами.
-
Если вам нужно переключиться с фиксации, где
S
является подмодулем для комманды, гдеS
является каталогом, сначала проверьте "пустую ветвь" в подмодуле:(cd S && git checkout empty) git checkout A
Вы увидите это предупреждение, потому что Git оставит
S/.git
:warning: unable to rmdir S: Directory not empty
Поскольку
S/.git
все еще присутствует, вы должны быть осторожны, чтобы выдавать команды Git только за пределамиS
при работе с фиксацией, которая имеетS
как каталог; Команды Git, выпущенные подS
, будут работать сS/.git
(в этом состоянии это просто "подрепозиторий", а не полный подмодуль) вместо репозитория верхнего уровня.git
. -
Если вам нужно переключиться с фиксации, где
S
является каталогом для фиксации, гдеS
является подмодулем, вам нужно будет проверить соответствующую ветвь/фиксацию в подмодуле после переключения суперпроектов фиксации.
Вы можете использоватьgit submodule update
для восстановления фиксации, записанной в суперпроекте. Или, если вы работали над ветвью в подмодуле, просто проверьте его.git checkout B # THEN git submodule update # OR checkout a specific branch (cd S && git checkout master) # OR checkout previous branch (cd S && git checkout -)