Mirror Git repositories from an origin to a target and generate a Markdown status table. Built on go-git (no system Git required).
- Mirror all branches and tags from origin → target using a temporary bare repo
- Supports auth types: none, HTTP (username/password or token), SSH (key + optional passphrase)
- Determines default branch and latest commit automatically
- Emits a Markdown table to stdout, or replaces a placeholder in a Markdown file in-place
- YAML config with environment and secret indirection helpers
Requires Go 1.25+
go install github.com/mix-mirror/reposync/cmd/reposync@latest
Or clone and build:
git clone https://github.com/mix-mirror/reposync.git
cd reposync
go build ./cmd/reposync
-
Create a config file (e.g.
config.yml
):repos: - name: my-repo origin: url: https://github.com/org/source-repo.git auth: type: http token: env:GITHUB_TOKEN # or username/password target: url: [email protected]:org/destination-repo.git auth: type: ssh ssh_private_key_path: ~/.ssh/id_ed25519
-
Run a sync and print the Markdown table:
reposync -config config.yml
-
Optionally, update a Markdown file in-place by replacing a placeholder token:
-
Put a placeholder in any
.md
file (e.g.README.md
):<!-- REPOSYNC -->
-
Run with
-markdown
(and optionally override the placeholder token):reposync -config config.yml -markdown README.md -placeholder "<!-- REPOSYNC -->"
-
reposync -config <path> [-markdown <path>] [-placeholder <token>]
-config
(required): path to YAML config-markdown
(optional): Markdown file to update in-place; without this flag, the table is printed to stdout-placeholder
(optional): token to replace in the Markdown file (default:<!-- REPOSYNC -->
)
Exit codes: non-zero on errors (invalid config, failed fetch/push, missing placeholder, etc.).
Top-level schema:
repos: # list of repos to mirror
- name: <string> # friendly display name; falls back to repo name inferred from origin URL
origin:
url: <string> # source remote URL
auth: # auth for origin (see Auth below)
...
target:
url: <string> # destination remote URL
auth: # auth for target (see Auth below)
...
Auth options:
# Select one of the supported types
auth:
type: none | http | ssh
# HTTP auth (token preferred; else username/password)
token: <string> # commonly a Personal Access Token
username: <string>
password: <string>
# SSH auth
ssh_private_key_path: <path> # e.g. ~/.ssh/id_ed25519
ssh_private_key: | # inline key (optional alternative to *_path)
-----BEGIN OPENSSH PRIVATE KEY-----
...
-----END OPENSSH PRIVATE KEY-----
ssh_passphrase: <string> # if the key is encrypted
All string values in the YAML support expansion and simple secret indirection:
${VAR}
or$VAR
— expanded from the environmentenv:NAME
— value fromos.Getenv(NAME)
env-b64:NAME
— base64-decodeos.Getenv(NAME)
file:/path/to/secret
— file contentsfile-b64:/path/to/secret.b64
— base64-decode file contents
Examples:
# Use a token from the environment (recommended)
token: env:GITHUB_TOKEN
# Read a secret from a file
password: file:/run/secrets/git_password
# Base64-decoded variants
ssh_passphrase: env-b64:SSH_PASSPHRASE_B64
ssh_private_key: file-b64:/run/secrets/id_ed25519.b64
Columns in the generated table:
- Repository (links to target URL when available, otherwise origin)
- Default Branch
- Latest Commit Time (UTC)
- Commit (short SHA)
- Message (first line)
- Last Synced (UTC)
Example:
| Repository | Default Branch | Latest Commit Time (UTC) | Commit | Message | Last Synced |
|---|---|---|---|---|---|
| my-repo | main | 2025-09-12T10:20:30Z | `abc1234` | Initial import | 2025-09-12T10:21:05Z |
Notes:
- Repositories are sorted by most recent commit time (descending). If commit times are missing, rows fall back to name sort.
- Default branch is detected as
main
ormaster
when present; otherwise the branch with the most recent commit.
The current implementation relies on go-git defaults and does not enforce host key verification. Ensure you trust your SSH remotes or run in environments where this is acceptable.
- Run tests:
go test ./...
- Verbose logs: the binary uses a development Zap logger by default; run from a terminal to see logs.
This project is licensed under the MIT License; see the LICENSE file for details.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.