Git Workflow¶
This page is the single source of truth for how git is actually used in this
repository: which branch to work from, what CI checks run and why, how to
open a PR, and how to get out of the two situations that come up most —
merge conflicts and a failed core-guard check.
If you only read one section, read The Golden Rule
(core/ is off-limits) and step 5, Push and open the PR.
Branch model¶
STRP ●───●───●───●───●───●───●───●───● ← active development (trunk)
\ \
main ──────●───────────────● ← periodic release snapshots
| Branch | Role | Who commits here |
|---|---|---|
STRP |
The active trunk. All feature/fix branches are cut from STRP, and all PRs target STRP. CI (tests + core-guard) runs on every push and PR to main, master, or STRP. |
Everyone, via PR |
main |
A periodic release snapshot, updated by merging STRP in when a maintainer decides a checkpoint is ready. It lags STRP between releases — that's expected, not a bug. |
Maintainers only, via merge from STRP |
Practical takeaway: branch from STRP, and open your PR against STRP.
Don't branch from or target main — it won't have the latest plugins,
CI config, or fixes, and your PR will likely show a conflict-ridden diff
against stale code.
Branches you can ignore¶
If you run git branch -a you'll see a few branches that aren't part of the
active workflow:
legacy-ppage— a pre-rewrite history snapshot, kept for history.revert-55-feat/a2c-integration— a revert branch left on the remote.
None of these are meant to be branched from or merged into. They're archival.
Setup¶
git clone https://github.com/UHUMALAB/PPAGE.git
cd PPAGE
git checkout STRP
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\Activate.ps1
pip install -e ".[dev,baselines]"
pip install -e .makesppage(includingppage.baselines) importable without settingPYTHONPATH(see the Quickstart), so the commands below can be run as-is from the repository root.
Making a change¶
1. Branch from STRP¶
Use fix/... for bug fixes, feat/... for new functionality. Keep the
branch scoped to one change — small, reviewable PRs merge faster.
2. The Golden Rule: core/ is off-limits¶
You may not modify
src/ppage/core/(gridworld.py,agent.py). Extend the system throughobservations/,rewards/,actions/,wrappers/, andregistry/instead.
This isn't just a guideline — it's enforced automatically. The core-guard
CI job diffs the PR's base against its head (whatever the base is) and fails the check if any file under
core/ changed, regardless of how small the change looks. See
contributing guide for the full rationale and the layered
architecture this protects.
If you find yourself needing to touch core/, that's a signal to open an
issue and discuss it with a maintainer first — don't route around the
registries to avoid the check.
3. Before you push: run what CI runs¶
Run the exact same checks CI will run, locally, before pushing:
If black --check fails, just run black . (no --check) to auto-fix
formatting, then re-stage.
4. Commit¶
There's no strictly enforced commit message format, but the convention that's actually followed in this repo's history is:
Common types seen in git log: fix:, feat:/feature:, docs:,
refactor:, chore:. When a type doesn't add clarity, a plain imperative
summary (Add pytest job to CI) is fine too. Prefer a few focused commits
over one giant one, but don't over-fragment either.
5. Push and open the PR¶
Open the PR against STRP. GitHub defaults the PR base to the
repository default branch, which is main, so you must change the base
to STRP on every PR before submitting.
What CI actually checks¶
Defined in .github/workflows/ci.yaml,
triggered on every push and PR to main, master, or STRP:
| Job | Runs on | What it does |
|---|---|---|
lint |
currently disabled (commented out in ci.yaml) |
black --check ., flake8 ., pylint src. Fails on any formatting or lint violation. core/ and miscellenous/ are excluded from linting by design (see comments in .flake8 / .pylintrc). |
test |
push + PR (Python 3.10/3.11/3.12) | pytest tests/ -q — the full test suite (registries, plugin contracts, end-to-end training, architecture rules). |
core-guard |
PR only | Diffs the PR's base and head SHAs; fails if any file under src/ppage/core/ was touched. Never runs on plain pushes (there's no "PR diff" to check). |
Both test and core-guard must pass before merging. There is currently no branch protection
rule enforcing this at the GitHub level — reviewers should confirm the
checks are green before approving.
Handling merge conflicts¶
The most common source of conflicts in this repo isn't competing logic — it's Black reformatting touching the same lines as your change. If you get a conflict:
- Read both sides. If one side is purely whitespace/line-wrapping and the other has your actual logic change, keep the logic side and discard the formatting-only side.
- After resolving, run
black .on the resolved file(s) — the manual resolution often isn't Black-formatted itself. - Re-run the full check list from step 3 above before pushing the resolution.
To sync your branch with the latest STRP mid-PR:
git fetch origin
git merge origin/STRP # or: git rebase origin/STRP
# resolve conflicts, then:
black .
python -m pytest tests/ -q
git push
If your PR lives on someone else's fork and you're not that contributor, resolving and pushing the fix on their behalf requires their awareness first — even with "allow edits by maintainers" enabled, it's their branch. Comment on the PR explaining the conflict and what needs to change instead of pushing to it unannounced.
Merging¶
GitHub's squash, merge-commit, and rebase-merge options are all enabled on
this repo — there's no server-side restriction to one method, and history
so far is a mix of both squash and merge commits. Squash is the better
default for a small, single-purpose PR (one clean commit on STRP); use a
merge commit if the PR's individual commits are independently meaningful
and worth preserving. Branches are not auto-deleted on merge — delete
yours manually after merging (git push origin --delete fix/short-desc,
or the "Delete branch" button on the merged PR page).
Quick reference¶
# One-time setup
git clone https://github.com/UHUMALAB/PPAGE.git
cd PPAGE
pip install -e ".[dev,baselines]"
# Start work
git checkout STRP && git pull origin STRP
git checkout -b fix/my-fix
# ... make changes ...
# Verify before pushing
black --check . && flake8 . && pylint src && python -m pytest tests/ -q
git add <files>
git commit -m "fix: short description"
git push -u origin fix/my-fix
# open PR against STRP