We have a repo with a bunch of submodules and we are currently working on a develop branch.
Starting from the same common commit, two developers, A and B, made some changes to some files (unimportant here I think) and added a new revision of one of the submodules, then commited to develop. Now develop holds rev1 of subm commited by developer A, while B's develop branch holds rev2 of subm, thus creating a conflict when B tries to pull changes made by A from remote.
This is what git status
gives to B, after a merge with conflicts:
Your branch and 'origin/develop' have diverged,
and have 1 and 1 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)
All conflicts fixed but you are still merging.
(use "git commit" to conclude merge)
Changes to be committed:
modified: path/to/another/submodule
modified: path/to/file/file.html
Now, whenever B tries to commit, it gets:
U path/to/subm
error: Committing is not possible because you have unmerged files.
hint: Fix them up in the work tree, and then use 'git add/rm <file>'
hint: as appropriate to mark resolution and make a commit.
fatal: Exiting because of an unresolved conflict.
I tried looking up for solutions and they all seem to suggest to add the conflicted files to the stage to mark them as resolved, but git status
does not list any unmerged files.
It looks like I am missing something here, any help would be gladly appreciated.
What you need to realize here is that a Git submodule is another Git repository.
Let's label all the repositories in play here. I'm going to assume that both developers have their own clones, so that there is another Git at some third location (perhaps GitHub, perhaps a corporate server, whatever it might be):
path/to/another/submodule
.path/to/subm
.When developer A does some work in DevASuper, he:
X
;git add
to add the new commit inDevASubmod2
as an updated gitlink entry; andThe new commit, in DevASuper, contains a gitlink that says "use commit
X
in submodule #2".Developer A can push this new commit to the central superproject (perhaps on a branch). Before he does so, he should also push the new DevASubmod2 commit to CentralSubmod2 (also perhaps on a branch). Whoever merges these, to the branch named
develop
on CentralSuper, should make sure the submodule repository commit in CentralSubmod2 is available to everyone first, presumably by merging that first. (The person who merges them could be developer A himself. This is just a general pattern: the submodule commit must be available first.)Let's call the final commit, on the
develop
branch in CentralSuper, commitSX
, with theS
standing for Super and theX
standing for commitX
(commit SX uses / refers-to commit X from submodule#2).Now we get to Developer B
At any time before or at this point, developer B can make new commits in any of his three repositories. Based on what you've posted, it seems likely that he has made a new commit in DevBSubmod2. Let's call this commit
Y
. Like commitX
, it is some big ugly hash ID.Like developer A, developer B should—and apparently did—now make a new commit in his DevBSuper repository using
git add
andgit commit
. We'll call this commitSY
.So now, developer B wants to merge his new commit with the final result from whoever did the merge of developer A's commit. But commit
SX
says use hash X whileSY
says use hash Y.This is the submodule conflict you are seeing:
The superproject that B is working with/on has a commit,
SY
, that says use Y, and a commit,SX
, that says use X. These "use" things are gitlinks in these two commits.Git cannot resolve this on its own. If the correct resolution is use
X
, developer B should put that in his superproject's index. If the correct resolution is useY
, developer B should put that in his superproject's index. Chances are very good, however, that neither commitX
nor commitY
is the correct commit to use for a new commit in developer B's superproject repository.If this last is true, what developer B must now do is:
X
andY
.Z
. Make sure this is the current commit in DevBSubmod2.path/to/subm
as commitZ
, usinggit add path/to/subm
. This resolves the merge conflict and says that the correct gitlink goes to commitZ
. Neither commitX
nor commitY
is correct;Z
is correct.SZ
.At this point developer B can now send these back to the various central repositories, again keeping in mind that the new submodule commit must be available to everyone before making commit
SZ
available to everyone, since usingSZ
requires that they obtain commitZ
.