Я столкнулся с этой проблемой в реальном проекте и сумел воспроизвести ее с минимальными шагами, описанными ниже.
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
.
Так это баг или я что-то не так делаю?