Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't resolve merge conflict with git submodule folder

I have two git branches, develop and redesign that I need to merge. I have a submodule called library where its updates are being tracked by develop. When I run 'git merge' it says library has been modified by both even though I haven't touched the library submodule. When I click on library in VS Code to see the conflicting changes I see this:

diff --cc library
index 749618f9,589a7ae5..00000000
--- a/library
+++ b/library

I've tried deleting the library folder and running 'git submodule update' while in the redesign branch before merging with no success. I added ignore = all to the .gitmodules file in redesign but didn't work. How do I get rid of the merge conflict with this submodule?

like image 512
mdailey77 Avatar asked Aug 23 '19 20:08

mdailey77


1 Answers

The problem is that library has been modified in both branches, with respect to the merge-base commit. The trick here is understanding what it means for a submodule to be "modified".

Remember that the essence of any submodule is that your superproject is referring to some other Git repository. That other Git repository—the one being used as a submodule—has no idea that it is being used as a submodule. It's just a regular old Git repository.1 It has commits. The true name of any one commit is its hash ID. The superproject that uses this submodule runs Git commands in the submodule to tell it to git checkout some particular commit by hash ID, which result in the submodule Git being in detached HEAD mode.

Meanwhile, back in the superproject: This repository is an ordinary Git repository. It has commits. The true name of each commit is some hash ID, though generally you'll git checkout some branch name. The branch name will resolve to some particular hash ID, and your superproject Git will check out that commit via that branch name—e.g., develop—and now be on some particular commit, e.g., a123456.... So let's say you're on commit a123456.

Somewhere in commit a123456, there is a file-like object that is not actually a file, but instead is a gitlink. This gitlink object in the commit contains the raw hash ID of some commit that exists in the submodule. In your case, this gitlink is the entry for the name library and it holds, e.g., 589a7ae5. That's the submodule's commit: your superproject Git will, if you run git submodule update, enter the submodule Git and command it to git checkout 589a7ae5.

So: each commit in the superproject has a "file" named library that is really a gitlink, and that stores some hash ID. You've now run:

git checkout develop
git merge redesign

(or maybe vice versa). The git merge command has located the commits designated by the branch names develop and redesign, along with a third commit that is the merge base of these other two commits.

All three of these commits have (or lack: one of yours is 00000000) a gitlink entry named library. The three hash IDs in these gitlinks are all different. Git is now attempting to merge two diffs:

  • One diff says starting with gitlink X in the merge base, replace that gitlink with hash ID Y.
  • The other diff says starting with X in the merge base, replace that with Z.

These two directives—replace with Y, and replace with Z—conflict with each other. Git does not know which one is correct (if in fact either one is correct).

Your job, in order to resolve this particular merge conflict, is to pick the correct hash ID for the submodule. Once you know the correct hash ID—how you find this is up to you2—you simply temporarily change into the submodule Git repository and run git checkout hash, then return to the superproject and run git add library. Your superproject Git now records the new hash ID in the gitlink that will go into the merge commit, and the merge conflict is resolved.

When you have resolved all merge conflicts—including ordinary file ones, if any—and are ready to commit the merge, run git merge --continue or git commit to finish the merge. The merge commit will have, as its gitlink for library, the hash ID you added.

(If the correct thing is to stop using the submodule entirely, you can git rm library instead of first checking out the correct submodule hash, then git adding the name.)


1This skips some technical details by which it's possible to discover that this submodule repository lives within some superproject. The important thing is that most of Git is blissfully unaware of these details: the submodule thinks it's independent, as it were. Moreover, a typical submodule Git repo is a clone of some other Git repo, and that other Git repo is totally unaware of the clone, so even if the clone—the submodule you're using—were aware that it was a submodule, its origin would still not be aware.

2A typical example method for finding the correct hash ID begins with:

cd library

followed by various git log and/or git show and/or git checkout commands, or maybe gitk --all or whatever you like to use to view a Git repository. Eventually, you spot some hash ID that looks good and run git checkout on it, so as to update the work-tree in this repository, then cd back out of the submodule and build and test the project. This process naturally leaves the submodule on the correct commit, so that you don't have to re-git checkout the right hash ID.

like image 178
torek Avatar answered Sep 30 '22 04:09

torek