From 51acf9f86e22d98f1a30dc3817767cd96b111d9d Mon Sep 17 00:00:00 2001 From: Grant Whitmer Date: Wed, 12 Aug 2026 22:11:34 -0400 Subject: [PATCH] =?UTF-8?q?URGENT=20FIX:=20reverse=20the=20sync=20?= =?UTF-8?q?=E2=80=94=20GitHub=20is=20the=20source=20of=20truth,=20not=20Wi?= =?UTF-8?q?ndy=20Git?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I migrated nine repos writable with push-mirrors pointed AT GitHub. That was wrong for the actual situation: a dozen agent sessions on the Mac mini are pushing to GitHub continuously, so GitHub is where the live work is. A push-mirror force-updates refs. On its 8-hour timer it would have pushed Windy Git's stale copy over live work — silently, no conflict, nothing to notice. Removed all nine before the first timer fired; verified no GitHub repo had been touched (latest push predated the mirrors). Replaced with the correct Phase 1 direction: agents --push--> GitHub --sync--> Windy Git --> CI on Veron It requires NOTHING from anyone. No remote changes, no coordination, no 'everybody stop pushing'. Agents keep working exactly as they are and CI starts running on 24 cores. Windy Git is force-updated on purpose: in Phase 1 it holds nothing anyone depends on, so GitHub always wins and there is no merge to reconcile. Phase 2 is per-repo and only when that repo is idle. Never a big-bang cutover across a dozen live sessions. Fetches +refs/heads/* and tags explicitly rather than --mirror, which would drag GitHub's refs/pull/* that Gitea rejects and bury the real errors. Co-Authored-By: Claude Opus 5 --- scripts/sync_from_github.sh | 74 +++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100755 scripts/sync_from_github.sh diff --git a/scripts/sync_from_github.sh b/scripts/sync_from_github.sh new file mode 100755 index 0000000..4c9c935 --- /dev/null +++ b/scripts/sync_from_github.sh @@ -0,0 +1,74 @@ +#!/usr/bin/env bash +# Phase 1 sync: GitHub is the source of truth, Windy Git follows. +# +# ── Why this direction, and why the other one was wrong ──────────────────── +# +# On 2026-08-13 nine repos were migrated writable with push-mirrors pointed AT +# GitHub. That was premature: a dozen agent sessions on the Mac mini are pushing +# to GitHub continuously, so GitHub — not Windy Git — is where the current work +# actually lives. A push-mirror force-updates refs, so on its 8-hour timer it +# would have pushed Windy Git's stale copy over live work, silently, with no +# conflict to notice. The mirrors were removed before the first timer fired. +# +# This script is the correct Phase 1: pull from GitHub, push into Windy Git. +# +# Mac mini agents ──push──▶ GitHub ──this script──▶ Windy Git ──▶ CI on Veron +# +# **It requires nothing from anyone.** No remote changes, no coordination, no +# "everybody stop pushing for a minute." Agents keep working exactly as they are +# and CI starts running on 24 cores. +# +# Windy Git is force-updated on purpose. In Phase 1 it holds nothing anyone +# depends on, so GitHub always wins and there is no merge to reconcile — which +# is the entire point of not flipping direction until a repo is quiet. +# +# Phase 2, per repo, only when that repo is idle: point its agents at Windy Git, +# drop it from REPOS here, and add a push-mirror back to GitHub. One repo at a +# time. Never a big-bang cutover across a dozen live sessions. + +set -uo pipefail + +: "${GITHUB_TOKEN:?GITHUB_TOKEN required}" +: "${GITEA_ADMIN_TOKEN:?GITEA_ADMIN_TOKEN required}" +GH_OWNER="${GITHUB_OWNER:-sneakyfree}" +WG="${WG_HOST:-app.windygit.com}" +WG_OWNER="${WINDYGIT_OWNER:-windyadmin}" +WORK="${SYNC_WORK:-/srv/windygit/sync}" +FAILED=0 + +# Repos Windy Git tracks FROM GitHub. Remove a repo from this list at the moment +# it flips to Windy-Git-first, or the sync will fight its authors and win. +REPOS="${SYNC_REPOS:-windy-calendar windy-search windy-registry Windy-Clone WindyCloud windy-cloud-sites windy-mind eternitas windy-agent}" + +mkdir -p "$WORK" +log() { printf '[sync %s] %s\n' "$(date -u +%H:%M:%SZ)" "$*"; } + +for r in $REPOS; do + bare="$WORK/${r}.git" + if [[ ! -d "$bare" ]]; then + git clone --quiet --bare "https://x-access-token:${GITHUB_TOKEN}@github.com/${GH_OWNER}/${r}.git" "$bare" 2>/dev/null \ + || { log "FAILED initial clone of $r"; FAILED=1; continue; } + fi + + # +refs/heads/* — branches only, deliberately. + # + # `--mirror` would also carry refs/pull/* (GitHub's read-only PR refs, which + # Gitea rejects) and every remote-tracking ref, turning a working sync into a + # wall of errors that hides the one that matters. + if ! git --git-dir="$bare" fetch --quiet --prune origin '+refs/heads/*:refs/heads/*' '+refs/tags/*:refs/tags/*' 2>/dev/null; then + log "FAILED fetch $r"; FAILED=1; continue + fi + + before="$(git --git-dir="$bare" rev-parse HEAD 2>/dev/null || echo none)" + + if git --git-dir="$bare" push --quiet --force \ + "https://${WG_OWNER}:${GITEA_ADMIN_TOKEN}@${WG}/${WG_OWNER}/${r}.git" \ + '+refs/heads/*:refs/heads/*' '+refs/tags/*:refs/tags/*' 2>/dev/null; then + log "$r ok (${before:0:7})" + else + log "FAILED push $r -> windy git"; FAILED=1 + fi +done + +[[ "$FAILED" -ne 0 ]] && { log "COMPLETED WITH FAILURES"; exit 1; } +log "all repos in step with GitHub"