Copy template repositories from a source GitHub organization into a semester (or other) target organization, keeping only the main branch so students never receive a solution (or any other) branch.
History on main is preserved, so you can re-run the script later to sync updates from source → target.
After templates sync, the script overlays Classroom50 seed config from SOURCE/classroom50 into a live TARGET/classroom50 (created with gh teacher init when missing).
-
GitHub CLI (
gh) -
git -
jq -
Classroom50 teacher CLI:
gh extension install foundation50/gh-teacher -
Authenticated
ghas an account that can read the source org and create/push repos in the target org:gh auth login -h github.com gh auth status -h github.com
You must be a member of the target org with permission to create repositories (typically an owner). Being able to view the org on github.com is not enough.
If create fails with CreateRepository / viewerCanCreateRepositories=false:
- Confirm you are logged in as the account that owns the org:
gh auth status -h github.com - Open https://github.com/ORG and accept any pending invitation
- Or have an owner add you and enable member repo creation under Organization settings → Member privileges
When the target does not yet have a live classroom50 repo, set a fine-grained PAT and run the sync:
export CLASSROOM50_SERVICE_TOKEN=github_pat_...
./sync-templates.sh --source IT3038C --target YOUR-SEMESTER-ORGToken requirements (resource owner = target org, all repositories): Contents R/W, Actions R/W, Administration R/W, Organization Members: Read. See the Classroom50 GitHub Integration wiki.
Do not run gh teacher init on IT3038C — that org keeps a hand-authored seed at IT3038C/classroom50, not a live Classroom50 install.
./sync-templates.sh --source IT3038C --target IT3038C-Reed-FA26
./sync-templates.sh --source IT3038C --target IT3038C-Reed-FA26 \
--target-classroom it3038c-001-fa26
./sync-templates.sh --source IT3038C --target IT3038C-Reed-FA26 --dry-run
./sync-templates.sh --source IT3038C --target IT3038C-Reed-FA26 --repo Bash-Basics
./sync-templates.sh --source IT3038C --target IT3038C-Reed-FA26 --skip-classroom50
./sync-templates.sh --source IT3038C --target IT3038C-Reed-FA26 --classroom it3038c| Flag | Purpose |
|---|---|
--source ORG |
Source organization (required) |
--target ORG |
Target organization (required) |
--dry-run |
List actions only; no creates, pushes, or Classroom50 writes |
--repo NAME |
Limit template sync to one repo (repeatable) |
--classroom NAME |
Limit Classroom50 overlay to one seed classroom (repeatable) |
--target-classroom NAME |
Existing target classroom that receives seed assignments |
--skip-classroom50 |
Templates only (skip init/overlay) |
--workdir DIR |
Local clone cache (default: .sync-cache) |
- Lists repos in the source org with GitHub
is_template: true - Skips any template whose default branch is not
main(warns; does not guess) - Creates the matching repo in the target org if missing (same visibility as source, marked as a template)
- Clones/updates a local cache with
--single-branch --branch mainonly - Pushes
main:mainto the target (no force-push)
Re-running the same command syncs newer main commits from source to target.
If target main has diverged (unique commits), the push fails safely. Resolve that manually before re-running; this tool will not force-push.
- Clones
SOURCE/classroom50seed (read-only; this is not an assignment template) - If
TARGET/classroom50is missing, runsgh teacher init TARGET(needsCLASSROOM50_SERVICE_TOKEN) - For each classroom directory in the seed (for example
it3038c/):- Resolves the destination classroom on the target:
--target-classroom NAMEif provided- else the seed short-name when it already exists on the target
- else the sole classroom on the target when there is exactly one (e.g. seed
it3038c→it3038c-001-fa26) - else creates a new classroom from the seed name when the target has none
- Registers each assignment into that existing (or newly created) classroom with
--template TARGET/<repo>@main - Applies declarative tests from the seed
assignments.json(gh teacher assignment addupserts by slug) - Copies optional
autograder.py/autograders/overrides into the destination classroom
- Resolves the destination classroom on the target:
- Never copies roster, scores, secrets, or overwrites init-owned skeleton workflows
Example for FA26 (seed it3038c → existing it3038c-001-fa26):
./sync-templates.sh --source IT3038C --target IT3038C-Reed-FA26 \
--target-classroom it3038c-001-fa26If FA26 already has only that one classroom, the same mapping happens automatically without --target-classroom.
- Only
mainis ever fetched or pushed for assignment templates. Solution and other branches stay in the source org. - Do not replace this flow with
git clone --mirrororgit push --mirror— those copy all refs. - Source and target orgs must differ.
- Local clones live under
.sync-cache/(gitignored). IT3038C/classroom50is seed content only; live Classroom50 belongs in semester orgs.
- Issues, wiki, Projects, GitHub Classroom assignment linkage
- Force-push / rewriting diverged target
main - Tags and release assets
- Copying Classroom50 roster or scores between orgs