Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Pull Request

## Checklist
- [ ] Target branch is correct (`development` for features, `main` only for releases)
- [ ] For PRs targeting `main`, choose **Rebase and merge** or **Squash and merge**
- [ ] No merge commits are present in this PR
22 changes: 22 additions & 0 deletions .github/workflows/linear-history.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Enforce Linear History

on:
pull_request:
branches:
- main

jobs:
check:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Ensure no merge commits
run: |
git fetch origin main
Comment on lines +16 to +18

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Linear history workflow flags every PR

The workflow checks for merge commits with git rev-list --merges origin/main..HEAD, but on pull_request events actions/checkout leaves HEAD on GitHub’s synthetic refs/pull/<id>/merge commit, which is itself a merge commit. As a result the check fails even when the head branch contains only rebased commits, blocking all releases to main. Consider checking origin/main..origin/${{ github.head_ref }} or checking out github.head_ref to avoid the synthetic merge.

Useful? React with 👍 / 👎.

if [ -n "$(git rev-list --merges origin/main..HEAD)" ]; then
echo "Merge commits detected. Use Rebase/Squash.";
exit 1;
fi
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Changelog

All notable changes to this project will be documented in this file.

## v0.1.0
- release marker
1 change: 1 addition & 0 deletions VERSION
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0.1.0
21 changes: 21 additions & 0 deletions docs/branching.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Branching and Release Workflow

Default branch for this repository is `development`.
All feature branches should open Pull Requests into `development` and be merged using **Squash and merge**.

## Release process
1. Create a Pull Request from `development` to `main`.
2. On GitHub choose **Rebase and merge** or **Squash and merge**. Do **not** use merge commits and do not fast-forward from the CLI.
3. After merging, run `scripts/release/mark-main.sh` on `main` to add a version marker commit.

## Keeping history visible
After a release do **not** reset or fast-forward `development` to `main`.
If `development` needs the latest changes from `main`, merge `main` into `development` so the network graph shows the branching clearly.

## Manual fallback
If automation fails, create the release PR manually via the GitHub UI:
- Base: `main`
- Compare: `development`
- Merge using **Rebase and merge** or **Squash and merge**

This strategy keeps `main` linear and ensures every release is visible in the network graph.
41 changes: 41 additions & 0 deletions scripts/release/mark-main.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/usr/bin/env bash
set -euo pipefail

branch=$(git rev-parse --abbrev-ref HEAD)
if [[ "$branch" != "main" ]]; then
echo "This script must run on main. Current: $branch" >&2
exit 1
fi

bump=""
if [[ "${1:-}" == "--bump" ]]; then
bump="${2:-}"
fi

version=$(cat VERSION)
IFS='.' read -r major minor patch <<<"$version"
case "$bump" in
major)
((major++)); minor=0; patch=0;;
minor)
((minor++)); patch=0;;
patch)
((patch++));;
"")
;;
*)
echo "Unknown bump level: $bump" >&2
exit 1;
;;
esac
new_version="${major}.${minor}.${patch}"
echo "$new_version" > VERSION

{
echo ""
echo "## v$new_version"
echo "- release marker"
} >> CHANGELOG.md

git add VERSION CHANGELOG.md
git commit -m "chore(release): v$new_version (marker)"
22 changes: 22 additions & 0 deletions scripts/release/release-from-dev.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env bash
set -euo pipefail

if [[ -n "$(git status --porcelain)" ]]; then
echo "Working tree is dirty." >&2
exit 1
fi

# Ensure local development branch is up to date
git fetch origin development
git checkout development
git pull origin development

gh pr create --base main --head development --fill

gh pr merge --${MERGE_MODE:-rebase} --admin

git checkout main
git pull origin main
Comment on lines +18 to +19

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Release script never pushes marker commit

After merging development into main, the script runs mark-main.sh which creates a local commit bumping VERSION and CHANGELOG, but the script exits without pushing main back to origin. Every run will therefore leave the release marker only in the local clone and the remote branch stays unchanged, so the release history on GitHub is never updated.

Useful? React with 👍 / 👎.

"$(dirname "$0")/mark-main.sh"

echo "Release complete."
14 changes: 14 additions & 0 deletions scripts/release/setup-repo.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/usr/bin/env bash
set -euo pipefail

# Configure merge options
gh repo edit --allow-merge-commit=false --allow-rebase-merge=true --allow-squash-merge=true

# Enable branch protection with linear history (requires admin token)
read -r owner repo <<<"$(gh repo view --json owner,name -q '.owner.login + " " + .name')"

gh api -X PUT repos/${owner}/${repo}/branches/main/protection --input - <<'JSON'
{
"required_linear_history": true
}
JSON
Loading