From 41b0b69231a0a3428f3874f3cf3b957eb8580100 Mon Sep 17 00:00:00 2001 From: Midgard Date: Mon, 23 May 2022 14:35:29 +0200 Subject: [PATCH] Improve --- README.md | 29 +++++++++++++++++++++++----- git-mirror.sh | 53 +++++++++++++++++++++++++++++++++++---------------- 2 files changed, 61 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index f5f59a2..1be2945 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,19 @@ Run this script to synchronize a repository once. +## Quick start +Clone git-mirror somewhere on your system. Create a script like the following in the directory of +the repository you want to keep mirrored, and configure the variables: +```bash +#!/bin/sh + +mirror="$HOME/path/to/git-mirror/git-mirror.sh" +leader="github" # Name of the leader remote +followers="origin" # Space separated list of names of follower remotes + +exec "$mirror" --notor "$(dirname "$0")" $leader $followers +``` + ## Dependencies * bash * git @@ -12,7 +25,7 @@ Run this script to synchronize a repository once. ./git-mirror.sh ``` -## Get started +## How to use Create a git repo, add remotes for the leader and the followers: ```bash mkdir ~/git-mirror-my-repo; cd ~/git-mirror-my-repo @@ -33,15 +46,21 @@ The first remote, `github` in this case, is the leader. The others are followers If you want to do this conveniently every now and then, you can create a script like this in your repository's directory: ```bash -#!/bin/bash -mirror="$HOME/git-mirror/git-mirror.sh" -here="$(dirname "$0")" -exec "$mirror" --notor "$here" github origin +#!/bin/sh + +mirror="$HOME/path/to/git-mirror/git-mirror.sh" +leader="github" # Name of the leader remote +followers="origin" # Space separated list of names of follower remotes + +exec "$mirror" --notor "$(dirname "$0")" $leader $followers ``` Make sure to make it executable, and gitignore it when relevant. A good idea may be to choose an arcane name, like `update--.sh`, and add it to a global gitignore file in `~/.gitignore`. +## Caveat +If a branch has diverged, it will not be updated. Update it manually in that case. + ## Automate To automate mirroring, run it periodically, for example once every 30 minutes. On a *NIX you could use cron for this, or write a system service definition for your system supervisor (such as diff --git a/git-mirror.sh b/git-mirror.sh index 81dab19..ed5023f 100755 --- a/git-mirror.sh +++ b/git-mirror.sh @@ -1,7 +1,7 @@ #!/bin/bash # git-mirror: Mirror a git repo in leader-followers configuration -# Copyright © 2019 Midgard +# Copyright © 2019-2022 Midgard # # This program is free software: you can redistribute it and/or modify it under the terms of the # GNU Affero General Public License as published by the Free Software Foundation, either version 3 @@ -60,10 +60,15 @@ echo "${branches[*]}" IFS=$'\t' +up_to_date=( ) errors=( ) error() { - echo "XXX $1" >&2 + tput bold + tput setaf 1 + echo -n "XXX" + tput sgr0 + echo " $1" >&2 errors[${#errors[*]}]="$1" } @@ -84,33 +89,49 @@ for branchspec in "${branches[@]}"; do if [ "$branch" = HEAD ]; then continue; fi for remote in "${followers[@]}"; do - echo - echo "Updating $remote/$branch" follower_ref="refs/remotes/$remote/$branch" + msg="" if ! ref_exists "$follower_ref"; then - echo "Branch doesn't yet exist at remote, creating" - git checkout "$leader_sha" -- - git push "$remote" "+HEAD:$branch" || { error "$remote $branch: failed to push"; continue; } - - elif is_ref_at_sha "$follower_ref" "$leader_sha"; then - echo "Already up to date" - + msg="Creating $remote/$branch" + elif ! is_ref_at_sha "$follower_ref" "$leader_sha"; then + msg="Updating $remote/$branch" else - echo "Branch exists at remote, updating" - git checkout "$follower_ref" -- - git merge --ff-only "$leader_sha" || { error "$remote $branch: FF not possible"; continue; } - git push "$remote" "+HEAD:$branch" || { error "$remote $branch: failed to push"; continue; } + up_to_date[${#up_to_date[*]}]="$remote/$branch" + fi + + if [[ -n $msg ]]; then + echo + tput bold + echo "$msg" + tput sgr0 + + git push "$remote" "+$leader_sha:refs/heads/$branch" || { error "$remote $branch: failed to push"; continue; } fi done done +if [[ "${#up_to_date[*]}" -gt 0 ]]; then + echo + echo "Already up to date:" + echo "${up_to_date[@]}" +fi + echo if [[ "${#errors[*]}" -gt 0 ]]; then + tput bold + tput setaf 1 echo "Errors:" - echo "${errors[@]}" + tput sgr0 + tput bold + for (( i=0; i < ${#errors[*]}; i++ )); do + echo "${errors[$i]}" + done + tput sgr0 + + exit 1 else echo "No errors." fi