Simpler Deploys with git Subtrees: A Retrospective

Article summary

Back in March I posted about “using git subtrees to simplify deploys”:https:/deploy-git-subtrees/. I was initially hoping to clean things up a bit by using subtrees. I wanted to reduce the size of my deploy and my Heroku slug by excluding source assets. I also wanted to make sure that it was easy to understand and that other developers didn’t have to worry about extra steps when cloning the repo or when deploying. Submodules force some extra steps when cloning, pulling, and pushing, so they weren’t my first choice.

Using subtrees like this did work fairly well, but I would think twice before using them again for this type of problem.

What Went Well

It did do what we wanted. Just as my initial investigation showed submodules always came down when cloning the repo without a problem, so when I transitioned to another developer all the pieces were there. There wasn’t any need to fiddle with other commands to pull down submodules, or any other extra scripts to run.

It worked for deploys. I was able to set up remotes correctly so I could push just the subtree to Heroku to deploy. I also got good separation between the repositories: the Heroku repo only contained the minimum it needed with no uncompiled assets, documentation, or any other extraneous pieces.

What Didn’t

It’s still just not a standard approach. That’s not that big of a deal, but it does substantially reduce its benefit because any new developers still need to be introduced to subtrees. If we’d gone with submodules, it’d have the other downsides but likely been a feature a new dev would be familiar with. Similarly, a build script that just copied the build into a “deploy” repo would have been conceptually simple.

The biggest disappointment is that the act of pushing the subtree to a remote is O(n) with n being the number of commits. Even with the --squash parameter, each time you push takes longer than the previous (I believe the --squash is there to squash the history during the initial clone of the subtree, not squash subsequent changes). That can be worked around by removing and re-adding the subtree, but at that point your workaround is costing you more than just choosing a different approach in the first place.

The downsides aren’t huge, but adding them all together the complexity just doesn’t seem to buy enough to be a good solution for this approach.