I’m involved into several projects, luckily all of them are using Git as VCS for code storage.
When working in a team, it’s very important to pre-define certain rules that everyone will follow to make everything straightforward and expected. This will allow to simplify general workflow and to decrease cognitive load when switching between tasks/branches/projects.
Before going into branch management in some of my projects, I would like to first cover the repository usage for your projects.
Project as a monorepo with single build tool and common dependencies
For those unfamiliar – that’s when you have several libraries/plugins/addons, that are part of a single product, in the same repository.
Example: you are developing various plugins for WooCommerce. That means your repository has a structure like this (and locally you pull it into wp-content/plugins/
directory:
.github/
.gulp/
node_modules/
plugin1-for-woocommerce/
plugin2-for-woocommerce/
vendor/
woocommerce/
query-monitor/
.gitignore
composer.json
gulpfile.js
package.json
As you can see, all plugins share the same build tool (.gulp
directory and associated main gulpfile.js
file), composer
and node_modules
directories. .lock
files should be in the repository as well, I’m just no including them for sanity.
This approach is the most disc space efficient, but requires a very careful and accurate build tool rules and dependencies version management. You will also need to have a unified way to build things (translations, zip files, SCSS->CSS, etc) across all of your plugins inside the repository, and make sure that every one uses certain correct non-conflicting version of dependencies.
If you use Composer autoloading – you will have a terrible headache when you make a distribution zip archive – you don’t want to include in plugin1
dependencies from plugin2
. Of course, this is possible, but you might end with writing lots of custom scripts for composer
and/or npm
.
Project as a monorepo with multiple build tools and independent dependencies
That’s basically the same as above, with a small but very important difference in directory structure and the way build tools (gulp
in my example) are used.
.github/
plugin1-for-woocommerce/
├── .gulp/
├── node_modules/
├── vendor/
├── composer.json
├── gulpfile.js
└── package.json
plugin2-for-woocommerce/
├── .gulp/
├── node_modules/
├── vendor/
├── composer.json
├── gulpfile.js
└── package.json
woocommerce/
query-monitor/
.gitignore
Each plugin has its own copy of build tools, composer
and node_modules
directories.
This approach:
- simplifies building and managing dependencies for each plugin – as they are independent;
- is very good, when you have a core plugin,
say plugin1
, and all others: plugin2
, plugin3
etc – depend on it (aka addons). So quite often you need to make a big change in a core plugin, and all “addons” will require a minor change in behavior (like filter usage).
For both of these monorepo approaches:
- you make only 1 commit when you modify something similar (or the same) for both plugins: adding a footer link in the admin area of a plugin, for example;
- you can automate
running composer install
and npm install
for each of the plugins by using a Git hookpost-checkout
– so developer initially runs a singlecommand git clone
and everything is set up after its done.
Product with several repositories (projects)
You take each custom pluginN-for-woocommerce
directory from above and put it into own repository. That will mean that when you make changes in admin area of your plugins (like the new footer link) – you end up with multiple commits to each repository.
This approach is also more complex at the beginning, because every developer (or when you change your working machine: home/office, Mac/Windows etc) will need to:
- request access to each of the separate repositories;
pull
them one by one into specific places;run composer install
and npm install
for each of them.
So several repositories provide more granular access control (which needs to be managed), complicates initial development, requires lots of similar commits across your various repositories, might duplicate common build steps.
What to select?
There is no an easy answer. You select the road to take depending on your vision and your project.
I think that highly coupled projects might benefit from being in a single repository (aka monorepo), but with own dependencies. You can always make a mix of those 2 monorepo examples:
- the single build tool (like a top-level
.gulp
directory and a singlegulpfile.js
) and a special top levelpackage.json
just for building (of course if you areusing node
, because you can have a Robo too); - each plugin has its own
composer.json
AND evenpackage.json
(which just won’t havegulp
and everything related to actually building it).
But if all of your plugins are totally separate and do not relate to each other – let them be in separate repositories. In case something is in common, like an admin area handling (basic skeleton) – you can make it a library, release via the Pcomposer require
Featured image by Sear Greyson.