Ошибка объединения после преобразования подмодуля 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 примените их, чтобы восстановить их.