chore(mirror): keep the Gitea fallback current from local git (#38)

GitHub is the source of truth; Gitea (origin) is a just-in-case copy that had
drifted two commits behind. Rather than require a credential on GitHub's side
or convert the repo to a read-only Gitea mirror, wire it into the local
workflow:

- scripts/mirror-gitea.sh — pushes prod + all tags to the Gitea remote
  (--branches for every branch). Refuses to push to a GitHub remote, prints
  what it did, exits non-zero when the mirror could not be updated.
- scripts/hooks/pre-push — git has no post-push hook, so the mirror runs before
  a push that includes prod/main or a tag; skips other remotes, deletions and
  its own recursion.
- scripts/hooks/post-merge — refreshes the mirror after `git pull`/merge on
  prod, which is how a PR squash-merged on GitHub reaches the mirror.
- scripts/install-git-hooks.sh — one-time per clone; sets
  core.hooksPath=scripts/hooks so the hooks stay versioned with the repo.

Mirror failures are warnings: a Gitea outage never blocks a push to GitHub.
AGENTS.md documents the setup plus the GitHub-only release flow.

Verified: script + hooks exercised for the prod/tag case, the feature-branch
skip, the Gitea-remote skip and the recursion guard; the mirror is idempotent
(no-op when already in sync).
This commit is contained in:
2026-09-24 03:56:27 +08:00
committed by GitHub
parent 9089f313f8
commit b17bf95b6d
5 changed files with 207 additions and 2 deletions
+25
View File
@@ -0,0 +1,25 @@
#!/bin/sh
#
# post-merge hook — after `git pull`/merge, refresh the Gitea fallback.
#
# Installed via `scripts/install-git-hooks.sh` (git core.hooksPath = scripts/hooks).
# GitHub merges (e.g. a squash-merged PR) happen server-side, so a local
# `git pull` on prod is the moment to bring the Gitea mirror along.
#
# args: $1 = 1 when the merge was a squash, otherwise 0
if [ "${GRIDLINE_MIRROR_RUNNING:-}" = "1" ]; then
exit 0
fi
branch="$(git symbolic-ref --short -q HEAD)" || exit 0
case "$branch" in
prod|main) ;;
*) exit 0 ;;
esac
root="$(git rev-parse --show-toplevel)" || exit 0
GRIDLINE_MIRROR_RUNNING=1 sh "$root/scripts/mirror-gitea.sh" ||
echo "post-merge: warning: Gitea mirror was not updated" >&2
exit 0
+46
View File
@@ -0,0 +1,46 @@
#!/bin/sh
#
# pre-push hook — mirrors the trunk branch and tags to the Gitea fallback.
#
# Installed via `scripts/install-git-hooks.sh` (git core.hooksPath = scripts/hooks).
# Git has no client-side post-push hook, so the mirror runs here: the refs are
# already committed locally, so whether Gitea or GitHub receives them first makes
# no difference. A Gitea outage prints a warning and never blocks the push.
#
# stdin receives one line per ref being pushed:
# <local-ref> <local-sha> <remote-ref> <remote-sha>
#
# args: $1 = remote name, $2 = remote URL
remote_url="${2:-}"
# Only react to pushes of the canonical GitHub remote.
case "$remote_url" in
*github.com*) ;;
*) exit 0 ;;
esac
# Don't recurse when the mirror script itself is pushing to Gitea.
if [ "${GRIDLINE_MIRROR_RUNNING:-}" = "1" ]; then
exit 0
fi
mirror_needed=0
while read -r _local_ref local_sha remote_ref _remote_sha; do
# Ignore deletions (all-zero object id).
case "$local_sha" in
0000000000000000000000000000000000000000) continue ;;
esac
case "$remote_ref" in
refs/heads/prod|refs/heads/main|refs/tags/*) mirror_needed=1 ;;
esac
done
[ "$mirror_needed" = "1" ] || exit 0
root="$(git rev-parse --show-toplevel)" || exit 0
GRIDLINE_MIRROR_RUNNING=1 sh "$root/scripts/mirror-gitea.sh" ||
echo "pre-push: warning: Gitea mirror was not updated (continuing with the push)" >&2
# Never block the push to GitHub because of a mirror problem.
exit 0