gitlab-github-sync
A Python CLI that keeps repositories on GitLab and GitHub in sync — metadata, code,
issues and merge requests / pull requests — by driving the official vendor CLIs
(glab, gh) and GitLab’s remote mirroring APIs.
Why this exists
Section titled “Why this exists”GitLab can mirror code to GitHub natively, and that solves exactly one part of the problem. Nothing carries the repository description, the topics, the issues or the merge requests across. Writing that against both REST APIs directly means dealing with two authentication schemes, two pagination models and two JSON shapes.
This tool sidesteps all of it by shelling out to the CLIs that already solve authentication.
If gh repo list and glab repo list work on your machine, the tool works — there is no
token to put in a config file and no API client to keep current.
What gets synchronized
Section titled “What gets synchronized”| Area | Direction | Mechanism |
|---|---|---|
| Metadata — description, homepage URL, topics/tags | both ways | gh repo edit / glab repo update |
| Code — branches, tags, commits | both ways | GitLab remote mirrors, configured via glab api |
| Issues | both ways | gh issue create/edit / glab issue create/update |
| Merge requests ↔ pull requests | both ways | gh pr create/edit / glab mr create/update |
Features
Section titled “Features”- Auto-discovery —
--sync-alllists repositories on both platforms and pairs them by repository name, independent of namespace. - Counterpart creation —
--create-missingcreates the repository on the side where it does not exist yet, copying the description across. - Blacklist —
fnmatchpatterns such asgroup/*-scratchexclude repositories from discovery and from the final sync list. - Idempotent state —
.sync_state.jsonstores last-sync timestamps per pair plus the issue and MR/PR number mappings, so a second run updates instead of duplicating. - Dry run —
--dry-runlogs every intended change and performs none. - Readable output — a
tqdmprogress bar over repository pairs, with a logging handler that routes records throughtqdm.write()so the bar never gets corrupted.
What it does not do
Section titled “What it does not do”Being explicit about this is more useful than a feature list:
- Comments on issues and MRs/PRs are not synchronized — only title, body and state.
- Nothing is ever deleted. Closing propagates; deletion does not.
- A new MR/PR needs its branches to already exist on the target side, so code sync has to have run first.
- Pull mirroring (GitHub → GitLab code) requires GitLab Premium or higher. On lower tiers only the GitLab → GitHub direction is configured.
- Metadata sync is last-writer-wins, with no conflict detection.
- The project ships no automated tests.
Next steps
Section titled “Next steps”- Installation — prerequisites and setup
- Configuration — every option explained
- Usage — commands and flags
- Architecture — how the modules fit together