First off, I am writing about subtrees without ever knowing the pain of dealing with a submodule. For those of you seeking counseling, I believe there are other blogs for you…I hope you overcome your trauma. A year ago, I was barely learning the ins and outs of Git and how to manage the flow, so the first time the concept of a subtree came in front of me I read about it from a blissful state of ignorance and filed it away in my mind’s might-need-to-know-one-day section.
The day finally came.
I began by working on the subtree without knowing that I was working on a subtree—you know, just writing code and tests and expecting the world to work as usual. So…
How do you identify a subtree in the wild?
You finally know what kind of animal you’re dealing with, but it’s time to set up headquarters and pull out the binoculars. Could there be more than meets the eye? Here are some things to check for that weren’t immediately obvious to me.
The most obvious sign that your project contains a subtree (besides someone telling you months prior, and it slipping your mind…that could happen to some people…) is that you’ll have a file structure that looks like it could make for its own repository within your project. In my case, the big clue was that the subtree was contained in the vendors folder and had its own lib and test folders within the structure.
In some cases, you might have a branch on your main project repo named like the subtree folder, and that branch will have a different root structure than your main project. The Git documentation explains how this might be set up.
It is important to know whether the remote repo is 3rd party or not. If it’s not, your project is more likely to be up-to-date with the most current version of the remote, and your focus might be on pushing your project changes back upstream. If it is 3rd party, you’ll most likely worry more about the repercussions of pulling an update into your project.
How do I manage this thing?
Introducing the subtree flow—intimidating at first, but easily mastered with a few flicks of your whip. I’ll be showing how to use the subtree commands, but many people use the subtree merge strategy. Whether you want to pull a remote version or push upstream, you need to set a few things up locally before you can begin.
Add the remote to be tracked locally:
where sub_project can be whatever your little heart will remember 3 weeks or 3 years from now.
At this point, when you type
git remote you should see something like:
And then to add the subtree to your local project:
where squash suppresses the commits of the subtree’s remote. This practice keeps your repo cleaner, but leave it off if you want to include all those other commits in your project for any reason.
Pulling from the remote
Once you have the remote tracked and added as a subtree locally, you can pull with a single command.
This will merge the remote code with your subtree code. You can customize the code however you please, independent of the subtree’s remote repo, but when you commit the changes and push to your project, your teammates will have access. Yipee!
To push upstream, you add another remote to be tracked, so essentially you are using one remote to pull and another to push:
so now you have these remotes:
And then the command to push looks like this:
Take note that you’ll be pushing to master in this case. If you want to push to a branch before putting in a pull request, replace master with the name of your branch.
There are many blogs out there about git subtrees, and it took me a while to figure out how to work with one already in my project. I hope this blog has helped you out too!