Skip to content

Your first release plan

In this tutorial you will build a small repository, ask colophon what it would release, and watch the answer change as you add commits. Nothing here touches a forge, nothing needs a token, and everything happens in a directory you can delete afterwards.

You will need git and colophon installed. If colophon is not installed yet, see Getting started.

Step 1: make a repository

mkdir colophon-demo && cd colophon-demo
git init -b main
git config user.email [email protected]
git config user.name "Your Name"

Step 2: commit something worth releasing

colophon reads Conventional Commits, so the type at the front of each subject line is what decides the version.

echo "# demo" > README.md
git add -A && git commit -m "feat: the first thing"

echo a > a.txt
git add -A && git commit -m "fix: correct the first thing"

echo b > b.txt
git add -A && git commit -m "docs: explain the first thing"

Three commits: one feature, one fix, and one that documents. Keep an eye on that third one.

Step 3: ask what would be released

colophon plan
0.0.0 → 0.1.0 (minor)
This project has never released; 0.0.0 is where it starts.

Decided by 2 commits:
  96e07a74 minor  feat: the first thing
  7a4bb891 patch  fix: correct the first thing

1 commit moved nothing.

Three things happened here.

The project has never released, so colophon started at 0.0.0 and said so rather than guessing. The feat: commit asked for a minor and the fix: asked for a patch, and the largest of those wins, so the answer is 0.1.0. And the docs: commit moved nothing, which colophon reports as a count rather than silently dropping.

That last line matters more than it looks. A tool that only lists the commits which counted leaves you unable to tell a commit that was correctly ignored from one that was mistyped.

Step 4: release it, then break something

Tag the release yourself for now, so there is a starting point to move from.

git tag v0.1.0

Now add a breaking change. The ! after the type is what marks it.

echo c > c.txt
git add -A && git commit -m "feat!: change the shape of the thing"
colophon plan
0.1.0 → 0.2.0 (minor)

Decided by 1 commit:
  4118ff44 minor  feat: change the shape of the thing

A breaking change, and a minor bump. That is deliberate. Below 1.0.0 a single breaking change would otherwise cut 1.0.0, and declaring a stable API is a decision a person should make on purpose rather than one that falls out of a commit message.

The reasoning is not hidden. Ask for machine-readable output:

colophon plan --output json
    {
      "sha": "4118ff449bfef068ac7274a0bdf23dbcbefec2cb",
      "type": "feat",
      "subject": "change the shape of the thing",
      "bump": "minor",
      "why": "breaking change, held to a minor below 1.0 — promote deliberately with a `Release-As: 1.0.0` trailer"
    }

Step 5: declare 1.0 on purpose

Take the advice the why field just gave you.

git commit --allow-empty -m "chore: promote" -m "Release-As: 1.0.0"
colophon plan
0.1.0 → 1.0.0 (major)

Decided by 1 commit:
  4118ff44 minor  feat: change the shape of the thing

1 commit moved nothing.

Note: version set to 1.0.0 by a Release-As: trailer

The version is now the one you asked for, and colophon says which mechanism overrode the calculation. It does not quietly substitute the answer.

Step 6: hold it back

A version can be right and still be the wrong moment to ship. Commit a .colophon.yaml to say so.

printf 'hold: true\nreason: waiting on the downstream migration\n' > .colophon.yaml
git add -A && git commit -m "chore: hold the release"
colophon plan
0.1.0 → 1.0.0 (major)

HELD — waiting on the downstream migration
The release is computed and shown, but publish will not act on it.

Decided by 1 commit:
  4118ff44 minor  feat: change the shape of the thing

2 commits moved nothing.

Note: version set to 1.0.0 by a Release-As: trailer

The release is still computed and still shown. A hold stops it being published; it does not hide it. A held release you cannot look at is one nobody can decide about.

Tidy up

cd .. && rm -rf colophon-demo

What you learned

  • plan answers "what would be released" and writes nothing, so it is safe anywhere and needs no credentials.
  • The commit type decides the bump, and commits that move nothing are counted rather than dropped.
  • Below 1.0.0, a breaking change is held to a minor, and --output json carries the reason in a why field.
  • Release-As: sets a version explicitly, and colophon reports that it did.
  • .colophon.yaml holds a release back without hiding it.

Next, put it in a pipeline: Run it in GitLab CI.