Рабочий процесс поддерева Git. Почему слияние/вытягивание поддерева всегда приводит к КОНФЛИКТУ?

Я столкнулся с этой проблемой в реальном проекте и сумел воспроизвести ее с минимальными шагами, описанными ниже.

EDIT: Это не повторяющийся вопрос. Я видел другой вопрос, который касается git subtree add, но здесь это не так.

Сценарий таков: у меня есть большой репозиторий, и я хочу передать небольшую часть проекта кому-то еще для работы и, в конечном итоге, объединить их работу обратно в большой репозиторий, когда они закончат.

Проблема в том, что git subtree merge (и связанные с ними push/pull) всегда приводят к фиктивным конфликтам.

Вот полное изложение:

root@devbox:/tmp/git-demo# ll
total 164
drwxr-xr-x 2 root root   4096 Dec  5 10:55 ./
drwxrwxrwt 9 root root 159744 Dec  5 10:55 ../

root@devbox:/tmp/git-demo# git init bigrepo
Initialized empty Git repository in /tmp/git-demo/bigrepo/.git/

root@devbox:/tmp/git-demo# cd bigrepo/
root@devbox:/tmp/git-demo/bigrepo# echo 1 > one.txt
root@devbox:/tmp/git-demo/bigrepo# echo 2 > two.txt
root@devbox:/tmp/git-demo/bigrepo# mkdir lib
root@devbox:/tmp/git-demo/bigrepo# echo 3 > lib/three.txt
root@devbox:/tmp/git-demo/bigrepo# echo 4 > lib/four.txt
root@devbox:/tmp/git-demo/bigrepo# git add -A :/
root@devbox:/tmp/git-demo/bigrepo# git commit -minitial
[master (root-commit) 8360303] initial
 4 files changed, 4 insertions(+)
 create mode 100644 lib/four.txt
 create mode 100644 lib/three.txt
 create mode 100644 one.txt
 create mode 100644 two.txt

Вот где я готовлю небольшой репозиторий для моего соавтора:

root@devbox:/tmp/git-demo/bigrepo# git subtree split --prefix=lib
87938ea784d67b83d61e6292a85788f3bdb28fab
root@devbox:/tmp/git-demo/bigrepo# git checkout -b lib_br 87938ea784d67b83d61e6292a85788f3bdb28fab
Switched to a new branch 'lib_br'

root@devbox:/tmp/git-demo/bigrepo# git init ../smallrepo
Initialized empty Git repository in /tmp/git-demo/smallrepo/.git/

root@devbox:/tmp/git-demo/bigrepo# git remote add small ../smallrepo
root@devbox:/tmp/git-demo/bigrepo# git push small lib_br:work
Counting objects: 4, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (4/4), 238 bytes | 0 bytes/s, done.
Total 4 (delta 0), reused 0 (delta 0)
To ../smallrepo
 * [new branch]      lib_br -> work

Теперь представьте, что вы соавтор, работающий на другой машине. Не обращайте внимания на то, что я использую локальные репозитории, проблема та же, что и при использовании github. Подготовьтесь к некоторой работе:

root@devbox:/tmp/git-demo/bigrepo# cd ../collaborator/
root@devbox:/tmp/git-demo/collaborator# git clone ../smallrepo
Cloning into 'smallrepo'...
done.
root@devbox:/tmp/git-demo/collaborator# cd smallrepo/
root@devbox:/tmp/git-demo/collaborator/smallrepo# ls
four.txt  three.txt
root@devbox:/tmp/git-demo/collaborator/smallrepo# git status
On branch work
Your branch is up-to-date with 'origin/work'.

nothing to commit, working directory clean

Теперь тяжелая работа, добавьте строку в файл:

root@devbox:/tmp/git-demo/collaborator/smallrepo# echo 3-too >> three.txt
root@devbox:/tmp/git-demo/collaborator/smallrepo# git commit -a -m"added a line"
[work feb5252] added a line
 1 file changed, 1 insertion(+)

Соавтор публикует свой шедевр:

root@devbox:/tmp/git-demo/collaborator/smallrepo# git push origin work:work2
Counting objects: 5, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 265 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To /tmp/git-demo/collaborator/../smallrepo
 * [new branch]      work -> work2

Обычно соавтор нажимал бы здесь на ветку work, но я забыл сделать smallrepo голым репозиторием, поэтому он нажимает на work2. Это не меняет поведение по сравнению с github и должно быть несущественным для проблемы, которую вы на самом деле увидите в конце.

Сотрудник собирает вещи и идет домой. Теперь он снова вернулся ко мне:

root@devbox:/tmp/git-demo/collaborator/smallrepo# cd ../../bigrepo
root@devbox:/tmp/git-demo/bigrepo# git checkout master
Switched to branch 'master'

root@devbox:/tmp/git-demo/bigrepo# ll
total 24
drwxr-xr-x 4 root root 4096 Dec  5 11:06 ./
drwxr-xr-x 5 root root 4096 Dec  5 10:59 ../
drwxr-xr-x 9 root root 4096 Dec  5 11:06 .git/
drwxr-xr-x 2 root root 4096 Dec  5 11:06 lib/
-rw-r--r-- 1 root root    2 Dec  5 11:06 one.txt
-rw-r--r-- 1 root root    2 Dec  5 11:06 two.txt

root@devbox:/tmp/git-demo/bigrepo# git subtree pull --prefix=lib small work2
From ../smallrepo
 * branch            work2      -> FETCH_HEAD
Auto-merging lib/three.txt
CONFLICT (add/add): Merge conflict in lib/three.txt
Automatic merge failed; fix conflicts and then commit the result.

Сейчас. Это однострочное изменение НЕ должно быть конфликтом. Я видел то же самое в больших файлах, большие изменения, маленькие изменения, не имеет значения. Каждый отдельный файл, затронутый с любой стороны, становится КОНФЛИКТОМ при обработке git subtree merge.

Так это баг или я что-то не так делаю?


person Alex R    schedule 05.12.2015    source источник
comment
Возможный дубликат конфликта слияния git-subtree pull   -  person Franck    schedule 06.12.2015
comment
Возможный дубликат конфликта git-subtree при извлечении из центрального репо также   -  person Franck    schedule 06.12.2015
comment
Не дубликат. В обоих случаях используется git subtree add и pull из центрального репо. Я использую разделение поддерева и извлечение из репозитория соавтора, это прямо противоположно этим другим вопросам.   -  person Alex R    schedule 07.12.2015