A
Etienne Deneuve
Mar 10, 2024 · 4 min read

Monorepo with Git - Centralize without compromise

Side view worker wearing gloves

Historical Background

  • Google was one of the pioneers (early 2000s) to adopt this model due to the considerable size of its code base.
  • The widespread adoption of Git (2005) as a distributed version control system played a significant role in the popularity of Monorepos.
  • Facebook’s transition to a Monorepo structure in 2010 drew the attention of other organizations to explore this approach. Since then, tools such as Bazel (created by Google) and Buck (created by Facebook) have emerged to specifically address the challenges posed by Monorepos. In this article, we will focus on the direct approach, using only Git to merge multiple repositories into a single Monorepo while preserving the commits history of each.

Practical Example

In this example, we will use 2 repositories:

  • An empty repository that will serve as our Monorepo under the name ‘monorepo’, initialized with the command
Terminal window
git init
Terminal window
node init -y

and a file app.js with the following content: which displays a message with the current date and time in the console. The goal is to merge repo1 into the Monorepo while preserving the commit history.

1. Clone the Repository

To begin, create a folder (in our case it will be called monorepo-guide-repo1) in which we will have the empty Monorepo and the cloned repo1 with the following command:

Terminal window
git clone https://github.com/meriouliabdallah/monorepo-guide-repo1

You should have the following structure:

2. Add a Reference

It is necessary to add repo1 as a reference from the Monorepo (you should navigate to the folder) with the following command:

Terminal window
git remote add repo1 ../monorepo-guide-repo1

which adds a reference named repo1 from a local repository. It is possible to add a reference from a remote repository by specifying the URL after the name.

3. Fetch the Content of repo1

To retrieve the content of repo1 without merging its changes with the current branch, use the following command:

Terminal window
git fetch

4. Create a Branch

Before merging, it is advisable to create a branch which in our case will be named feat/repo1 with the following command:

Terminal window
git checkout -b feat/repo1

This practice is recommended for several reasons:

  • Isolation of changes
  • Possibility of review and testing before accepting the pull request.
  • Facilitated collaboration.
  • Easy rollback.
  • Clear history.

5. Merge the Content

To merge the content of repo1 into our Monorepo, we will use the command:

Terminal window
git merge <nom du remote/nom de la branche> --allow-unrelated-histories

The —allow-unrelated-histories flag allows merging two branches with different development histories. You will end up with the following content:

Note: If there are conflicts, you should resolve them before being able to merge.

6. Move the Content while Preserving History

To avoid having files from multiple repositories in the root of the Monorepo, it is advisable to create a folder for each repo. In our case, we will do this with the following command:

Terminal window
mkdir repo1

Then move the files to this folder while preserving history, we will use the following command:

Terminal window
git mv README.md app.js package,json repo1

7. Commit the Changes

We will use the tool Goji (developed internally by Omnivya) which allows committing beautiful commits quickly while following best practices. To launch it after installation, it’s very simple:

Terminal window
goji -i

then

Terminal window
goji

and you will have the following interface:

specify that it is a feature, add the scope and the commit message

8. Push the Changes

Once finished, push the changes with the command:

Terminal window
git push

Since the branch is not present in the Monorepo, you will be asked to use the following command:

Terminal window
git push --set-upstream repo1 feat/repo1

A pull request (PR) will be created and after review and acceptance, the content will be merged while preserving the history of each repository.

Conclusion

Through our practical example, we have explored a direct approach using only Git to merge multiple repositories into a single Monorepo while preserving the commit history of each.

Monorepo Git

Related articles