Add spork strategy: tooling and documentation
Spork-create mise task sets up a floating-branch soft-fork of a mirrored upstream project with daily mirror-sync via Forgejo Actions. Includes explanation card, how-to guides for setup and branch management, and the spork-create uv script. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
bb60369956
commit
6ecfaf02b6
6 changed files with 675 additions and 0 deletions
84
docs/how-to/configuration/create-a-spork.md
Normal file
84
docs/how-to/configuration/create-a-spork.md
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
---
|
||||
title: Create a Spork
|
||||
modified: 2026-03-28
|
||||
last-reviewed: 2026-03-28
|
||||
tags:
|
||||
- how-to
|
||||
- git
|
||||
- forgejo
|
||||
---
|
||||
|
||||
# Create a Spork
|
||||
|
||||
How to set up a floating-branch soft-fork ("spork") of a mirrored upstream project using `mise run spork-create`.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Mirror already exists at `mirrors/<project>` on forge (see [[manage-forgejo-mirrors]])
|
||||
- 1Password CLI authenticated (`op` CLI)
|
||||
- SSH access to `forge.ops.eblu.me:2222`
|
||||
|
||||
## Create the spork
|
||||
|
||||
```fish
|
||||
mise run spork-create kingfisher
|
||||
```
|
||||
|
||||
This will:
|
||||
|
||||
1. Fork `mirrors/kingfisher` → `eblume/kingfisher` on forge
|
||||
2. Create a `blumeops` branch from upstream's main branch
|
||||
3. Remove any upstream `.forgejo/` directory (if present)
|
||||
4. Add `.forgejo/workflows/mirror-sync.yaml` and commit it
|
||||
5. Set `blumeops` as the default branch
|
||||
6. Clone to `~/code/3rd/kingfisher` with three remotes: `origin`, `mirror`, `upstream`
|
||||
|
||||
Options:
|
||||
|
||||
```fish
|
||||
mise run spork-create kingfisher --dry-run # preview only
|
||||
mise run spork-create kingfisher --no-clone # skip local clone
|
||||
mise run spork-create kingfisher --main-branch dev # override branch name
|
||||
```
|
||||
|
||||
## Verify the setup
|
||||
|
||||
```fish
|
||||
cd ~/code/3rd/kingfisher
|
||||
git remote -v
|
||||
# origin ssh://forgejo@forge.ops.eblu.me:2222/eblume/kingfisher.git (fetch)
|
||||
# mirror ssh://forgejo@forge.ops.eblu.me:2222/mirrors/kingfisher.git (fetch)
|
||||
# upstream https://github.com/mongodb/kingfisher.git (fetch)
|
||||
|
||||
git branch -a
|
||||
# * blumeops
|
||||
# remotes/origin/blumeops
|
||||
# remotes/origin/main
|
||||
```
|
||||
|
||||
## What happens next
|
||||
|
||||
The mirror-sync workflow runs daily at 05:00 UTC and:
|
||||
|
||||
- Fast-forwards `main` from the mirror
|
||||
- Rebases `blumeops` on top of `main`
|
||||
- Rebases any `feature/local/*` and `feature/upstream/*` branches
|
||||
- Rebuilds the `deploy` branch (all features merged)
|
||||
|
||||
See [[manage-spork-branches]] for working with feature branches.
|
||||
|
||||
## Terminology
|
||||
|
||||
| Term | Meaning |
|
||||
|------|---------|
|
||||
| `origin` | Your mutable fork at `eblume/<project>` on forge |
|
||||
| `mirror` | Read-only upstream mirror at `mirrors/<project>` on forge |
|
||||
| `upstream` | Canonical upstream repository (e.g., GitHub) |
|
||||
| `main` | Clean upstream tracking branch (may be named `master`, `dev`, etc.) |
|
||||
| `blumeops` | Default branch — upstream + local workflows/tooling |
|
||||
| `deploy` | Build artifact branch — everything merged, used for deployments |
|
||||
|
||||
## See also
|
||||
|
||||
- [[manage-spork-branches]] — creating feature branches, upstreamable vs local
|
||||
- [[manage-forgejo-mirrors]] — mirror setup and PAT rotation
|
||||
|
|
@ -145,3 +145,5 @@ Trigger a manual sync on one mirror to confirm the new PAT works:
|
|||
|
||||
- [[forgejo]] — Forgejo service reference
|
||||
- [[gandi-operations]] — Similar PAT rotation workflow for Gandi DNS
|
||||
- [[spork-strategy]] — floating-branch soft-fork strategy explanation
|
||||
- [[create-a-spork]] — create a spork on top of a mirror
|
||||
|
|
|
|||
116
docs/how-to/configuration/manage-spork-branches.md
Normal file
116
docs/how-to/configuration/manage-spork-branches.md
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
---
|
||||
title: Manage Spork Branches
|
||||
modified: 2026-03-28
|
||||
last-reviewed: 2026-03-28
|
||||
tags:
|
||||
- how-to
|
||||
- git
|
||||
- forgejo
|
||||
---
|
||||
|
||||
# Manage Spork Branches
|
||||
|
||||
How to create, maintain, and reason about feature branches on a sporked repository. See [[create-a-spork]] for initial setup.
|
||||
|
||||
## Branch types
|
||||
|
||||
### Upstreamable features (`feature/upstream/*`)
|
||||
|
||||
Changes intended to be contributed upstream. Branch off `main` so the diff is clean — no local tooling or workflows mixed in.
|
||||
|
||||
```fish
|
||||
cd ~/code/3rd/kingfisher
|
||||
git fetch origin
|
||||
git checkout -b feature/upstream/forgejo-support origin/main
|
||||
|
||||
# Make changes, commit as normal
|
||||
git push -u origin feature/upstream/forgejo-support
|
||||
```
|
||||
|
||||
The mirror-sync workflow will automatically rebase this branch onto `main` each day.
|
||||
|
||||
To see what the upstream contribution looks like:
|
||||
|
||||
```fish
|
||||
git log main..feature/upstream/forgejo-support --oneline
|
||||
git diff main...feature/upstream/forgejo-support
|
||||
```
|
||||
|
||||
To create a preview PR on forge (targets the mirror, not upstream):
|
||||
|
||||
```fish
|
||||
# From the eblume/<project> repo, PR targeting mirrors/<project>:main
|
||||
# This gives a public URL showing the diff without filing upstream
|
||||
tea pr create --repo mirrors/kingfisher --head eblume/kingfisher:feature/upstream/forgejo-support --base main
|
||||
```
|
||||
|
||||
When ready to contribute upstream, manually translate the branch to a GitHub PR.
|
||||
|
||||
### Non-upstreamable features (`feature/local/*`)
|
||||
|
||||
Local-only changes that will never go upstream. Branch off `blumeops` so you have access to all local tooling.
|
||||
|
||||
```fish
|
||||
cd ~/code/3rd/kingfisher
|
||||
git fetch origin
|
||||
git checkout -b feature/local/custom-rules origin/blumeops
|
||||
|
||||
# Make changes, commit as normal
|
||||
git push -u origin feature/local/custom-rules
|
||||
```
|
||||
|
||||
The mirror-sync workflow will automatically rebase this branch onto `blumeops` each day.
|
||||
|
||||
## The `deploy` branch
|
||||
|
||||
The `deploy` branch is a build artifact — rebuilt fresh by mirror-sync daily. It contains everything merged together: `blumeops` + all `feature/local/*` + all `feature/upstream/*`. Use this branch for deployments (e.g., ArgoCD `targetRevision`).
|
||||
|
||||
**Never commit to or work from `deploy`.**
|
||||
|
||||
## Working with rebasing branches
|
||||
|
||||
Because mirror-sync force-pushes rebased branches daily, local checkouts will diverge. Always pull with rebase:
|
||||
|
||||
```fish
|
||||
git pull --rebase origin feature/upstream/my-change
|
||||
```
|
||||
|
||||
Or set it as default for the repo:
|
||||
|
||||
```fish
|
||||
git config pull.rebase true
|
||||
```
|
||||
|
||||
This is the fundamental trade-off of the spork strategy: small frequent rebases instead of rare catastrophic merges.
|
||||
|
||||
## When rebases fail
|
||||
|
||||
If upstream changes conflict with a feature branch, mirror-sync will skip that branch and log an error. Recovery:
|
||||
|
||||
```fish
|
||||
cd ~/code/3rd/kingfisher
|
||||
git fetch origin
|
||||
git checkout feature/upstream/my-change
|
||||
git rebase origin/main
|
||||
# Resolve conflicts...
|
||||
git push --force-with-lease origin feature/upstream/my-change
|
||||
```
|
||||
|
||||
The next mirror-sync run will pick up the resolved branch and rebuild `deploy`.
|
||||
|
||||
**TODO:** Rebase failures are currently only visible in the Forgejo Actions UI. Alerting via Grafana is planned but not yet implemented.
|
||||
|
||||
## Future: `.spork.toml`
|
||||
|
||||
For repos with multiple feature branches, a `.spork.toml` file on the `blumeops` branch could declare:
|
||||
|
||||
- **Branch dependencies** (stacked branches — `bar` depends on `foo`)
|
||||
- **Feature descriptions** (what the branch is for, in prose)
|
||||
- **Upstream/local classification** (as an alternative to the naming convention)
|
||||
|
||||
This is not yet implemented. For now, the `feature/upstream/*` vs `feature/local/*` naming convention is the source of truth.
|
||||
|
||||
## See also
|
||||
|
||||
- [[create-a-spork]] — initial setup
|
||||
- [[manage-forgejo-mirrors]] — mirror setup and PAT rotation
|
||||
Loading…
Add table
Add a link
Reference in a new issue