Skip to main content

mirror-tool

A tool for maintaining Git subtree mirrors.

PyPI Docker Repository on Quay

Installation

Install the mirror-tool package from PyPI.

pip install mirror-tool

Alternatively, run mirror-tool directly as a container image.

Note that you must expose the git repo you want to manage as a directory to the container as the current working directory, as well as setting any needed environment variables if GitLab features are enabled. The details of how to do this are beyond the scope of this README, but an example command may look like:

podman run \
  -v $PWD:/workdir:Z -w /workdir \
  quay.io/rmcgover/mirror-tool:latest \
  update-local

Usage

mirror-tool has the following subcommands. Please install the tool and run with --help for complete documentation on the available commands and options.

mirror-tool validate-config

Verify that .mirror-tool.yaml in the current directory, or a specified configuration file, is valid.

Exits with a 0 exit code if and only if a valid config file was found.

mirror-tool update-local

For each mirror defined in the config file, create a subtree merge commit updating that mirror.

By default, this will not create any commits if there are no changes to be made. It can be forced to create a commit by using the --allow-empty argument.

mirror-tool update

Perform the same updates as update-local, but also push the commit(s) to any configured remote targets.

Currently, GitLab is the only supported target. See the configuration reference below for more information about GitLab integration.

When using this command to push to GitLab, it is recommended to run it from within a GitLab CI/CD pipeline. The command will use predefined environment variables in the CI environment to determine how to connect to GitLab. If used in other contexts, it will be necessary to explicitly set many environment variables.

mirror-tool promote

For any merge requests previously created by update, create additional merge request(s) to promote the same changes to other branch(es) as defined in config.

This command can be used to implement a multi-tiered deployment/update workflow, for example:

  • Whenever mirrored repos change, create an MR updating them (via mirror-tool update), targeting testing branch.
  • Perform some pre- or post-merge testing on that MR by some means (outside the scope of mirror-tool).
  • After the MR is submitted to testing branch, create a new MR promoting the same changes to stable branch (via mirror-tool promote).

The command only operates on changes previously created via mirror-tool update.

Like update, GitLab is currently the only supported target for this command.

mirror-tool gitlab-ci-yml

Generates a .gitlab-ci.yml snippet with a recommended configuration for integrating mirror-tool into a GitLab pipeline.

It is recommended to put the generated config into its own YAML file and use the include keyword to include that file.

The output of this command is influenced by the .mirror-tool.yaml config. When changing configuration elements relating to GitLab, it is a good idea to re-run this command.

Configuration

mirror-tool requires a configuration file. By convention, this should be placed at .mirror-tool.yaml at the top level of your superproject repository.

The following example demonstrates the available configuration options.

# Define the repositories to mirror.
mirror:
- url: https://github.com/org/repo1
  ref: refs/heads/master
  dir: repo1

- url: https://github.com/org/repo2
  ref: refs/heads/main
  dir: repo2

# Git configuration to be applied when mirror-tool creates commits.
# Any arbitrary config can be set, but this is most commonly needed
# just to set the name/email on merge commits.
git_config:
  user.name: "mirror-tool"
  user.email: "noreply@example.com"

# Message for generated commits.
# This is a Jinja template.
commitmsg: |-
  Merge {{commits[0].revision_abbrev}} to {{mirror.dir}}

  {{commits|length}} commit(s) are being merged.

  {% for commit in commits %}
  - {{ commit.revision_abbrev }} {{ commit.subject }}
  {%- endfor %}

# Configures the GitLab merge request integration.
gitlab_merge:
  # If enabled, the update command will create/update a GitLab
  # merge request whenever a mirrored repo is updated.
  enabled: true

  # Token used to authenticate with GitLab.
  #
  # Currently, this token must always be of the format '$SOME_VARIABLE',
  # and the token will be accessed from that environment variable at
  # runtime. If running from a GitLab CI/CD pipeline, this should be
  # set as a protected CI variable.
  token: $GITLAB_MIRROR_TOKEN

  # Source branch used for merge requests.
  # WARNING: update will do force pushes to this branch!
  src: latest

  # Target branch used for merge requests.
  # The following example supposes that the target branch is used
  # to perform some kind of deployment.
  dest: deploy

  # Title for the merge request.
  # This is a Jinja template.
  title: "Deploy changes [{{ datetime_day }}]"

  # Any desired labels to add onto the merge request.
  labels:
  - deploy

  # Description for the merge request.
  # This is a Jinja template.
  description: |-
    Automated update of dependencies generated by
    {{ env.CI_JOB_URL }}.

    Submitting this merge request will trigger a deployment.

  # Comment(s) to be added when a merge request is created or updated.
  # Can be used to ping reviewers.
  # If omitted, comments won't be added.
  # These are Jinja templates.
  comment:
    create: "@some-team: please review and submit."
    update: "@some-team: merge request has been updated, please re-review."

# Configures GitLab promotion between branches.
# A list of (src, dest) branch pairs with other config.
# Most config has the same meaning as in gitlab_merge.
gitlab_promote:
- src: stage
  dest: prod
  title: "Promote from stage to prod [{{datetime_day}}]"
  token: $GITLAB_MIRROR_TOKEN
  labels:
  - promote
  description: |-
    Automated promotion of {{ src_mr.web_url }} to prod.

Jinja context

Some configuration elements are described above as Jinja templates. The following variables are available for use within the templates:

env (dict)

  • All environment variables at the time mirror-tool is invoked.
  • If running in GitLab CI/CD, can be used to access the CI/CD variables.
  • Example: {{ env.CI_JOB_URL }} => https://gitlab.example.com/someteam/somerepo/-/jobs/6366493

datetime_iso8601 (str)

  • Current UTC date/time, in ISO8601 format, with seconds precision.
  • Example: 2022-05-10T05:28:26Z

datetime_minute (str)

  • Current UTC date/time, with minutes precision.
  • Example: 2022-05-10 05:28

datetime_day (str)

  • Current UTC date.
  • Example: 2022-05-10

datetime_week (str)

  • Current UTC year and week of year.
  • Example: 2022wk19 for week 19 of 2022.

updates (list[UpdateInfo]) (update only)

In most Jinja contexts for the update and update-local commands, this is a list of objects of the following form:

UpdateInfo(
  mirror=Mirror(
    url="https://github.com/rohanpm/mirror-tool",
    ref="refs/heads/main",
    dir="mirror-tool"
  ),

  # Objects representing commits included in the update, starting
  # with the most recent.
  #
  # If there is a large number of commits being handled, some may be
  # elided from this list.
  commits=[
    Commit(
      revision="472b7797518b963f8ab381c39858c18b2b784c2e",
      revision_abbrev="472b779",
      author_name="Rohan McGovern",
      author_email="rohan@mcgovern.id.au",
      author_email_local="rohan",
      author_datetime=datetime.datetime(2022, 5, 26, 0, 24, 37),
      committer_name="Rohan McGovern",
      committer_email="rohan@mcgovern.id.au",
      committer_email_local="rohan",
      committer_datetime=datetime.datetime(2022, 5, 26, 0, 37, 37),
      subject="Raise test coverage to 100%",
      body="Do this, that and some other\nthings as well.",
      url="https://github.com/rohanpm/mirror-tool/commit/472b7797518b963f8ab381c39858c18b2b784c2e",
    ),
    ...,
  ],

  # Total number of commits in the update (may be more than len(commits)
  # if some were elided).
  commit_count=4,

  # Number of commits omitted from 'commits' object.
  # For example, if an update pulled 200 commits, only the most recent 20
  # may appear in 'commits', and this value will be set to 180.
  commit_elided_count=0,
)

In the Jinja context for commitmsg, as only a single update is being processed, updates is not defined. Instead, all of the fields shown above under UpdateInfo are directly included onto the context.

src_mr (dict) (promote only)

A merge request object which is now being promoted; i.e. a merge request previously created by mirror-tool and submitted to one branch, and now being promoted by mirror-tool to another branch.

The format of this object can be found in the GitLab API docs.

Only available for the promote command.

License

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

Metadata

Release files for mirror-tool 2025.8

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mirror-tool 2025.8
File Size Uploaded
mirror_tool-2025.8.tar.gz 58.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for mirror-tool 2025.8
File Interpreter ABI Platform
mirror_tool-2025.8-py3-none-any.whl Python 3 none any Details

Total release size: 104.7 kB

Release files / mirror_tool-2025.8.tar.gz

Download URL mirror_tool-2025.8.tar.gz
Size 58.1 kB
Tags Source
SHA-256 checksum
How to use checksums
3817d1911181a0381ced4e3de8281096425287c66d7503083bfb149f3c132a0e
BLAKE2b-256 checksum
How to use checksums
1b115010acfefcd64eccc63f8fc2b861ef62ddc2afbd263b95fa43ff9292bfbf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.12.9

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 14, 2025.

Transparency log

Release files / mirror_tool-2025.8-py3-none-any.whl

Download URL mirror_tool-2025.8-py3-none-any.whl
Size 46.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6a0a6b6d61a50347ed4da61c18f878ab93cb80592cce1eeb8d292be368d9470c
BLAKE2b-256 checksum
How to use checksums
3a0d74ad48dc4c9f9b2f8b272fda905621e56a2ffa78b42558ed367494035b3c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.12.9

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 14, 2025.

Transparency log

Release history Release notifications | RSS feed

This release

2025.8 This release

2 release files

2025.3

2 release files

2024.9

2 release files

2023.5

2 release files

1.0.0

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page