Open-source project
Yikun/hub-mirror-action avatar
Yikun/hub-mirror-action

hub-mirror-action: mirroring an account across GitHub, Gitee, GitLab and GitCode

一个Github Action,用于在Github, Gitee, GitLab和GitCode之间同步代码。Action for mirroring repos between Hubs (like Github, Gitee, GitLab and GitCode).

711 stars199 forksPythonMIT

At a glance

What is it?
Hub Mirror Action is a Python GitHub Action that copies an account's repositories between code hosting hubs, creating the destination repos if they do not exist and pushing with an SSH key, with filters and per-hub endpoints. It suits a team that needs one project's history on more than one platform, and it does nothing for a single repository that only needs a fork.
Who is it for?
hub-mirror-action is worth adding to a workflow when one upstream account has to appear on several platforms, because it understands the difference between a user, an organisation and a GitLab group, it creates the destination repository when it is missing, and it lets you copy only the repositories you name in the white list. It is the wrong tool for mirroring a single repository, where a plain git push to a second remote is simpler and needs no tokens.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 169 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

It mirrors an account, not a repository

The project description states the scope in both languages: it is a GitHub Action for synchronising code repositories between accounts on hubs such as GitHub, Gitee, GitLab and GitCode.

The unit of work is the account. The action is given a source account and a destination account, and it walks the source's repository list and pushes each one to the matching place on the destination. The example configuration mirrors the kunpengcompute organisation from GitHub to Gitee:

yaml
steps:
- name: Mirror the Github organization repos to Gitee.
  uses: Yikun/hub-mirror-action@master
  with:
    src: github/kunpengcompute
    dst: gitee/kunpengcompute
    dst_key: ${{ secrets.GITEE_PRIVATE_KEY }}
    dst_token: ${{ secrets.GITEE_TOKEN }}
    account_type: org

Two credentials are involved, and they do different jobs. dst_key is the private key used to push code to the destination, and the documentation notes it can be taken from ~/.ssh/id_rsa by default, with links to the key generation guides for Gitee, GitHub and GitLab. dst_token is the API token used to create repositories that do not exist yet, so that the push has somewhere to go. The public key corresponding to dst_key has to be registered on the destination side, and the documentation links the settings pages for each hub.

The repository itself is small: a hub-mirror/ directory holding the Python implementation, an action.yml, and a .github/ directory whose workflows directory is pointed at as the place to find complete usage and test demos. The primary language is Python, the licence is MIT, and the default branch is master.

User, organisation and group are three different things

The parameter that causes the most confusion is account_type, and the documentation explains why with a rule rather than a description.

The default is user. The value can be org for an organisation, user for a user, or group for a group, and the parameter supports synchronising accounts of the same type, organisation to organisation, user to user, or group to group. If the source and destination repositories are of different types, you configure src_account_type and dst_account_type separately.

That is the whole rule: account_type sets both ends and requires them to match, while the two separate parameters override each end independently. Their defaults are account_type itself, so setting only one of them leaves the other following the shared value. The comment in the example configuration shows the shape, with src_account_type and dst_account_type both present but commented out.

The supported combinations differ by hub, and the documentation is specific about it: GitHub, Gitee and GitCode support users, organisations and GitLab supports groups. So a group-to-group mirror is a GitLab to GitLab job, while org-to-org covers the other platforms.

For a user, the account is the person, so the src value looks like github/someuser and the action mirrors that person's public repositories. For an organisation it is the org name, and for a GitLab group it is the group path.

The optional parameters are where the real behaviour lives

Beyond the two account type parameters there is a set of options that change what gets copied and how it gets there, and each one has a documented default.

src_token is an API token for fetching the repository list from the source. It is required when the source is an organisation or has private repositories and authentication is needed, which the documentation names explicitly for GitCode and Gitee, and it links the token settings pages for all four hubs. Without it, the action cannot list the source's repositories, so this is the parameter that decides whether a private or org mirror works at all.

src_endpoint and dst_endpoint are empty by default and only take effect when the relevant end is GitLab. They hold a self-hosted GitLab address such as gitlab.example.com, without the https prefix, and an empty value means gitlab.com. That is a narrow but important rule, because a self-hosted GitLab mirror silently has to be spelled without a scheme.

clone_style defaults to https and can be ssh or https. When it is ssh, the public key matching dst_key has to be configured on both the source and the destination, so a private source repository can be cloned.

cache_path defaults to hub-mirror-cache and caches the code in the given directory, to be used with actions/cache to speed up the mirroring. A relative path is automatically joined to ${{ github.workspace }}. So the action is written to be run repeatedly without re-cloning everything each time.

Then the two filters. black_list defaults to an empty string, and once configured the repositories in it are not synchronised, in a comma separated form such as repo1,repo2,repo3. white_list also defaults to an empty string, and when set only the matching repositories are synchronised. The documentation excerpt for white_list is cut off, but the two are complementary, and a black list is the safer of the pair for an organisation mirror where a new repository should not silently appear on the other platform.

The release line is slow, and the last push is months behind

The maintenance picture is worth stating plainly rather than glossing.

The releases are v1.3 from 2023-07-18, v1.4 from 2024-04-26, and v1.5 from 2025-01-28, named with the tag description Hub Mirror Action v1.5 and so on. The last push to the repository was on 2026-05-07, and the repository is not archived.

So the code is not abandoned, but the last change is over five months old, and the newest tag is more than a year older than that. The example configuration in the documentation refers to the action at @master rather than at a version tag, which is a choice with a real cost: you get whatever is on the branch at the moment the workflow runs, and there is no published tag to pin to if you want a reproducible pipeline.

The upstream context explains the shape of the project. The documentation points at a search showing more than 100 organisations and more than 4000 users referring to hub-mirror-action with the account_type and org parameters, and it links a set of user tutorials from projects including openEuler, Ascend, MindSpore, openGauss, OpenHarmony, EdgeGallery and WeBankFinTech. Those are large multi-platform organisations, openEuler and OpenHarmony among them, and the practical lesson is that this action exists because mirroring an entire project account to a second code hosting platform is common work in that ecosystem and tedious to script by hand.

The licence is MIT, which is the permissive end and carries no obligation beyond keeping the notice, and the project also offers a Gitter room for questions.

Where hub-mirror-action is the wrong tool

The first limit is the credential surface. To mirror an account you need an SSH private key on the destination, an API token with repository creation rights, and often a second token on the source to list private repositories. Three secrets with real write scope, held in a workflow, is a meaningful attack surface for what is conceptually a copy operation, and a project that has moved from a private repository to a public one on a second platform has published that code to two platforms with the same history.

The second is that this is a mirror, not a fork, and not a sync in the two-way sense. The action copies in one direction from the source account to the destination account. A diverged destination is not reconciled, and there is no description in the documentation of a conflict policy. A team that pushes to the source and also has contributors pushing directly to the destination is in a situation this action does not describe.

The third is the account granularity. The unit is the account, and the filters are repository names. For an organisation with hundreds of repositories, the white list has to name every one you want mirrored, and the black list has to be maintained as new repositories appear. A project that wants exactly one repository mirrored is paying for an account-level tool.

The fourth is the platform scope. The documentation describes endpoints only for GitLab, and the account type combinations only make sense for the four named hubs. A destination on another forge, or a self-hosted GitLab that the endpoint parameters do not cover, is not addressed.

The fifth is that a plain git remote is often the better tool. A single repository that needs to exist on a second platform does not need tokens, does not need a whitelist, and does not need an account walk, and a scheduled git push to a second remote does it in a few lines. hub-mirror-action earns its complexity when the scope is an account.

Editorial conclusion

hub-mirror-action is worth adding to a workflow when one upstream account has to appear on several platforms, because it understands the difference between a user, an organisation and a GitLab group, it creates the destination repository when it is missing, and it lets you copy only the repositories you name in the white list. It is the wrong tool for mirroring a single repository, where a plain git push to a second remote is simpler and needs no tokens. Before you adopt it, check the three things the parameter documentation is explicit about: the account_type rule, since the parameter only synchronises same type accounts and a mismatch needs the separate src_account_type and dst_account_type values; the token scopes, since GitCode requires api, read_api, read_repository and write_repository; and the endpoint settings, because src_endpoint and dst_endpoint only take effect for GitLab and must be given without the https prefix if you are self-hosting.

Frequently asked questions

How do I mirror a GitHub organisation to Gitee with hub-mirror-action?

Add a step that uses Yikun/hub-mirror-action@master with src set to the GitHub organisation, dst set to the matching Gitee organisation, dst_key pointing at a private key secret, dst_token pointing at a Gitee API token secret, and account_type set to org. The public key matching dst_key has to be registered on the destination side.

What is the difference between account_type and src_account_type in hub-mirror-action?

account_type defaults to user and sets both ends at once, and it only supports synchronising accounts of the same type, organisation to organisation, user to user or group to group. src_account_type and dst_account_type each default to account_type and are used when the source and destination are different types.

Which parameters control which repositories hub-mirror-action copies?

The black_list parameter, empty by default, excludes the named repositories from the sync, and the white_list parameter, also empty by default, restricts the sync to the named repositories. Both take a comma separated list, such as repo1,repo2,repo3.

Official sources

  1. Issues
  2. License: MIT
  3. README
  4. Releases
  5. Yikun/hub-mirror-action on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/yikun-hub-mirror-action.svg)](https://hysenlabs.com/projects/yikun-hub-mirror-action)

Was this useful?