Skip to content

Latest commit

 

History

History
99 lines (71 loc) · 3.24 KB

git-submodule-merge-conflicts.md

File metadata and controls

99 lines (71 loc) · 3.24 KB

Git Submodule Merge Conflicts

A submodule merge conflict is possible if the submodule commit diverges independently in some set of branches. When two branches from this set are merged, git cannot not resolve which commit is correct, resulting in a conflict.

Examining Submodule Merge Conflicts

git status will tell you which submodules have conflicts:

> git status
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add <file>..." to mark resolution)
        both modified:   <submodule>

This status message will appear regardless of the ignore setting of the submodule, because this conflict represents a conflict in the super repository content, not the submodule content.

Run git diff to reveal the conflicting commits. Multiple outputs exist depending on the state of the submodule repository:

1) The submodule repository exists on disk

> git diff
diff --cc <submodule>
index <commit1>,<commit2>..0000000
--- a/<submodule>
+++ b/<submodule>

2) The submodule repository does not exist on disk

> git diff
- Subproject commit <commit1>
 -Subproject commit <commit2>
++Subproject commit 0000000000000000000000000000000000000000

Resolving Submodule Merge Conflicts

The git metadata for a submodule is stored in .git\modules\<submodule>. Resolution of a submodule merge conflict is essentially restoring this folder to proper state and then running git add <path-to-submodule>.

If the submodule exists on disk (scenario one above), one resolution strategy is to checkout the correct commit from within the submodule:

cd <path-to-submodule>
git checkout <commit1|commit2>
cd <repository-root>
git add <path-to-submodule>

Another similiar resolution strategy is:

git checkout --ours <path-to-submodule> 
# git checkout --theirs <path-to-submodule>
git add <path-to-submodule>

If the submodule does exist on disk (scenario two above), then neither of these strategies will suffice. Entering the submodule and checking out fails because there is no submodule repository. The -ours or -theirs checkout strategy does nothing, and attempting to retrieve the submodule via git submodule update fails:

> git diff
- Subproject commit <commit1>
 -Subproject commit <commit2>
++Subproject commit 0000000000000000000000000000000000000000

> git checkout --ours <path-to-submodule>

> git status
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add <file>..." to mark resolution)

        both modified: <submodule>
        
> git submodule update
Skipping unmerged submodule <path-to-submodule>

Fortunately, you can use a git reset to modify the index directly:

> git reset <source-branch> -- <path-to-submodule>
# git reset <target-branch> -- <path-to-submodule>

> git status
All conflicts fixed but you are still merging.
  (use "git commit" to conclude merge)

Finally, if the submodule does not exist on disk, you could manually clone the submodule into the submodule path and use a strategy from scenario one.