How do I manage conflicts with git submodules?
Asked Answered
U

11

203

I have a git superproject that references several submodules and I am trying to lock down a workflow for the rest of the my project members to work within.

For this question, lets say my superproject is called supery and the submodule is called subby. (Then is a simplification of what I'm trying to do...I'm not actually using the branches for versions, but I thought it would be easiest to lay out as a question.)

My master branch of supery has the tag v1.0 of the git project subby referenced as a submodule. The branch of supery called one.one and changed the reference of the submodule to point to the tag v1.1 of subby.

I can work within each of these branches without a hitch, but if I try to update the one.one branch with changes from the master branch I receive some conflicts and I don't how to resolve them.

Basically after running a git pull . master while in the subby branch, it looks like it creates additional submodules.

Before the pull/merge, I get the desired response from git submodule from the one.one branch:

$ git checkout master
$ git submodule
qw3rty...321e subby (v1.0)
$ git checkout one.one
$ git submodule
asdfgh...456d subby (v1.1)

But after the pull, it adds additional submodules when I run git submodule:

$ git pull . master
Auto-merged schema
CONFLICT (submodule): Merge conflict in subby - needs qu3rty...321e
Automatic merge failed; fix conflicts and then commit the results.

$ git submodule
qw3rty...321e subby (v1.0)
asdfgh...456d subby (v1.1)
zxcvbn...7890 subby (v1.1~1)

How do I delete/ignore the unwanted submodule references and commit my conflicts and changes? Or is there a parameter I can use with my original git pull that will ignore my submodules?

Undercool answered 5/5, 2009 at 20:11 Comment(0)
B
33

I have not seen that exact error before. But I have a guess about the trouble you are encountering. It looks like because the master and one.one branches of supery contain different refs for the subby submodule, when you merge changes from master git does not know which ref - v1.0 or v1.1 - should be kept and tracked by the one.one branch of supery.

If that is the case, then you need to select the ref that you want and commit that change to resolve the conflict. Which is exactly what you are doing with the reset command.

This is a tricky aspect of tracking different versions of a submodule in different branches of your project. But the submodule ref is just like any other component of your project. If the two different branches continue to track the same respective submodule refs after successive merges, then git should be able to work out the pattern without raising merge conflicts in future merges. On the other hand you if switch submodule refs frequently you may have to put up with a lot of conflict resolving.

Begin answered 7/5, 2009 at 17:33 Comment(3)
Thanks for shedding some light on the question. That makes total sense to me now and the reset command works perfectly for my situation above. But what would be the commands to accept the submodule ref from the master branch and throw away the ref to the current branch's submodule? I know how to handle normal conflicts, but after three days of scouring the web, I can not find one code example other than rm -r. And I'm beginning to think that there a reason for the examples not existing; submodule are so far abstracted from the superproject that you have have to manage every transition.Undercool
FINALLY! An answer! I had added by us: ../Mono.Cecil in git status but git add and git rm failed with Mono.Cecil: needs merge, pathspec 'Mono.Cecil/' did not match any files because it was just an empty folder and git only really handles files. git checkout gave me Mono.Cecil: needs merge, error: you need to resolve your current index first, git submodule update gave Skipping unmerged submodule Mono.Cecil and git checkout master Mono.Cecil FINALLY fixed it. Basic problem: the git status suggestion is wrong, so pick a branch and take its copy of the folder with checkout!Truncated
@IBBoard's command helped me with this situation -- I tried git checkout --ours SUBMOD and git add SUBMOD and others, but finally doing git checkout master SUBMOD fixed the conflict. This comment should probably be an answer, not a comment... :)Inconformity
U
151

Well, its not technically managing conflicts with submodules (ie: keep this but not that), but I found a way to continue working...and all I had to do was pay attention to my git status output and reset the submodules:

git reset HEAD subby
git commit

That would reset the submodule to the pre-pull commit. Which in this case is exactly what I wanted. And in other cases where I need the changes applied to the submodule, I'll handle those with the standard submodule workflows (checkout master, pull down the desired tag, etc).

Undercool answered 7/5, 2009 at 15:33 Comment(4)
For me this only seems to change the status of the conflicting module from "both modified" to "deleted".Daisy
You may want to keep the merged branch's submodule instead: git reset <merged-branch> subbyBedell
works for me as prescribed in the answer.. git reset HEAD path/to/submodule/dirOvershoe
git reset HEAD subby is the savior!Corves
A
94

I struggled a bit with the answers on this question and didn't have much luck with the answers in a similar SO post either. So this is what worked for me - bearing in mind that in my case, the submodule was maintained by a different team, so the conflict came from different submodule versions in master and my local branch of the project I was working on:

  1. Run git status - make a note of the submodule folder with conflicts
  2. Reset the submodule to the version that was last committed in the current branch:

    git reset HEAD path/to/submodule

  3. At this point, you have a conflict-free version of your submodule which you can now update to the latest version in the submodule's repository:

    cd path/to/submodule
    git submodule foreach git pull origin SUBMODULE-BRANCH-NAME
  4. And now you can commit that and get back to work.

Atrium answered 15/9, 2015 at 8:59 Comment(0)
T
39

I had this problem with git rebase -i origin/master to a branch. I wanted to take master's version of the submodule ref, so I simply did:

git reset master path/to/submodule

and then

git rebase --continue

That solved the problem for me.

Talion answered 1/5, 2017 at 13:35 Comment(1)
This worked for me. I'm still figuring what they did in order to damage the submoduleDesmarais
B
33

I have not seen that exact error before. But I have a guess about the trouble you are encountering. It looks like because the master and one.one branches of supery contain different refs for the subby submodule, when you merge changes from master git does not know which ref - v1.0 or v1.1 - should be kept and tracked by the one.one branch of supery.

If that is the case, then you need to select the ref that you want and commit that change to resolve the conflict. Which is exactly what you are doing with the reset command.

This is a tricky aspect of tracking different versions of a submodule in different branches of your project. But the submodule ref is just like any other component of your project. If the two different branches continue to track the same respective submodule refs after successive merges, then git should be able to work out the pattern without raising merge conflicts in future merges. On the other hand you if switch submodule refs frequently you may have to put up with a lot of conflict resolving.

Begin answered 7/5, 2009 at 17:33 Comment(3)
Thanks for shedding some light on the question. That makes total sense to me now and the reset command works perfectly for my situation above. But what would be the commands to accept the submodule ref from the master branch and throw away the ref to the current branch's submodule? I know how to handle normal conflicts, but after three days of scouring the web, I can not find one code example other than rm -r. And I'm beginning to think that there a reason for the examples not existing; submodule are so far abstracted from the superproject that you have have to manage every transition.Undercool
FINALLY! An answer! I had added by us: ../Mono.Cecil in git status but git add and git rm failed with Mono.Cecil: needs merge, pathspec 'Mono.Cecil/' did not match any files because it was just an empty folder and git only really handles files. git checkout gave me Mono.Cecil: needs merge, error: you need to resolve your current index first, git submodule update gave Skipping unmerged submodule Mono.Cecil and git checkout master Mono.Cecil FINALLY fixed it. Basic problem: the git status suggestion is wrong, so pick a branch and take its copy of the folder with checkout!Truncated
@IBBoard's command helped me with this situation -- I tried git checkout --ours SUBMOD and git add SUBMOD and others, but finally doing git checkout master SUBMOD fixed the conflict. This comment should probably be an answer, not a comment... :)Inconformity
M
21

First, find the hash you want to your submodule to reference. then run

~/supery/subby $ git co hashpointerhere
~/supery/subby $ cd ../
~/supery $ git add subby
~/supery $ git commit -m 'updated subby reference'

that has worked for me to get my submodule to the correct hash reference and continue on with my work without getting any further conflicts.

Mavilia answered 9/1, 2013 at 2:1 Comment(4)
or you could just do a git checkout --theirs (or --ours) subbyShang
@Bachi: git checkout --theirs and --ours has no effect on submodules.Bedell
While this does resolve the conflict, it's not easy to determine <hashpointerhere>. I don't know of an easy way to see the submodule commit checked out on each side of the conflict. Whatever commit you check out in subby may be different from either side of the merge, which is not appropriate in a merge commit.Bedell
@nilbus that is true. We have abandoned working with git submodules as that was one of the concerns we had and made it very hard to tell which commit you actually wanted. We've used composer (php) as a package manager, which I actually like since it creates a lock file locking the repos to a certain hash. However, since we are using node_modules within multiple repos, we would run into conflicting modules here and there. We have since switched to npm to manage this stuff but that is also a whole other can of worms.Mavilia
C
10

Got help from this discussion. In my case the

git reset HEAD subby
git commit

worked for me :)

Callen answered 29/8, 2017 at 9:20 Comment(2)
Worked for me. Any idea why??Odor
What i understood you need to reset it to head for the particular submodule.Callen
M
6

All the above didn't work for me... I had the submodule under "unmerged path" and I was stuck...

Eventually after many many attempts what worked was: deleting manually the merge conflicts file from the sub-module than in main repo:

git restore --staged submodule_path

(this moved it to "Changes not staged for commit:")

 git clean -df

then

git submodule update --init

Marris answered 11/10, 2021 at 18:10 Comment(0)
V
3

Well In my parent directory I see:

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Unmerged paths:
(use "git reset HEAD <file>..." to unstage)
(use "git add <file>..." to mark resolution)

So I just did this

git reset HEAD linux
Votyak answered 16/1, 2018 at 8:25 Comment(0)
H
3

How to resolve conflicts with git submodules, in your outer repo containing them

Option 1:

Like the main answer:

# run this for each conflicting submodule
git reset -- path/to/submodule

Then, when done with the conflict resolution, manually cd into each submodule, pull or check out your latest changes you want, then cd back up into the upper repo, and run git add path/to/submodule for each submodule.

Option 2:

Do an interactive rebase in the upper (outer-most) repo:

# pull latest upstream main repo
git fetch origin main:main

# do interactive rebase onto it
git rebase -i main

In the interactive rebase file editor, manually delete all commits which updated your submodules. Complete the rebase.

When done, manually cd into each submodule, pull or check out your latest changes you want, then cd back up into the upper repo, and run git add path/to/submodule for each submodule you want updated to your latest changes.

Done.

See also:

  1. My answer on How to update all git submodules in a repo (two ways to do two very different things!)
Hankow answered 17/2, 2023 at 19:51 Comment(0)
L
1

If you want to use the upstream version:

rm -rf <submodule dir>
git submodule init
git submodule update
Lundell answered 16/9, 2020 at 15:18 Comment(0)
R
1

In case if someone rebased and made git push --force in submodule repo, then

git submodule update --remote --checkout -f <submodule>

Refill answered 29/6, 2023 at 12:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.