I encountered this issue in a real project and managed to reproduce it with the minimal steps below.
EDIT: This is not a duplicate question. I saw another question which involves git subtree add
and that's not the case here.
The scenario is: I have a big repository, and I want to give a small part of the project to someone else to work on, and eventually merge their work back to the big repo when they're done.
The problem is git subtree merge
(and the related push/pull) always results in bogus Conflicts.
Here's the full run-down:
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
Here's where I prepare a small repo for my collaborator to work on:
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
Now pretend you're the collaborator working on another machine. Ignore the fact that I'm using local repositories, the issue is the same when using github. Prepare to do some work:
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
Now the hard work, add a line to a file:
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(+)
Collaborator publishes their masterpiece:
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
Normally the collaborator would push to the work
branch here, but I forgot to make smallrepo
a bare repo, so he pushes to work2
. That doesn't change the behavior compared to github and should be immaterial to the problem that you'll actually see at the end.
Collaborator packs up and goes home. Now it's back to me again:
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.
Now there. That single-line change should NOT be a conflict. I've seen the same thing on larger files, big changes, small changes, doesn't matter. Every single file touched on either side becomes a CONFLICT when handled by git subtree merge
.
So, is this a bug, or am I doing something wrong?