Skip to content

Push mirrors (Remote mirrors)

This section allows to manage push mirroring for projects.

Basic use

All mirrors are defined under the remote_mirrors section/key. Multiple mirrors can be defined as a dictionary. The key name for each mirror is the mirror target URL (e.g., https://... or ssh://...) and the values are parameters described in the Remote mirrors API docs.

Also, GitLab's UI doesn't allow updating configuration of an existing mirror. One must be deleted and recreated. But, using GitLab's edit API, GitLabForm will modify an existing mirror, if changes to mirror attributes are detected.

projects_and_groups:
  my-group/my-project:
    remote_mirrors:
      "https://username:password@example.com/path-to/my-repo.git":
        enabled: true
        auth_method: "password"
        only_protected_branches: true

Authentication and URL formats

Unlike the GitLab Web UI, which provides separate fields for usernames and passwords, GitLab API expects authentication credentials to be embedded directly within the URL string. For more details on how GitLab handles mirror authentication, see the GitLab documention on Authentication methods for mirrors.

The URL Patterns are not clearly documented in GitLab's API documentation. Below are some example URL format:

Protocol auth_method URL Format
HTTPS (Token) password https://username:token@github.com/org/repo.git
SSH (Password) password ssh://username:password@external-host.com/org/repo.git
SSH (Public Key) ssh_public_key ssh://git@external-host.com/org/repo.git

Verify your URL format

If you are unsure of the exact URL format GitLab expects for a specific provider, manually create a mirror in the GitLab UI first and make sure it works. Then, use a curl command to inspect the resulting mirror object:

curl --header "PRIVATE-TOKEN: <your_token>" "https://gitlab.example.com/api/v4/projects/<id>/remote_mirrors

Note that GitLab will return the URL with credentials masked (e.g., https://*****:*****@...), but the structure will confirm if your URL for GitLabForm configuration is correct.

Limitation

For SSH type mirrors, GitLab requires host key of the target where the mirror is located. GitLab's Web UI allows it to either automatically detect the target host using the mirror URL or a host key can be manually entered.

As of GitLab 18.6, the API does not accept the target's SSH host keys in the request payload. Because of this, SSH based mirror can be configured using GitLabForm, but it will not be functional. GitLab will not be able to push to the target mirror. And unlike the API, GitLab's UI doesn't allow "editing" a mirror either where manual intervention could've been a work-around.

Warning

Configuring a SSH based mirror using GitLabForm is possible but it will not be functional due to limitation with GitLab's API not accepting mirror's host key.

Tip

Use an HTTP based mirror for completely automatied configuration-as-code workflow for managing push mirrors.

Special configuration keys

enforce

This is a boolean type key that can be set under remote_mirrors section. Set to true to delete any mirrors found in GitLab that are not defined in the config.

projects_and_groups:
  my-group/my-project:
    remote_mirrors:
      enforce: true # Delete all other mirrors in GitLab that are not defined below
      "https://username:password@example.com/path-to/my-repo.git":
        enabled: true
        auth_method: "password"
        only_protected_branches: true

Because repository mirror settings are often restricted to users with Maintainer or Owner permissions, regular developers often cannot verify if a mirror is functioning correctly through the GitLab Web UI.

Set this attribute to true and GitLabForm will retrieve the full state of all remote mirrors in the project and print their attributes to the terminal. This includes the synchronization status, last successful update time, and any error messages returned by GitLab. This is particularly useful in CI/CD logs to monitor the health of your mirrors.

projects_and_groups:
  my-group/my-project:
    remote_mirrors:
      print_details: true # Global option to report on all mirrors in this project
      "https://username:password@example.com/path-to/my-repo.git":
        enabled: true
        auth_method: "password"

Example Output in Terminal:

📋 Final Remote Mirror Report for 'my-group/my-project':
  ────────────────────────────────────────
  - enabled: True
  - auth_method: password
  - enabled: True
  - host_keys: []
  - id: 479
  - keep_divergent_refs: None
  - last_error: None
  - last_successful_update_at: 2026-01-11T10:00:00.000Z
  - last_update_at: None
  - last_update_started_at: None
  - mirror_branch_regex: None
  - only_protected_branches: False
  - update_status: ✅ finished
  - url: https://*****:*****@example.com/path-to/my-repo.git
  ────────────────────────────────────────

delete

This is a boolean type key that can be used within indiviudal mirror. Set this to true for the corresponding mirror to be deleted.

projects_and_groups:
  my-group/my-project:
    remote_mirrors:
      # Mirror to GitHub using a Personal Access Token (HTTPS)
      "https://username:github_pat_12345@github.com/my-org/my-repo.git":
        enabled: true
        only_protected_branches: true
        keep_divergent_refs: false
      # Delete an old mirror
      "https://username:password@example.com/path-to/my-repo.git":
        delete: true

force_push

Set this to true within a mirror to trigger an immediate push to the remote mirror.

projects_and_groups:
  my-group/my-project:
    remote_mirrors:
      "https://username:password@example.com/path-to/my-repo.git":
        enabled: true
        auth_method: "password"
        only_protected_branches: true
        force_push: true       # Sync immediately after configuration

force_update

For each mirror, GitLabForm will compare all parameters between the config and what's in GitLab. If changes are detected or has drifted from the config, the mirror configuration in GitLab will be updated.

However, GitLabForm cannot detect changes to authentication, as GitLab returns credentials in the URL as masked. Set this key to true, in case credentials need to be changed for a mirror. For example: change username/password. Note, changing the rest of URL (i.e. protocol, path, etc.) will result in a new mirror to be created.

projects_and_groups:
  my-group/my-project:
    remote_mirrors:
      "https://usernamenew_username:passwordnew_password@example.com/path-to/my-repo.git":
        enabled: true
        auth_method: "password"
        only_protected_branches: true
        force_update: true  # Update the existing mirror with new credentials based on config above

Only use when needed

Using this key will result in the mirror being updated always. For performance reason, remove this configuration if mirror authentication/credential update is not needed. This will avoid unnecessary API calls to GitLab.

If a mirror is configured that is SSH type and auth_method is set to ssh_public_key, GitLab will automatically create a public key. This key will need to be setup in the target system so that GitLab can authenticate and push to the target. In this case, you need a way to retrieve this public key. Set this attribute to true and GitLabForm will retrieve the key and print it in the terminal.

projects_and_groups:
  my-group/my-project:
    remote_mirrors:
      "ssh://git@external-provider.com/repo.git":
        enabled: true
        auth_method: "ssh_public_key"
        print_public_key: true # Prints the key so you can add it to the target