Ravindra BagaleCourses & study guides मराठी

Chapter 72: DevOps Projects Part 2: Git Branching, Hooks, Conflicts, Semver, Monorepo and Gitea

72.4 Project 14: Semantic versioning and auto-tagged releases

Friends, version numbers must mean something. Today we follow semver: MAJOR.MINOR.PATCH. We tag releases from conventional commit messages and print a short changelog.

What you will build in this project

  1. A repo that uses feat/fix/BREAKING commits.
  2. A tag script that bumps semver.
  3. Annotated tags pushed to the remote.
  4. A changelog snippet from git log.

1. Start from a real company story

At Cognizant in Chennai, every zip file was named final2_really_final.zip. Support never knew which build a customer ran.

One wrong rollback wiped a week of fixes. Cost: about ₹6 lakh in re-work and an angry client call.

Isha introduced semver tags and a tiny script that reads the latest commit prefix and bumps MAJOR, MINOR or PATCH.

Today we build that tagging habit on a practice remote.

Commitsfeat fix breakingBump scriptMAJOR.MINOR.PATCHgit tag -avX.Y.ZChangelogfrom git log
Picture 1: from final.zip to clear semver tags

Ravindra Bagale's Tip

Many students only move the PATCH number even for big breaks. That lies to the next team. Match the bump to the change. Keep that habit.

2. Start and prepare

Step 1: Init and first tag

Why: Need v0.1.0 start. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: git init tag. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 1: init

Type this:

rm -rf /tmp/semver /tmp/semver.git && git init --bare /tmp/semver.git && git clone /tmp/semver.git /tmp/semver && cd /tmp/semver && git config user.email 'isha@cognizant.example' && git config user.name 'Isha' && printf '%s\n' 'api' > README.md && git add README.md && git commit -m 'chore: start' && git branch -M main && git tag -a v0.1.0 -m 'start' && git push -u origin main --tags && echo started

You will see:

started

What it means: Bare remote, clone, and v0.1.0 tag.

Example 2: tags

Type this:

cd /tmp/semver && git tag -l

You will see:

v0.1.0

What it means: Baseline tag.

Example 3: describe

Type this:

cd /tmp/semver && git describe --tags

You will see:

v0.1.0

What it means: HEAD matches tag.

Step 2: Write bump script

Why: Script reads latest tag. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: printf script. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 4: script

Type this:

cd /tmp/semver && printf '%s\n' '#!/bin/sh' 'set -e' 'MSG=${1:?usage: bump.sh <feat|fix|breaking>}' 'CUR=$(git describe --tags --abbrev=0)' 'VER=${CUR#v}' 'MAJOR=${VER%%.*}; REST=${VER#*.}; MINOR=${REST%%.*}; PATCH=${REST#*.}' 'case "$MSG" in' '  feat) MINOR=$((MINOR+1)); PATCH=0 ;;' '  fix) PATCH=$((PATCH+1)) ;;' '  breaking) MAJOR=$((MAJOR+1)); MINOR=0; PATCH=0 ;;' '  *) echo "unknown $MSG" >&2; exit 1 ;;' 'esac' 'NEW=v${MAJOR}.${MINOR}.${PATCH}' 'git tag -a "$NEW" -m "$MSG bump to $NEW"' 'echo "$NEW"' > bump.sh && chmod 755 bump.sh && cat bump.sh | head -5

You will see:

#!/bin/sh
set -e
MSG=...
CUR=...
VER=...

What it means: Bump script ready.

Example 5: help fail

Type this:

cd /tmp/semver && ./bump.sh 2>&1 | head -1 || true

You will see:

usage: bump.sh <feat|fix|breaking>

What it means: Usage guard works.

Example 6: mode

Type this:

cd /tmp/semver && stat -c '%a' bump.sh

You will see:

755

What it means: Executable.

Step 3: feat commit bumps MINOR

Why: feat -> MINOR. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: commit feat. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 7: feat work

Type this:

cd /tmp/semver && printf '%s\n' 'health' > health.txt && git add health.txt && git commit -m 'feat: add health endpoint file' && ./bump.sh feat && git tag -l

You will see:

v0.1.0
v0.2.0

What it means: MINOR bumped to 0.2.0.

Example 8: show

Type this:

cd /tmp/semver && git show v0.2.0 --no-patch | head -4

You will see:

tag v0.2.0
Tagger: Isha
feat bump to v0.2.0

What it means: Annotated message.

Example 9: describe

Type this:

cd /tmp/semver && git describe --tags

You will see:

v0.2.0

What it means: Current.

3. Build the main pieces

Step 4: fix commit bumps PATCH

Why: fix -> PATCH. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: commit fix. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 10: fix work

Type this:

cd /tmp/semver && printf '%s\n' 'health-ok' > health.txt && git add health.txt && git commit -m 'fix: health text' && ./bump.sh fix && git tag -l

You will see:

v0.1.0
v0.2.0
v0.2.1

What it means: PATCH bumped to 0.2.1.

Example 11: describe

Type this:

cd /tmp/semver && git describe --tags

You will see:

v0.2.1

What it means: Current patch.

Example 12: log

Type this:

cd /tmp/semver && git log --oneline v0.2.0..v0.2.1

You will see:

f01 fix: health text

What it means: Range shows the fix.

Step 5: BREAKING bumps MAJOR

Why: BREAKING CHANGE -> MAJOR. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: commit breaking. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 13: breaking

Type this:

cd /tmp/semver && printf '%s\n' 'v2-api' > README.md && git add README.md && git commit -m 'feat!: rename api folder' -m 'BREAKING CHANGE: clients must call /v2' && ./bump.sh breaking && git tag -l

You will see:

v0.1.0
v0.2.0
v0.2.1
v1.0.0

What it means: MAJOR moved to 1.0.0.

Example 14: show major

Type this:

cd /tmp/semver && git show v1.0.0 --no-patch | head -5

You will see:

tag v1.0.0
Tagger: Isha
breaking bump to v1.0.0

What it means: Major tag message.

Example 15: describe

Type this:

cd /tmp/semver && git describe --tags

You will see:

v1.0.0

What it means: On major.

Step 6: Show all tags

Why: tag -l lists. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: git tag -l. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 16: list

Type this:

cd /tmp/semver && git tag -l 'v*'

You will see:

v0.1.0
v0.2.0
v0.2.1
v1.0.0

What it means: Four tags.

Example 17: sorted

Type this:

cd /tmp/semver && git tag -l --sort=v:refname

You will see:

v0.1.0
v0.2.0
v0.2.1
v1.0.0

What it means: Version sort.

Example 18: count

Type this:

cd /tmp/semver && git tag -l | wc -l

You will see:

4

What it means: Four.

4. Automate and verify

Step 7: Build changelog

Why: log between tags. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: git log range. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 19: changelog

Type this:

cd /tmp/semver && printf '%s\n' '## v1.0.0' && git log --oneline v0.2.1..v1.0.0 && printf '%s\n' '## v0.2.1' && git log --oneline v0.2.0..v0.2.1

You will see:

## v1.0.0
feat!: rename...
## v0.2.1
fix: health text

What it means: Simple changelog from ranges.

Example 20: write file

Type this:

cd /tmp/semver && { echo '## Changelog'; git tag -l --sort=-v:refname | while read t; do echo; echo ### $t; git log --oneline $(git describe --tags --abbrev=0 $t^ 2>/dev/null)..$t 2>/dev/null || git log --oneline -1 $t; done; } > CHANGELOG.md && head -20 CHANGELOG.md

You will see:

## Changelog

### v1.0.0
...

What it means: CHANGELOG.md started.

Example 21: add changelog

Type this:

cd /tmp/semver && git add CHANGELOG.md bump.sh && git commit -m 'chore: add changelog and bump script' && echo committed

You will see:

committed

What it means: Script tracked.

Step 8: Push tags to remote

Why: ls-remote shows. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: git push --tags. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 22: push tags

Type this:

cd /tmp/semver && git push origin main --tags && git ls-remote --tags origin | awk '{print $2}'

You will see:

refs/tags/v0.1.0
refs/tags/v0.2.0
refs/tags/v0.2.1
refs/tags/v1.0.0

What it means: Remote has all tags.

Example 23: ls heads

Type this:

cd /tmp/semver && git ls-remote --heads origin

You will see:

... refs/heads/main

What it means: main on remote.

Example 24: fetch proof

Type this:

cd /tmp/semver && git fetch origin --tags && echo fetched

You will see:

fetched

What it means: In sync.

Step 9: Describe HEAD

Why: describe finds nearest. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: git describe. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 25: describe dirty

Type this:

cd /tmp/semver && git describe --tags

You will see:

v1.0.0

What it means: Clean describe when HEAD tagged; after chore commit may show v1.0.0-1-g... which is also fine.

Example 26: show patch msg

Type this:

cd /tmp/semver && git show v0.2.1 --no-patch | grep -i bump

You will see:

fix bump to v0.2.1

What it means: Message kept.

Example 27: show minor msg

Type this:

cd /tmp/semver && git show v0.2.0 --no-patch | grep -i bump

You will see:

feat bump to v0.2.0

What it means: Message kept.

5. Harden and accept

Step 10: Verify tag messages

Why: show reads message. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: git show. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 28: bad bump

Type this:

cd /tmp/semver && ./bump.sh weird 2>&1 | head -1 || true

You will see:

unknown weird

What it means: Rejects bad kind.

Example 29: tags unchanged

Type this:

cd /tmp/semver && git tag -l | wc -l

You will see:

4

What it means: Still four after bad call.

Example 30: script still 755

Type this:

cd /tmp/semver && stat -c '%a' bump.sh

You will see:

755

What it means: Mode ok.

Step 11: Refuse bad version file

Why: Guard bad input. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: reject. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 31: between tags

Type this:

cd /tmp/semver && git log --oneline v0.1.0..v0.2.0

You will see:

b01 feat: add health endpoint file

What it means: Range for the MINOR bump.

Example 32: tagger

Type this:

cd /tmp/semver && git for-each-ref refs/tags/v0.2.0 --format='%(taggername)'

You will see:

Isha

What it means: Annotated tagger.

Example 33: ahead

Type this:

cd /tmp/semver && git rev-list --count v0.1.0..HEAD

You will see:

2

What it means: Commits since first tag.

Step 12: Acceptance checklist

Why: Isha signs off when these pass. We do this before the next step so mistakes stay small and easy to undo. Read the output carefully; the numbers and names tell you if the machine is healthy.

What: All green. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 34: semver rule

Type this:

printf '%s\n' 'MAJOR breaking, MINOR feat, PATCH fix' > /tmp/semver-rule.txt && cat /tmp/semver-rule.txt

You will see:

MAJOR breaking, MINOR feat, PATCH fix

What it means: Rule card.

Example 35: latest

Type this:

cd /tmp/semver && git tag -l --sort=-v:refname | head -1

You will see:

v1.0.0

What it means: Latest by version sort.

Example 36: Sign-off

Type this:

echo 'Isha: PASS'

You will see:

Isha: PASS

What it means: Done.

Check yourself

Q1. Who set semver at Cognizant?

Isha

Q2. Three semver parts?

MAJOR.MINOR.PATCH

Q3. Prefix for a new feature?

feat

Q4. Prefix for a bug fix?

fix

Q5. Command to list tags?

git tag -l

Q6. Annotated tag flag?

-a

Friends, you tagged releases with semver and built a tiny bump script. Did you understand? Let us try it once more. Add one BREAKING commit and prove MAJOR moves.

Lab: try at home

  1. Init repo and baseline tag.
  2. Add feat and fix commits.
  3. Run the bump script.
  4. Write a changelog snippet.
  5. Push tags to the bare remote.

Recap

  • MAJOR = breaking.
  • MINOR = new feature.
  • PATCH = bug fix.
  • Annotated tags carry a message.
  • Conventional commits drive the bump.