Greetings, battle-hardened code warrior! You have survived the introductory enchantments of branching and the clean-commit oath. But the realm of version control runs far deeper than a single git push. Today you face the Grand Merge Ritual โ a trial reserved for those who would command entire release kingdoms, orchestrate fleets of pull requests, and bend the timeline of code to their will.
In this quest you will study real pull requests from an active open-source repository and learn the advanced arts of semantic versioning, branch orchestration, automated changelogs, and CI/CD-driven releases. The spells you forge here are the same ones used by maintainers of the worldโs most critical software.
Long ago, the Great Repository fell into chaos. Features collided, hotfixes overwrote releases, and the changelog โ the sacred chronicle of change โ went blank for months. It took a council of senior engineers, armed with conventional commits, semantic versions, and automated pipelines, to restore order. Their techniques were codified into the Grand Merge Ritual, and now they are yours to learn.
By the time you complete this epic journey, you will have mastered:
Youโll know youโve truly mastered this quest when you can:
git revert or git reset safelygit log, git diff, and git stashgit --versiongh --versionstandard-version tooling)graph TB
subgraph "Prerequisites"
Branches["๐ฑ Branches & PRs<br/>Level 0010"]
Commits["๐ฑ Clean Commits<br/>Level 0010"]
Changelogs["๐ Change Logs<br/>Level 0010"]
end
subgraph "Current Quest"
Main["๐ด Mastering Version<br/>Control Workflows<br/>Level 1100"]
end
subgraph "Unlocked Adventures"
CICD["๐ฐ CI/CD Pipeline<br/>Mastery"]
Maintainer["๐ Open-Source<br/>Maintainer Epic"]
end
Branches --> Main
Commits --> Main
Changelogs -.-> Main
Main --> CICD
Main --> Maintainer
Before touching a single branch, every master architect must understand the language of versions. Semantic Versioning (SemVer) is the universal tongue that tells the world what your changes mean.
MAJOR . MINOR . PATCH
โ โ โ
โ โ โโโ Bug fixes, chores โ backward compatible
โ โโโโโโโโโโโ New features โ backward compatible
โโโโโโโโโโโโโโโโโโโโ Breaking changes โ contracts change
Every conventional commit carries a version destiny:
| Commit Prefix | SemVer Bump | Example | Version Change |
|---|---|---|---|
fix: |
PATCH โ | fix: prevent crash on empty input |
1.0.0 โ 1.0.1 |
chore: |
PATCH โ | chore(deps): upgrade axios |
1.0.0 โ 1.0.1 |
docs: |
PATCH โ | docs: update API examples |
1.0.0 โ 1.0.1 |
feat: |
MINOR โ | feat: add dark mode toggle |
1.0.0 โ 1.1.0 |
BREAKING CHANGE: |
MAJOR โ | Footer in any commit | 1.0.0 โ 2.0.0 |
Letโs examine a real bug fix from the IT-Journey repository:
PR #169 โ
fix(validator): skip required field checks for fields with _config.yml defaults
- Branch:
fix/validator-config-defaultsโmain- What it does: Updates the quest validator to respect Jekyll
_config.ymldefault values, preventing false validation failures- SemVer impact: PATCH bump โ this fixes incorrect behavior without changing the API
# The commit that would trigger this:
fix(validator): skip required field checks for fields with _config.yml defaults
feat(auth): add 2FA login trigger?chore(deps): commit bumps which version component?Not all branches are created equal. A master architect knows which type of branch to summon for every situation โ and more importantly, when to merge them and in what order.
| Branch Type | Naming Convention | Purpose | Merges Into | SemVer Impact |
|---|---|---|---|---|
feature/ |
feat/short-description |
New capabilities | main |
MINOR |
bugfix/ |
fix/short-description |
Non-urgent fixes | main |
PATCH |
hotfix/ |
hotfix/short-description |
Urgent production fixes | main |
PATCH |
refactor/ |
refactor/short-description |
Code reorganization | main |
PATCH (no behavior change) |
release/ |
release/vX.Y.Z |
Prepare versioned release | main |
Tagged release |
automated/ |
automated/workflow-name |
Bot-generated changes | main |
PATCH |
Letโs dissect every open PR in the IT-Journey repo and classify them:
fix/validator-config-defaults โ main
bugfix/ (prefixed fix/)validator โ the quest validation system--config CLI argument, parses _config.yml defaults, skips false-positive errorsfeat/quest-content-updates โ main
feature/feat/contributor-profile-system โ main
feature/refactor/relocate-generation-scripts โ main
refactor/_data/ to scripts/generation/automated/organize-posts-23102108538 โ main
automated/graph LR
subgraph "Independent โ Can merge in any order"
PR169["๐ง #169<br/>fix/validator-config-defaults"]
PR166["๐ #166<br/>refactor/relocate-generation-scripts"]
PR163["๐ค #163<br/>automated/organize-posts"]
end
subgraph "Dependent โ Must merge in order"
PR167["โจ #167<br/>feat/contributor-profile-system"]
PR168["โจ #168<br/>feat/quest-content-updates"]
end
PR167 -->|"must land before"| PR168
style PR169 fill:#90EE90
style PR166 fill:#87CEEB
style PR163 fill:#DDA0DD
style PR167 fill:#FFD700
style PR168 fill:#FFD700
Before creating a branch, ask yourself:
feature/bugfix/ or hotfix/ (if urgent)refactor/automated/release/refactor/ the right prefix?A pull request is not just a code diff โ itโs a communication artifact. The best PRs tell a story: what changed, why it changed, how to verify it, and what it affects downstream.
Letโs study PR #169โs description โ itโs a model of clarity:
## Description
Updates quest_validator.py to respect Jekyll _config.yml default values,
preventing false validation failures for fields that have defaults set
at the collection level.
## Changes Made
- Added --config / -c CLI argument to specify config file path
- Auto-detects _config.yml if not explicitly provided
- Parses defaults section to find collection-scoped default fields
- Handles YAML anchors/aliases via regex fallback parser
- Skips required field errors for fields that have config defaults (e.g., layout)
## Type of Change
- [x] Bug fix (non-breaking change fixing an issue)
## Testing
- 142/142 quests pass validation with -c _config.yml
- No false positives for fields with config-level defaults
| Rune | Purpose | PR #169 Example |
|---|---|---|
| ๐ง Description | What and why in plain language | โPreventing false validation failuresโ |
| ๐ Changes Made | Bullet list of specific modifications | 5 clear, scannable bullets |
| ๐ท๏ธ Type of Change | Checkbox classification | Bug fix checked |
| ๐งช Testing | Proof it works | โ142/142 quests passโ |
| ๐ Dependencies | Other PRs that must merge first | (See PR #168 โ depends on #167) |
Feature PR (like #167):
## Description
Adds a complete contributor profile system with gamified RPG elements
including character sheets, achievement walls, and stats panels.
## Changes Made
- Data layer: _data/contributors/ with YAML profiles and template
- Display components: _includes/contributor/ (character_sheet, stats_panel,
profile_card, achievement_wall)
- Contributor CSS styling
- Contributor directory and individual pages
- GitHub Actions workflow for updating contributor profiles
- Generation scripts and Makefile targets
## Type of Change
- [x] New feature (non-breaking change adding functionality)
Refactor PR (like #166):
## Description
Moves statistics generation scripts from `_data/` to `scripts/generation/`
for better project organization. Scripts don't belong in the data directory.
## Changes Made
- Relocated generate_statistics.rb, generate_statistics.sh,
update_statistics.sh to scripts/generation/
- Updated all path references in Makefile, AGENTS.md, _data/README.md,
scripts/README.md, pages/stats.md, and stating-the-stats quest
- Removed obsolete files
## Type of Change
- [x] Refactoring (no behavior change)
## Testing
- [x] `make test` passes with new paths
- [x] Script syntax checks pass
Youโve just finished a feature that adds dark mode to the site. Write a complete PR description using the five runes above.
Requirements:
The most powerful spell in the version control codex is the release. It transforms a stream of commits into a versioned artifact that the world can depend on.
graph TD
A["๐ง Merge PRs to main"] --> B["๐ Review commit history"]
B --> C{"๐ฎ Determine version bump"}
C -->|"Has feat:"| D["MINOR bump"]
C -->|"Only fix:/chore:"| E["PATCH bump"]
C -->|"Has BREAKING CHANGE:"| F["MAJOR bump"]
D --> G["๐ Generate CHANGELOG"]
E --> G
F --> G
G --> H["๐ท๏ธ Create Git tag"]
H --> I["๐ Create GitHub Release"]
I --> J["๐ข Deploy & announce"]
Imagine all five open PRs have been reviewed and approved. Letโs plan the release:
Step 1: Determine merge order
1. PR #163 (automated/organize-posts) โ independent, safe to merge first
2. PR #166 (refactor/relocate-scripts) โ independent, no behavior change
3. PR #169 (fix/validator-config-defaults) โ independent bug fix
4. PR #167 (feat/contributor-profiles) โ foundation feature, must precede #168
5. PR #168 (feat/quest-content-updates) โ depends on #167
Step 2: Calculate the version bump
Current version: v1.5.0 (hypothetical)
Commits entering main:
- chore: automated post organization โ PATCH
- refactor: relocate generation scripts โ PATCH
- fix: validator config defaults โ PATCH
- feat: contributor profile system โ MINOR โ highest non-breaking
- feat: quest content updates โ MINOR
Highest impact: feat: โ MINOR bump
New version: v1.6.0
Step 3: Generate the changelog
# Changelog
## [1.6.0] - 2026-03-21
### Added
- feat(contributors): add contributor profile system with RPG character sheets (#167)
- feat(quests): add contributor quest line and rewrite bash-run quest (#168)
### Fixed
- fix(validator): skip required field checks for fields with _config.yml defaults (#169)
### Changed
- refactor(scripts): relocate generation scripts from _data/ to scripts/generation/ (#166)
### Maintenance
- chore: weekly post organization and archiving (#163)
standard-version# Install the release automation tool
npm install --save-dev standard-version
# Add release scripts to package.json
# "scripts": {
# "release": "standard-version",
# "release:minor": "standard-version --release-as minor",
# "release:patch": "standard-version --release-as patch",
# "release:major": "standard-version --release-as major"
# }
# Dry run โ see what would happen without committing
npx standard-version --dry-run
# Execute the release
npx standard-version
# Push the tag
git push --follow-tags origin main
# Create a release from the latest tag
gh release create v1.6.0 \
--title "v1.6.0 โ Contributor Profiles & Validation Fixes" \
--notes-file CHANGELOG.md \
--target main
# Or auto-generate release notes from PRs
gh release create v1.6.0 --generate-notes
fix: and docs: commits, what version bump applies?--dry-run do and why should you always use it first?When two branches modify the same lines of code, Git summons you to settle the dispute. Conflict resolution is not a failure โ it is a rite of passage.
Imagine PR #166 (refactor scripts) and PR #169 (fix validator) both modify Makefile references. When you merge one, the other will conflict.
# After merging PR #166, rebase PR #169 onto updated main
git switch fix/validator-config-defaults
git fetch origin main
git rebase origin/main
# Git pauses at the conflict:
# CONFLICT (content): Merge conflict in Makefile
# 1. Open the conflicted file โ look for conflict markers
<<<<<<< HEAD
STATS_SCRIPT = scripts/generation/generate_statistics.sh
=======
STATS_SCRIPT = _data/generate_statistics.sh
>>>>>>> fix/validator-config-defaults
# 2. Choose the correct version (PR #166 already relocated the scripts)
STATS_SCRIPT = scripts/generation/generate_statistics.sh
# 3. Remove ALL conflict markers (<<<, ===, >>>)
# 4. Stage and continue
git add Makefile
git rebase --continue
# 5. Force-push the rebased branch (only YOUR branch, never main!)
git push --force-with-lease origin fix/validator-config-defaults
--force-with-lease โ safer than --force, prevents overwriting othersโ workPractice conflict resolution in a safe sandbox:
# Create a practice repo
mkdir conflict-practice && cd conflict-practice
git init
# Create a base file
echo "line 1: hello" > greetings.txt
echo "line 2: world" >> greetings.txt
git add . && git commit -m "feat: initial greetings"
# Branch A: changes line 2
git switch -c feature/formal-greeting
sed -i '' 's/world/esteemed colleague/' greetings.txt
git add . && git commit -m "feat: formal greeting"
# Branch B: also changes line 2
git switch main
git switch -c feature/casual-greeting
sed -i '' 's/world/friend/' greetings.txt
git add . && git commit -m "feat: casual greeting"
# Merge A into main
git switch main
git merge feature/formal-greeting
# Now try merging B โ CONFLICT!
git merge feature/casual-greeting
# Resolve it, then commit
Success Criteria:
A kingdom without walls falls to invaders. Branch protection rules are the enchanted walls that guard your main branch from chaos.
| Rule | Setting | Why |
|---|---|---|
| Require PR | โ | No direct commits to main |
| Require approvals | 1-2 reviewers | Peer review catches bugs |
| Require status checks | CI must pass | Automated quality gate |
| Require linear history | Optional | Cleaner git log |
| Block force pushes | โ | Protect shared history |
# Using GitHub CLI to configure branch protection
gh api repos/{owner}/{repo}/branches/main/protection \
--method PUT \
--field required_status_checks='{"strict":true,"contexts":["ci/build","ci/test"]}' \
--field enforce_admins=true \
--field required_pull_request_reviews='{"required_approving_review_count":1}'
Every PR in the IT-Journey repo must pass automated checks before merging. For example, PR #169 added validation that proves 142/142 quests pass โ thatโs a status check in action.
# Example: .github/workflows/pr-checks.yml
name: PR Quality Gate
on: [pull_request]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Validate quest frontmatter
run: python3 test/quest-validator/quest_validator.py -d pages/_quests/
- name: Check for broken links
run: python3 scripts/link-checker.py --scope internal
- name: Build Jekyll site
run: |
bundle install
bundle exec jekyll build
main?Simulate the full release workflow using the five open PRs as your model.
Setup: Create a practice repository with five branches mirroring the PR types:
mkdir release-practice && cd release-practice
git init
echo '{"version": "1.5.0"}' > package.json
echo "# My Project" > README.md
git add . && git commit -m "chore: initial commit"
# Create the five branches
git switch -c automated/organize-posts
echo "Posts organized" >> README.md
git add . && git commit -m "chore: weekly post organization"
git switch main
git switch -c refactor/relocate-scripts
mkdir -p scripts/generation
echo "#!/bin/bash" > scripts/generation/generate.sh
git add . && git commit -m "refactor(scripts): relocate generation scripts"
git switch main
git switch -c fix/validator-defaults
echo "validator fixed" >> README.md
git add . && git commit -m "fix(validator): skip checks for config defaults"
git switch main
git switch -c feat/contributor-profiles
echo "profiles system" >> README.md
git add . && git commit -m "feat(contributors): add contributor profile system"
git switch main
git switch -c feat/quest-updates
echo "new quests" >> README.md
git add . && git commit -m "feat(quests): add contributor quest line"
git switch main
The Mission:
feat/contributor-profiles before feat/quest-updatesfeat: present)git tag -a v1.6.0 -m "Release 1.6.0"git log --oneline --graphApply everything youโve learned to the actual IT-Journey repository:
gh repo fork bamr87/it-journeySuccess Criteria:
Semantic Versioning:
feat: โ MINOR, fix: โ PATCH, BREAKING CHANGE: โ MAJORBranch Strategy:
rebase vs mergePR Mastery:
Release Management:
Conflict Resolution:
--force-with-lease instead of --forcestandard-version / release-please โ Automated release managementgh release create โ GitHub Release creation from CLIgit rebase โ Clean branch integrationgit tag -a โ Annotated release tagsGo forth, architect. The branches await your command, the versions await your decree, and the changelog shall record your legend for all time. โ๏ธ