The Nuclear Squid Musings on stuff and other things.

Subtree merging and you

If you’re using Git, you’re probably aware of submodules. They’re useful when you want to integrate and track another Git repository into your own. But there are two other options at your disposal.

The first one is to simply merge the other repository. This works fine as long as there are no conflicting files, but chances are there already are or will be in the future, which makes this option not too useful.

This is where the subtree merge strategy comes in. It allows you to merge another repository (let’s call it “Project B”) into your own, but into its own subdirectory. It takes a bit of effort to set everything up the first time, but after that a pull from the other repository is all that is needed to update.

Here’s how you set it up. First you need to add Project B as a remote:

$ git remote add -f projectb /path/to/other/repo

(the -f-Flag tells Git to immediately fetch the commits after adding).

Then you prepare the subtree merge:

$ git merge -s ours --no-commit projectb/master

This tells Git to prepare a merge commit, but without actually committing yet. By specifying the ‘ours’ merge strategy, we tell Git that we want the result of the merge to be the current HEAD, no matter what.

Next we actually add Project B into our own repository:

$ git read-tree --prefix=vendor/projectb/ -u projectb/master

read-tree reads the master-tree of the other repository into the index, and stores it under the path given in prefix (in this case the vendor/projectb/). Please note that the path given to the prefix option must end in a slash, and that it must be empty when executing this command. The -u-flag causes read-tree to also update our working copy with the newly added files.

All that is left now is to commit our merge:

$ git commit -m "Merge Project B into vendor/projectb/"

And that’s it. Future updates only require a pull from Project B with the subtree merging strategy specified:

$ git pull -s subtree projectb master

It should be noted that this strategy also has a few drawbacks when compared to using submodules:

  • Anyone who clones your repo will also get the merged repository, wether they want to or not
  • Making and commiting changes to Project B is easier when using submodules

Also, if someone from Project B wants to merge those changes back into their own, it’ll get complicated. It’s not impossible to do, but probably something that requires advanced Git knowledge. In any case, doing so would also connect your projects history to Project B, which might not be desirable.