Something went wrong. Try again.
Bash script that mirrors repositories from my private Forgejo instance
Something went wrong. Try again.
2.5 kB · 86 lines · Created 1y ago
Shell
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687#!/usr/bin/env bash
# This script mirrors repositories from my private Forgejo instance to any# external Git hosts (in this case, Tangled.)## 1. Set `FORGEJO_DATA_DIR` to your Forgejo's repositories directory,# `STATE_FILE` is how this script takes note of changes.## 2. Create a repository (e.g. mary/mirror-config, configurable via# `CONFIG_REPO_PATH`) and write a `repos.txt` file containing the# repositories you want to mirror:## mary/pkg-protobuf=git@tangled.sh:mary.my.id/pkg-protobuf# # comments and blank lines are ignored## 3. Generate a new SSH key, or use your existing one, and set `GIT_SSH_COMMAND`# to make use of it.## 4. Run this script as a cron job.
set -euo pipefail
GIT_SSH_COMMAND="ssh -i ~/.ssh/forgejo_mirror_bot -o StrictHostKeyChecking=no"export GIT_SSH_COMMAND
STATE_FILE="$HOME/.forgejo-mirror-state"FORGEJO_DATA_DIR="$HOME/dockers/data/forgejo/git/repositories"CONFIG_REPO_PATH="$FORGEJO_DATA_DIR/mary/mirror-config.git"
# Read repo mapping from configcd "$CONFIG_REPO_PATH"REPOS=$(git show HEAD:config.txt)
# Load previous statedeclare -A last_hashesif [[ -f "$STATE_FILE" ]]; then while IFS='=' read -r repo hash; do last_hashes["$repo"]="$hash" done < "$STATE_FILE"fi
# Prepare new state and track if anything changeddeclare -A new_hasheschanges_made=false
# Process each repo mappingwhile IFS= read -r line; do # Skip empty lines and comments [[ -z "$line" || "$line" =~ ^[[:space:]]*# ]] && continue
# Parse source=target format if [[ "$line" =~ ^([^=]+)=(.+)$ ]]; then source_repo="${BASH_REMATCH[1]}" target_url="${BASH_REMATCH[2]}"
repo_path="$FORGEJO_DATA_DIR/$source_repo.git" if [ -d "$repo_path" ]; then cd "$repo_path" current_hash=$(git show-ref | sha256sum | cut -d' ' -f1) new_hashes["$source_repo"]="$current_hash"
if [[ "${last_hashes[$source_repo]:-}" != "$current_hash" ]]; then echo "[-] Mirroring $source_repo -> $target_url (changed)" git push --mirror "$target_url" || { echo "Failed to mirror $source_repo" continue } changes_made=true else echo "[-] Skipping $source_repo (no changes)" fi else echo "[-] Repository $source_repo not found at $repo_path" fi else echo "[-] Invalid format: $line (expected source=target)" fidone <<< "$REPOS"
# Only save new state if there were changesif [[ "$changes_made" == true ]]; then > "$STATE_FILE" for repo in "${!new_hashes[@]}"; do echo "$repo=${new_hashes[$repo]}" >> "$STATE_FILE" donefi