For a general overview of git cliff
see my earlier article on it. This article expands on that focusing just on git cliff’s abilities to address monorepos.
A monorepo is a single code repository that contains multiple “projects” which may each be versioned differently1. This is an older way to develop and it remains popular (mostly for cultural reasons) with those that come from pre-git source control management systems, like svn and cvs.
In order to emulate a mono repo we’ll create a sandbox. This sets up a code repository in the directory “repo” which has three projects “foo”, “bar”, and “baz”. Each of these projects have a fresh change log and are versioned to 1.0.0. But because we’re using a monorepo, the version tags are project specific. For example, there are two separate tags for foo-1.0.0
and bar-1.0.0
. When viewing the repository at “foo-1.0.0” the code in all other non-foo projects should be ignored.
git init repo
cd repo
git-cliff --init
echo "INITIAL COMMIT" >README.md
git add README.md
git commit -a -m 'initial commit'
for PROJ in foo bar baz; do
(
mkdir $PROJ
cd $PROJ
echo "New readme for $PROJ" >README.md
git add README.md
git commit -a -m"Added new project $PROJ"
git tag "$PROJ-1.0.0"
git-cliff --unreleased --bump >CHANGELOG.md
git add CHANGELOG.md
git commit -a -m"chore($PROJ): git-cliff"
git tag $(git cliff --unreleased --tag-pattern="$PROJ-.*" --bumped-version)
)
done
As before, this part is key and will remain unmodified generating the chore commit.
git-cliff --unreleased --bump --prepend CHANGELOG.md
git add CHANGELOG.md
git commit -a -m'chore: git-cliff'
git tag $(git cliff --tag-pattern="$PROJ-*" --bumped-version)
Demonstrating a single fix
To demonstrate a single fix, we can use this code
# Single commit test on foo
PROJ=foo
cd $PROJ
echo Short fix >>README.md
git commit -a -m"fix: single commit $PROJ"
git-cliff --unreleased --bump --prepend CHANGELOG.md
git add CHANGELOG.md
git commit -a -m'chore: git-cliff'
git tag $(git cliff --tag-pattern="$PROJ-*" --bumped-version)
Two commits on the same project?
Here we demonstrate two commits on the same project. This kind of thing will happen often in a PR for example, especially when the source is an integration branch.
PROJ=foo
cd $PROJ
echo One more fix >>README.md
git commit -a -m"feat: [1/2] dual commit/single proj $PROJ"
echo Always another one >>README.md
git commit -a -m"feat: [2/2] dual commit/single proj $PROJ"
git cliff --unreleased --bump --tag-pattern "$PROJ-.*" --prepend CHANGELOG.md
git commit -a -m'chore: git-cliff'
git tag $(git cliff --unreleased --tag-pattern="$PROJ-.*" --bumped-version)
Crossing project boundaries in one chore commit
But what if your integration branch crosses boundaries, not a problem. Here is the code that would handle that.
# Create commit
for PROJ in foo baz; do
(
cd $PROJ
echo "Dual project fix" >>README.md
)
done
git commit -a -m'fix: dual plugin commit'
# Iterate through project updating changelogs
for PROJ in foo baz; do
(
cd $PROJ
git cliff --unreleased --bump --tag-pattern="$PROJ-.*" --prepend CHANGELOG.md
)
done
# Create a chore commit
git commit -a -m'chore: git-cliff'
# Set version tags to that commit
for PROJ in foo baz; do
(
cd $PROJ
git tag $(git cliff --unreleased --tag-pattern="$PROJ-.*" --bumped-version)
)
done
You’ll notice here that this is the complex use case for version management in a monorepo. We have to break our pattern substantially, this is because in one chore commit we want
All the changelogs generated
All bumped versions tagged
This is only meant to demonstrate an overview of the monorepo functionality of git cliff. Git cliff is actively developed. As always, customizations will likely be required and be sure to read the documentation!
If you need neither different versioning nor changelogs for each project just ignore the monorepo functionality.