Skip to content

Latest commit

 

History

21 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 

mirror

GitHub Action to mirror a repo to any git forge

Usage

This action mirrors all branches and tags, pruning any that no longer exist in the source.

Warning

Mirrors should be treated as read-only; there is no two-way sync. Issues and pull requests are also not mirrored.

  1. Create a destination: an empty repository on your desired forge(s) (e.g. GitLab, Tangled, Codeberg)

  2. Prepare authentication: either a personal access token (e.g. for GitLab) or SSH key (e.g. for Tangled)

  3. Add this action to your repo: after checking out with fetch-depth: 0, call the action once per destination:

    - uses: actions/checkout@v6
      with:
        repository: your-org/your-repo
        fetch-depth: 0
    
    - name: Mirror to GitLab
      uses: roostorg/mirror@main
      with:
        destination: https://gitlab.com/your-org/your-repo.git
        token: ${{ secrets.GITLAB_TOKEN }}
    
    - name: Mirror to Tangled
      uses: roostorg/mirror@main
      with:
        destination: git@tangled.org:your-handle/your-repo
        ssh_private_key: ${{ secrets.TANGLED_SSH_PRIVATE_KEY }}
        ssh_known_hosts: ${{ secrets.TANGLED_KNOWN_HOSTS }}

See the examples below for specific forge configuration, or see how ROOST uses this.

Inputs

Input Required Default Description
destination yes — Remote URL to push to (HTTPS or SSH). Do not embed credentials here.
token for HTTPS — OAuth2 or personal access token. Injected into the URL; never echoed.
token_username no oauth2 Username in the HTTPS URL. oauth2 works for GitLab; use the account username for Gitea, Forgejo, and Codeberg.
ssh_private_key for SSH — PEM private key (ED25519 or RSA). Written to a temp file with mode 0600 and deleted after the push.
ssh_known_hosts recommended — Known-hosts entries for the destination host (see below). If omitted, falls back to ssh-keyscan with a TOFU warning.

Examples

GitLab: HTTPS with OAuth2 token (default token_username of oauth2 is correct):

- uses: roostorg/mirror@main
  with:
    destination: https://gitlab.com/your-org/your-repo.git
    token: ${{ secrets.GITLAB_TOKEN }}

Tangled: SSH with ED25519 key:

- uses: roostorg/mirror@main
  with:
    destination: git@tangled.org:your-handle/your-repo
    ssh_private_key: ${{ secrets.TANGLED_SSH_PRIVATE_KEY }}
    ssh_known_hosts: ${{ secrets.TANGLED_KNOWN_HOSTS }}

Codeberg: HTTPS with a Codeberg username and token:

- uses: roostorg/mirror@main
  with:
    destination: https://codeberg.org/your-username/your-repo.git
    token: ${{ secrets.CODEBERG_TOKEN }}
    token_username: your-username

Gitea / Forgejo: HTTPS with account username and token:

- uses: roostorg/mirror@main
  with:
    destination: https://your-forgejo-instance.example.com/your-username/your-repo.git
    token: ${{ secrets.FORGEJO_TOKEN }}
    token_username: your-username

Getting ssh_known_hosts

Run this once and store the output as a repository secret:

ssh-keyscan -t ed25519,rsa,ecdsa tangled.org

Providing this value means the action verifies the host's identity at push time. Without it, the action falls back to ssh-keyscan on each run, which does not verify host identity (trust-on-first-use).

Security notes

  • Tokens are injected into a shell variable and never echoed; GitHub Actions also masks the raw secret value in all log output.
  • SSH private keys are written to $RUNNER_TEMP (not ~/.ssh) with chmod 600 and deleted immediately after the push.
  • IdentitiesOnly=yes prevents the SSH agent from offering other keys during the push.
  • StrictHostKeyChecking=yes ensures the action hard-fails if the host key doesn't match, rather than silently connecting.
  • Only the git repository (branches, tags, and commits) is mirrored; pull requests and issues are not.
  • Do not mirror private repositories. The action does not check repo visibility.

How ROOST uses this

ROOST maintains a mirror workflow in this repo that runs hourly and on push to main. It checks out each repo in a matrix, then calls this action once for each remote.

To add a ROOST repo to our mirrors:

  1. Create an empty repo of the same name on each forge (e.g. gitlab.com/roostorg)
  2. Add the repo name to the repo matrix in .github/workflows/mirror.yml
  3. Wait up to an hour, or trigger the workflow manually from the Actions tab

About

GitHub Action to mirror a repo to any git forge

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors