Skip to content

Commit 36c7f20

Browse files
committed
git submodule merges, remove subtree
1 parent 2f626bd commit 36c7f20

File tree

1 file changed

+133
-8
lines changed

1 file changed

+133
-8
lines changed

book/07-git-tools/sections/submodules.asc

Lines changed: 133 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,138 @@ To https://github.com/chaconinc/MainProject
511511

512512
As you can see there, Git went into the DbConnector module and pushed it before pushing the main project. If that submodule push fails for some reason, the main project push will also fail.
513513

514-
With these tools, submodules can be a fairly simple and effective method for developing on several related but still separate projects simultaneously.
514+
===== Merging Submodule Changes
515+
516+
If you change a submodule reference at the same time as someone else, you may run into some problems. That is, if the submodule histories have diverged and are committed to diverging branches in a superproject, it may take a bit of work for you to fix.
517+
518+
If one of the commits is a direct ancestor of the other (a fast-forward merge), then Git will simply choose the latter for the merge, so that works fine.
519+
520+
Git will not attempt even a trivial merge for you, however. If the submodule commits diverge and need to be merged, you will get something that looks like this:
521+
522+
[source,shell]
523+
----
524+
$ git pull
525+
remote: Counting objects: 2, done.
526+
remote: Compressing objects: 100% (1/1), done.
527+
remote: Total 2 (delta 1), reused 2 (delta 1)
528+
Unpacking objects: 100% (2/2), done.
529+
From https://github.com/chaconinc/MainProject
530+
9a377d1..eb974f8 master -> origin/master
531+
Fetching submodule DbConnector
532+
warning: Failed to merge submodule DbConnector (merge following commits not found)
533+
Auto-merging DbConnector
534+
CONFLICT (submodule): Merge conflict in DbConnector
535+
Automatic merge failed; fix conflicts and then commit the result.
536+
----
537+
538+
So basically what has happened here is that Git has figured out that the two branches record points in the submodule's history that are divergent and need to be merged. It explains it as ``merge following commits not found'', which is confusing but we'll explain why that is in a bit.
539+
540+
To solve the problem, you need to figure out what state the submodule should be in. Strangely, Git doesn't really give you much information to help out here, not even the SHAs of the commits of both sides of the history. Fortunately, it's simple to figure out. If you run `git diff` you can get the SHAs of the commits recorded in both branches you were trying to merge.
541+
542+
[source,shell]
543+
----
544+
$ git diff
545+
diff --cc DbConnector
546+
index eb41d76,c771610..0000000
547+
--- a/DbConnector
548+
+++ b/DbConnector
549+
----
550+
551+
So, in this case, `eb41d76` is the commit in our submodule that *we* had and `c771610` is the commit that upstream had. If we go into our submodule directory, it should already be on `eb41d76` as the merge would not have touched it. If for whatever reason it's not, you can simply create and checkout a branch pointing to it.
552+
553+
What is important is the SHA of the commit from the other side. This is what you'll have to merge in and resolve. You can either just try the merge with the SHA directly, or you can create a branch for it and then try to merge that in. We would suggest the latter, even if only to make a nicer merge commit message.
554+
555+
So, we will go into our submodule directory, create a branch based on that second SHA from `git diff` and manually merge.
556+
557+
[source,shell]
558+
----
559+
$ cd DbConnector
560+
561+
$ git rev-parse HEAD
562+
eb41d764bccf88be77aced643c13a7fa86714135
563+
564+
$ git branch try-merge c771610
565+
(DbConnector) $ git merge try-merge
566+
Auto-merging src/main.c
567+
CONFLICT (content): Merge conflict in src/main.c
568+
Recorded preimage for 'src/main.c'
569+
Automatic merge failed; fix conflicts and then commit the result.
570+
----
571+
572+
We got an actual merge conflict here, so if we resolve that and commit it, then we can simply update the main project with the result.
573+
574+
[source,shell]
575+
----
576+
$ vim src/main.c <1>
577+
$ git add src/main.c
578+
$ git commit -am 'merged our changes'
579+
Recorded resolution for 'src/main.c'.
580+
[master 9fd905e] merged our changes
581+
582+
$ cd .. <2>
583+
$ git diff <3>
584+
diff --cc DbConnector
585+
index eb41d76,c771610..0000000
586+
--- a/DbConnector
587+
+++ b/DbConnector
588+
@@@ -1,1 -1,1 +1,1 @@@
589+
- Subproject commit eb41d764bccf88be77aced643c13a7fa86714135
590+
-Subproject commit c77161012afbbe1f58b5053316ead08f4b7e6d1d
591+
++Subproject commit 9fd905e5d7f45a0d4cbc43d1ee550f16a30e825a
592+
$ git add DbConnector <4>
593+
594+
$ git commit -m "Merge Tom's Changes" <5>
595+
[master 10d2c60] Merge Tom's Changes
596+
----
597+
598+
<1> First we resolve the conflict
599+
<2> Then we go back to the main project directory
600+
<3> We can check the SHAs again
601+
<4> Resolve the conflicted submodule entry
602+
<5> Commit our merge
603+
604+
It can be a bit confusing, but it's really not very hard.
605+
606+
Interestingly, there is another case that Git handles.
607+
If a merge commit exists in the submodule directory that contains **both** commits in it's history, Git will suggest it to you as a possible solution. It sees that at some point in the submodule project, someone merged branches containing these two commits, so maybe you'll want that one.
608+
609+
This is why the error message from before was ``merge following commits not found'', because it could not do *this*. It's confusing because who would expect it to **try** to do this?
610+
611+
If it does find a single acceptable merge commit, you'll see something like this:
612+
613+
[source,shell]
614+
----
615+
$ git merge origin/master
616+
warning: Failed to merge submodule DbConnector (not fast-forward)
617+
Found a possible merge resolution for the submodule:
618+
9fd905e5d7f45a0d4cbc43d1ee550f16a30e825a: > merged our changes
619+
If this is correct simply add it to the index for example
620+
by using:
621+
622+
git update-index --cacheinfo 160000 9fd905e5d7f45a0d4cbc43d1ee550f16a30e825a "DbConnector"
623+
624+
which will accept this suggestion.
625+
Auto-merging DbConnector
626+
CONFLICT (submodule): Merge conflict in DbConnector
627+
Automatic merge failed; fix conflicts and then commit the result.
628+
----
629+
630+
What it's suggesting that you do is to update the index like you had run `git add`, which clears the conflict, then commit. You probably shouldn't do this though. You can just as easily go into the submodule directory, see what the difference is, fast-forward to this commit, test it properly, and then commit it.
631+
632+
[source,shell]
633+
----
634+
$ cd DbConnector/
635+
$ git merge 9fd905e
636+
Updating eb41d76..9fd905e
637+
Fast-forward
638+
639+
$ cd ..
640+
$ git add DbConnector
641+
$ git commit -am 'Fast forwarded to a common submodule child'
642+
----
643+
644+
This accomplishes the same thing, but at least this way you can verify that it works and you have the code in your submodule directory when you're done.
645+
515646

516647
==== Submodule Tips
517648

@@ -710,10 +841,4 @@ Then, when you switch back, you get an empty `CryptoLibrary` directory for some
710841

711842
It's important to note that submodules these days keep all their Git data in the top project's `.git` directory, so unlike much older versions of Git, destorying a submodule directory won't lose any commits or branches that you had.
712843

713-
714-
715-
==== Alternatives to Submodules
716-
717-
===== Subtree
718-
719-
git-subtree
844+
With these tools, submodules can be a fairly simple and effective method for developing on several related but still separate projects simultaneously.

0 commit comments

Comments
 (0)