Ошибка объединения после преобразования подмодуля Git в поддерево
У меня есть проект, в котором я первоначально использовал подмодули для некоторого зависимого кода. Оказывается, что подмодули не подходят для этого проекта (и их трудно использовать на практике), поэтому я преобразовываю каждый подмодуль в поддерево (используя новую функцию git-subtree
).
В моем рабочем репозитории я успешно удалил каждый подмодуль и добавил старый подмодуль репо в качестве поддерева. Нет проблем с этим.
Когда я перехожу к другому клону и пытаюсь извлечь из первого, я получаю следующую ошибку на шаге слияния:
error: The following untracked working tree files would be overwritten by merge:
sub/.gitignore
sub/Makefile
sub/README
sub/src/main.c
... and so on for all files in sub/
Aborting
Похоже, что это связано с тем, что файлы в sub/
никогда не существовали в основном репозитории в первую очередь, а когда Git применяет патч для обновления .gitmodules
, он не удаляет каталог с подмодулем файлы. При обработке следующего коммита, где Git пытается создать новые файлы в sub/
, которые теперь являются частью основного репозитория, все эти файлы конфликтуют с все еще существующими файлами в sub/
.
Обходной путь, который я нашел, заключается в использовании rm -rf sub
до git pull
, что позволяет избежать этой проблемы.
Мой вопрос: есть ли какой-либо переключатель командной строки, который я могу использовать с git merge
, который говорит "Перезаписать все файлы, которые существуют в рабочем каталоге"? Еще лучше будет функция, в которой git merge
будет смотреть содержимое существующего файла, и если содержимое идентично файлу, который он собирается создать, подавите сообщение об ошибке и продолжайте.
UPDATE. Я создал репозитории Git, которые демонстрируют эту проблему, чтобы точно показать, о чем я говорю. Воспроизведение:
$ git clone https://github.com/ghewgill/q14224966.git
$ cd q14224966
$ git submodule init
$ git submodule update
$ git merge origin/branch
Это должно привести к сообщению об ошибке
error: The following untracked working tree files would be overwritten by merge:
sub/Makefile
sub/README
sub/src/main.c
Please move or remove them before you can merge.
Aborting
Ответы
Ответ 1
Я знаю, что ваш вопрос был специфическим для слияния, но у меня были схожие проблемы с объединением подмодулей git. Я думаю, что это решение будет работать с вашей проблемой, даже если оно напрямую не затрагивает вопрос о слиянии.
Я обнаружил, что, принудительно проверяя ветку, которую вы хотите объединить, а затем возвращаясь к мастеру, все работает с подмодулями.
Чтобы все работало в вашем примере:
$ git clone https://github.com/ghewgill/q14224966.git
$ cd q14224966
$ git submodule init
$ git submodule update
$ git checkout -f origin/branch
$ git checkout master
$ git merge origin/branch
Это работает, потому что он в основном выполняет ваш rm -rf
шаг для вас. Конечно, это немного круглая, и, возможно, не стоит делать, если у вас есть только один подмодуль, как ваш пример. Но я обнаружил, что это довольно время, когда вы работаете в проекте со многими подмодулями.
Кроме того, как указано в комментариях, если вы хотите избежать внесения изменений в дерево работы, вы можете использовать это:
$ git clone https://github.com/ghewgill/q14224966.git
$ cd q14224966
$ git submodule init
$ git submodule update
$ git reset origin/branch
$ git reset --hard master
Это работает примерно так же, но избегает проверки других файлов в процессе. У меня не было возможности использовать это в дикой природе, но это похоже на звуковой метод.
Там также $ git merge -s subtree origin/branch
. Он работает с вашим примером, но у меня были неожиданные результаты, когда задействовано более одного подмодуля. Однако вам может быть повезло.
Ответ 2
Вы не можете получить git-merge
(или любую другую команду) для принудительно клоблирования файлов, о которых он не знает, о которых нет, нет. git пытается довольно сильно не делать ничего совершенно необратимого.
Но со многими подмодулями вы можете сделать удаление более легким и безопасным с помощью git submodule foreach
:
$ git submodule foreach 'rm -rf $toplevel/$path'
Entering 'sub'
$ git merge origin/branch
Updating a231acd..6b4d2f4
Fast-forward
...
Ответ 3
(Предостережение: я никогда не работал с поддеревьями, и я не знаю, насколько сложным является ваше фактическое репо, поэтому эти решения могут на самом деле не работать для вас.)
От игры с образцом репо я нашел два решения, которые оба работают, хотя они производят разные деревья фиксации:
-
Используйте git merge -s resolve origin/branch
~/q14224966[master]> git reset --hard origin/master
HEAD is now at a231acd add submodule
~/q14224966[master]> touch other.c && git add . && git commit -m "New commit."
[master bc771ac] New commit.
0 files changed
create mode 100644 other.c
~/q14224966[master]> git merge -s resolve origin/branch
Trying really trivial in-index merge...
error: Merge requires file-level merging
Nope.
Trying simple merge.
Simple merge failed, trying Automatic merge.
Adding sub/Makefile
Adding sub/README
Adding sub/src/main.c
Merge made by the 'resolve' strategy.
.gitmodules | 3 ---
sub | 1 -
sub/Makefile | 1 +
sub/README | 1 +
sub/src/main.c | 1 +
5 files changed, 3 insertions(+), 4 deletions(-)
delete mode 160000 sub
create mode 100644 sub/Makefile
create mode 100644 sub/README
create mode 100644 sub/src/main.c
~/q14224966[master]> ls
README main.c other.c sub/
~/q14224966[master]> cd sub/
~/q14224966/sub[master]> ls
Makefile README src/
~/q14224966/sub[master]> git status
# On branch master
# Your branch is ahead of 'origin/master' by 5 commits.
#
nothing to commit (working directory clean)
~/q14224966/sub[master]> cd ..
~/q14224966[master]> git status
# On branch master
# Your branch is ahead of 'origin/master' by 5 commits.
#
nothing to commit (working directory clean)
Здесь результирующее дерево команд: ![git commit tree - merge option]()
-
Используйте переустановку вместо слияния:
~/q14224966[master]> git reset --hard origin/master
HEAD is now at a231acd add submodule
~/q14224966[master]> touch other.c && git add . && git commit -m "New commit."
[master ae66060] New commit.
0 files changed
create mode 100644 other.c
~/q14224966[master]> git rebase origin/branch
First, rewinding head to replay your work on top of it...
Applying: New commit.
~/q14224966[master]> ls
README main.c other.c sub/
~/q14224966[master]> cd sub/
~/q14224966/sub[master]> ls
Makefile README src/
~/q14224966/sub[master]> git status
# On branch master
# Your branch is ahead of 'origin/master' by 4 commits.
#
nothing to commit (working directory clean)
~/q14224966/sub[master]> cd ..
~/q14224966[master]> git status
# On branch master
# Your branch is ahead of 'origin/master' by 4 commits.
#
nothing to commit (working directory clean)
Здесь результирующее дерево фиксации: ![git commit tree - rebase option]()
Ответ 4
Он попытался
git fetch --all
git reset - грубое происхождение/мастер
но это не сработает.
Вы можете использовать стратегию слияния 'ours':
git merge -s наш старый мастер
Вы также можете использовать git -stash для сохранения изменений, затем git -stash примените их, чтобы восстановить их.