1
4
Fork
You've already forked forgesync
0
Automatically mirror all your Forgejo repositories to GitHub or any Forgejo instance (Mirror of https://hack.moontide.ink/pingfisher/forgesync)
  • Python 78.9%
  • Nix 20.2%
  • Dockerfile 0.9%
2026年07月05日 20:00:28 +02:00
src/forgesync fallback 2026年07月05日 19:36:25 +02:00
.envrc init 2025年05月01日 21:30:27 +02:00
.gitignore gitignore 2025年11月30日 21:50:04 +01:00
.python-version init 2025年05月01日 21:30:27 +02:00
Containerfile improvements 2025年08月21日 03:34:16 +02:00
flake.lock deps 2026年07月05日 19:51:39 +02:00
flake.nix debloat flake 2026年02月21日 13:05:43 +01:00
LICENSE init 2025年05月01日 21:30:27 +02:00
module.nix fix eval warning 2026年01月29日 22:52:59 +01:00
pyproject.toml release 1.2.0 2026年07月05日 20:00:28 +02:00
README.md properly handle description placeholders 2026年07月04日 19:25:58 +02:00
treefmt.toml debloat flake 2026年02月21日 13:05:43 +01:00
uv.lock release 1.2.0 2026年07月05日 20:00:28 +02:00

Forgesync

Forgesync automatically synchronizes all your Forgejo repositories to GitHub or any Forgejo instance (e.g. Codeberg).

While Forgejo supports periodic Git mirroring out of the box, it doesn't support syncing repository metadata, and setting these mirrors up manually can be a lot of work. Forgesync resolves this by:

  • Automatically creating target repositories
  • Syncing repository metadata (descriptions, topics, etc.)
  • Enabling or disabling features like issues or pull requests on the destination
  • Setting up mirrors directly within the source Forgejo instance
  • Filtering out forks, mirrors, and private repositories

Getting Forgesync

Forgesync is currently available as:

CLI usage

Here's how you would synchronize your Codeberg repositories to GitHub:

# Token for gathering source repository metadata and setting up mirrors.
export SOURCE_TOKEN=my_codeberg_token
# Token for creating and synchronizing repositories at the destination of your choosing.
export TARGET_TOKEN=my_github_token
# Token used within Forgejo for Git mirroring.
export MIRROR_TOKEN=my_github_mirror_token
# Run the sync:
forgesync https://codeberg.org/api/v1 github \
 --remirror \
 --feature issues \
 --feature pull-requests \
 --on-commit \
 --mirror-interval 8h0m0s \
 --exclude myrepo

Run forgesync --help to see what the example options do, and which ones you can add on top.

Check required token scopes to find out what you need to specify when creating tokens.

Warning

Before running Forgesync, make sure you have backed up your repositories from the destination if you have any and plan to keep them. Forgesync will overwrite any repositories at the destination that share the same names as those on the source Forgejo instance. For more information, see syncing by name.

Usage via Nix

This flake outputs a package via packages.<system>.default and a NixOS module via nixosModules.default. See flake.nix for more details.

NixOS module usage

Here's an example Forgesync configuration for NixOS:

{
 services.forgesync = {
 enable = true;
 jobs = {
 github = {
 source = "https://codeberg.org/api/v1";
 target = "github";
 settings = {
 remirror = true;
 feature = [
 "issues"
 "pull-requests"
 ];
 on-commit = true;
 mirror-interval = "0h0m0s";
 };
 # Use whichever secret management you prefer, e.g. agenix.
 secretFile = "/path/to/secrets";
 timerConfig = {
 OnCalendar = "daily";
 Persistent = true;
 };
 };
 codeberg = {
 source = "https://forgejo.example.com/api/v1";
 target = "codeberg";
 settings = {
 remirror = true;
 feature = [
 "issues"
 "pull-requests"
 ];
 on-commit = true;
 mirror-interval = "0h0m0s";
 };
 # Ditto.
 secretFile = "/path/to/secrets";
 timerConfig = {
 OnCalendar = "daily";
 Persistent = true;
 };
 };
 };
 };
}

Take a look at the module source for more details.

Container usage

Alternatively, Forgesync can also be run in a container with Podman, Docker, Kubernetes, etc.

Building the container

You can build the container with your favorite image building tool (Podman, Buildah, Docker, etc.).

Example with Podman:

podman build -t localhost/forgesync .

Running the container

The SOURCE_TOKEN, TARGET_TOKEN, and MIRROR_TOKEN tokens must be passed to the container at runtime (-e for Podman/Docker, or as a Kubernetes secret).

Example with Podman:

podman run --rm -it \
 -e SOURCE_TOKEN=my_forgejo_token \
 -e TARGET_TOKEN=my_github_token \
 -e MIRROR_TOKEN=my_github_mirror_token \
 localhost/forgesync https://codeberg.org/api/v1 github \
 --remirror \
 --feature issues \
 --feature pull-requests \
 --on-commit \
 --mirror-interval 8h0m0s \
 --exclude myrepo

Required token permissions

SOURCE_TOKEN

  • write:repository
  • read:user

Forgejo

TARGET_TOKEN

  • write:repository
  • write:user

MIRROR_TOKEN

  • write:repository

GitHub

TARGET_TOKEN

  • Administration: Read and write
  • Contents: Read-only
  • Metadata: Read-only

MIRROR_TOKEN

  • Contents: Read and write
  • Metadata: Read-only

Mirror management

Re-mirroring

Forgejo stores a few bits of information as part of a push mirror, including:

  • The mirror token
  • The mirror interval
  • The "on commit" toggle

There is currently no way to diff these fields via the Forgejo API, so if you want to change any of them, you need to use re-mirroring to recreate the push mirror with the desired configuration.

Syncing by name

Forgesync synchronizes repositories by their names, so a typical setup would look like this:

  • forgejo-user/repo-a → github-user/repo-a
  • forgejo-user/repo-b → github-user/repo-b
  • forgejo-user/repo-c → github-user/repo-c

If you rename repo-a to repo-a-ng, the old push mirror will remain in Forgejo, and it will keep mirroring to github-user/repo-a as well as github-user/repo-a-ng. Forgesync does not track renames or maintain any state about repository history, so it won't detect that the destination no longer matches the source. As a workaround, you can pass --purge to wipe all existing push mirrors from the source repository before creating any new ones.

Repository description

The --description-template option expects a string with placeholders. The default is {description} (Mirror of {url}), but you can use any of these placeholders in your own description:

  • description (the original description in the Forgejo repository)
  • url (the URL to the Forgejo repository)
  • website (the website entered in the Forgejo repository metadata)
  • full_name (e.g. user/repo)
  • clone_url (the Git clone URL)