Skip to content

Mirroring to GitHub or another forge

You want a copy of the repository on GitHub, Codeberg, or a similar forge for the people who browse, star, and search there, while the signed nostr state stays the source of truth.

There are two ways to arrange it. Either way, bring the forge up to date with nostr before merging a pull request there, so the two never diverge and you never have to merge them back together.

  • Keep the forge as a separate remote. Add it as an ordinary git remote in your checkout and push to it when you choose. ngit never learns it exists. This is what many maintainers settle on: the forge can't slow down or block a nostr push, and any mistake stays in your checkout.
  • List the forge as a git server. Add its clone URL to the announcement with --additional-clone. ngit then pushes to it, checks its refs, and lets nostr:// clones fetch objects from it. This is the most common reason to use --additional-clone at all.

Keep the forge as a separate remote

If the repository started on the forge, ngit init has already done this: it kept the old origin URL as a remote named after the host, such as github. See Already on GitHub or another forge. Otherwise, add the forge with a URL you can push to:

bash
git remote add github git@github.com:OWNER/REPOSITORY.git

Whenever you want the mirror refreshed, push the published nostr tracking ref rather than your working branch:

bash
git fetch origin
git push github refs/remotes/origin/main:refs/heads/main
git push github --tags

Repeat the explicit push for each branch you mirror. Push through the nostr remote first, so the mirror never carries commits that nostr doesn't.

ngit does not advertise, contact, update, or check this remote. The nostr.trust-server-domains setting has no effect on it, because it isn't a listed repository server. That is the point: a broken or stale mirror can't interfere with nostr operations, and the mirror moves only when you move it.

The trade-off is that it is manual. Forget to push and the mirror goes stale. If someone merges there, you carry the result back by hand.

If the forge is only a display mirror, the simplest policy is to disable pull requests on GitHub and avoid direct pushes there. It can then never move ahead through its own review flow.

List the forge as a git server

Add the forge's HTTPS clone URL to the repository announcement:

bash
ngit repo edit \
  --add-additional-clone https://github.com/OWNER/REPOSITORY.git
git config nostr.trust-server-domains github.com
ngit sync

List the HTTPS URL rather than the SSH one, so web clients such as GitWorkshop can fetch from it. For pushes, ngit tries the host's git@ SSH variant automatically, so pushing works wherever you have an SSH key set up for that domain.

The forge becomes one of the servers that nostr:// clones and fetches can use for git objects. Pushes through the nostr remote and ngit sync also try to keep it aligned with every other listed server.

The nostr.trust-server-domains setting gives ngit sync one extra ability: if the forge is strictly fast-forward ahead of the signed nostr state, sync may adopt the forge's tip and publish a new state event. Use ngit sync --trust-server for one-off trust instead. Add --global to the git config command to trust the host in every repository.

Trust is deliberately narrow:

  • It applies when you run ngit sync, not when you run git fetch or git push.
  • It accepts only a clean fast-forward. If the forge and nostr have diverged, neither side is chosen automatically.
  • Updating nostr state requires a logged-in maintainer, so the replacement state event can be signed.

This is the integrated option. Contributors can download from the forge copy, and ngit checks its refs while pushing. It also means the forge is part of normal repository operations rather than a fire-and-forget backup: an unreachable or misconfigured forge shows up in every push.

Merging on the forge

Bring the forge's default branch up to the current nostr state first, with the mirror push above. After the merge, bring the new tip back through the nostr remote:

bash
git fetch origin
git fetch github
git switch main
git merge --ff-only origin/main
git merge --ff-only github/main
git push origin main

With a listed git server and trust configured, ngit sync does that last step for you when the forge is cleanly ahead.

If a merge landed on nostr in between, the two have diverged. ngit sync reports it and prints a command for each way back: merge both sides and push the result through the nostr remote, which keeps every commit, or force one side to match the other, which discards some. See Refs out of sync.

Next

Git collaboration, without the platform.