- Go 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
|
||
| .forgejo/workflows | ||
| LICENSES | ||
| .gitignore | ||
| config.go | ||
| config_test.go | ||
| github.go | ||
| github_test.go | ||
| go.mod | ||
| go.sum | ||
| LICENSE | ||
| main.go | ||
| migrate.example.yaml | ||
| migrate.go | ||
| migrate_test.go | ||
| README.md | ||
| renovate.json | ||
| REUSE.toml | ||
ForgePort
A small CLI tool that migrates repositories from GitHub to the OpenCommit Forgejo
instance (opencommit.eu) using the
Forgejo SDK.
The tool reads all of its configuration from a YAML file in the current working directory. It currently migrates a single repository (or a list of them, sequentially).
Requirements
- Go 1.26 or later unless you use a pre-built binary
- A Forgejo API token for the destination instance (create it in
Forgejo → Settings → Applications →
Generate New Token) - A GitHub personal access token (classic) for the source repositories
Usage
forgeport -config migrate.yaml # defaults to `migrate.yaml` in the working directory
forgeport -dryrun # resolve and print repos without migrating
-config defaults to migrate.yaml in the working directory. Each repository
is migrated one at a time. Between migrations the tool sleeps a random pause of
5–15 seconds to avoid overloading the destination server. Run output is logged
to stderr; the tool exits with a non-zero status if the configuration is invalid
or any migration fails.
-dryrun resolves every repository (including user/org expansion) but does not
contact Forgejo or migrate anything; it only prints which repositories would
have been migrated.
Exiting example:
2026/01/01 12:00:00 migrating https://github.com/foo/bar -> opencommit/bar
2026/01/01 12:00:05 migrated: https://opencommit.eu/opencommit/bar
Note: migrate.yaml may contain secrets and is git-ignored. Commit
migrate.example.yaml instead.
Limitations
The forgeport tool does currently not support migration of packages. You will have to do that yourself with a tool like Skopeo and a small bash script for example.
Configuration
Copy migrate.example.yaml to migrate.yaml in the directory you will run the
tool from and edit it.
forgejo:
url: https://opencommit.eu
token: ""
defaults:
token: ""
include_private: true
include_archived: false
destination:
owner: ""
name: ""
options:
private: false
description: ""
wiki: true
milestones: true
labels: true
issues: true
pull_requests: true
releases: true
lfs: false
lfs_endpoint: ""
repositories:
- url: https://github.com/opencommit/opencommit.git
# - url: my-github-user # shorthand: migrate all of a user/org's source repos
Tokens
Secrets can live in the config file or their environment, with the environment winning:
| Setting | Environment variable | Precedence |
|---|---|---|
| Forgejo token | FORGEJO_TOKEN |
env > forgejo.token |
| GitHub token | GITHUB_TOKEN |
env > repository token > defaults.token |
The GitHub token is required: the Forgejo migration API authenticates against the source even for public repositories.
Sections
forgejo— connection settings for the destination instance.url— Forgejo server URL, e.g.https://opencommit.eu. Required.token— API token for the destination. Required unlessFORGEJO_TOKENis set.
defaults— global defaults applied to every repository (for every setting except the repositoryurl).token— default GitHub source token.include_private— when expanding a user/org shorthand, include private repos the token has access to. Default:true.include_archived— when expanding a user/org shorthand, include archived repos. Default:false.destination—owner(required once resolved) andname(blank means derived from the url's repository name).options— migration options:private,description,wiki,milestones,labels,issues,pull_requests,releases,lfs,lfs_endpoint.
repositories— list of repositories to migrate. Onlyurlis required per entry; everything else can be inherited fromdefaultsor overridden per entry with the same shape asdefaults.urlis a git clone URL ending in.git, such ashttps://github.com/foo/bar.git. The tool exits with an error if a full URL does not end in.git. If the list contains exactly one entry and itsurlis a single word (no/,.or:), it is treated as a GitHub user or org name and expanded into all of that user/org's source (non-fork) repositories. Forks are always excluded;include_privateandinclude_archivedindefaultscontrol whether private and archived repos are included. Private repos are listed via the token's own account endpoint, so when the single word names the user the token belongs to, their private repos are returned as expected. The expanded repos inherit the entry'stoken,destinationandoptionsfromdefaults.
Merge rules
- A repository entry inherits every setting from
defaultsand overrides only the fields it sets explicitly. destination.namedefaults to the repository name taken from the source url (a trailing.gitis stripped).- Unset option flags resolve to
false/""— there are no hidden built-in defaults. Set what you want migrated indefaults. - Unknown keys in the config are rejected.
License
This software is licensed under the EUPL-1.2 license. See the LICENSES/EUPL-1.2.txt file for the full license text.