DEV Community

Cover image for Monorepo: How to keep your history in order
Peter Grainger
Peter Grainger

Posted on • Edited on • Originally published at dev.to

Monorepo: How to keep your history in order

Can you really rely on history to be accurate? History is written by the winners not the losers. I'm a massive fan of the Vikings. I love historical TV series but the more I looked into the actual facts about the time the more I realised much of the series was based around rumours and myths. There is a distinct lack of paper and pens in the fiords of Norway in that time period. Even if they had the equipment, I doubt they would care that much to write down every detail. So who writes the history then? The conquering nations who do care about writing things down, that's who!

Viking

So like those conquers of the past we are going to re-write history--Git history :)

In this post I'll explain how I converted multiple Git repositories into one repository by gluing together two different solutions.

My project

My current setup consisted of multiple repositories with a few characteristics that caused a few headaches in this process:

  • Most of the repositories had 2000+ commits in each
  • Repositories were reliant on each other and had branches with the same name that related to each other, e.g. release-123
  • There were about 20 different repositories
  • The history was important
  • There were lots of branches, most stale.

Reusing Others Hard Work

The first thing I did when approaching this task was to re-use as much from others who have attempted this before.

There are some great tools to convert the structure of your repos from multi to monorepos. I'll discuss tomono and ShopSys. Tomono is simpler but shopsys has fuller features, both didn't really work for me.

Tomono

The tomono script is first. I noticed late on that the history wasn't actually being re-written (by design) and was relies on the built in mechanisms of git merge. I would probably agree with the maintainer that this is a bug in git not the scripts but it doesn't help me right now.

Shopsys

Next to the shopsys tools. These scripts do re-write history but they only merge the master branch. As my setup is weird and I need to merge any branch that has the same name. I can't use these scripts out of the box either.

Creating a Monster

Like Frankenstein my requirements were for something that didn't exist. I've got a good start but need to take the best parts from each script and combine them to create a monster script. I'll warn you now--like Frankenstein's monster this script is not the prettiest or most efficient but it gets the job done.

Frankenstein (1922 book)

It's alive

The magic from the shopsys script comes from the script rewrite-history-into which uses git filter-branch to rewrite the Git history to move everything into a subfolder.

I call the shopsys script from a modified tomono script to re-write the history for each branch. I've shown the interesting parts below:

# tomono.sh
git checkout -q $name/$branch # checkout the remote branch which will be a subfolder
../monorepo-tools/rewrite_history_into.sh $name # re-write the history
git switch -q -c temp-munge-branch # make a temp branch to store the changes
git checkout -q $branch # Go back to the base repo
git reset -q --hard # get rid of any changes
git merge -q --no-commit temp-munge-branch --allow-unrelated-histories # Do the merge!

Now for the downside

This script is painfully slow. It takes hours to run. I'm sure there are optimisations I can make but as I'm only running this once i don't really care.

My script also includes some logic around which branches to move over. You might want to clean up your branches before the move but I'm lazy and just avoided transferring those branches.

Expectation vs Reality

Current scripts are good but can't account for every scenario. If you are in the same scenario as me I hope this helps. There is a high chance you have a slightly different use case so be sure to allow enough time for your transition so you don't rush it and make a mistake!

Found a typo?

If you've found a typo, a sentence that could be improved or anything else that should be updated on this blog post, you can access it through a git repository and make a pull request. Instead of posting a comment, please go directly to https://github.com/peterjgrainger/dev-to-posts/blob/master/blog-posts/monorepo-keeping-your-history-in-order/monorepo-keeping-your-history-in-order.md and open a new pull request with your changes.

Top comments (3)

Collapse
 
matheo profile image
Mateo Tibaquirá

Hi Peter! thanks for this script!
Is it possible to run it per one repo at time? or it takes hours because it needs to move all the repos to the mono at once?
also, if I need only the develop and master branches from the repos, can I move those ones only without the stale ones?
Thank you in advance!

Collapse
 
grsahil20 profile image
Sahil

I think the link you specified in the end linking to github repo is missing repo name in link.

Collapse
 
peterjgrainger profile image
Peter Grainger • Edited

Yep. You're right, updated thanks @grsahil20