Improve
This commit is contained in:
parent
655f5c2fb4
commit
41b0b69231
2 changed files with 61 additions and 21 deletions
29
README.md
29
README.md
|
@ -2,6 +2,19 @@
|
||||||
|
|
||||||
Run this script to synchronize a repository once.
|
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
|
## Dependencies
|
||||||
* bash
|
* bash
|
||||||
* git
|
* git
|
||||||
|
@ -12,7 +25,7 @@ Run this script to synchronize a repository once.
|
||||||
./git-mirror.sh <workdir> <leader> <follower...>
|
./git-mirror.sh <workdir> <leader> <follower...>
|
||||||
```
|
```
|
||||||
|
|
||||||
## Get started
|
## How to use
|
||||||
Create a git repo, add remotes for the leader and the followers:
|
Create a git repo, add remotes for the leader and the followers:
|
||||||
```bash
|
```bash
|
||||||
mkdir ~/git-mirror-my-repo; cd ~/git-mirror-my-repo
|
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
|
If you want to do this conveniently every now and then, you can create a script like this in your
|
||||||
repository's directory:
|
repository's directory:
|
||||||
```bash
|
```bash
|
||||||
#!/bin/bash
|
#!/bin/sh
|
||||||
mirror="$HOME/git-mirror/git-mirror.sh"
|
|
||||||
here="$(dirname "$0")"
|
mirror="$HOME/path/to/git-mirror/git-mirror.sh"
|
||||||
exec "$mirror" --notor "$here" github origin
|
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
|
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`.
|
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
|
## Automate
|
||||||
To automate mirroring, run it periodically, for example once every 30 minutes. On a *NIX you could
|
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
|
use cron for this, or write a system service definition for your system supervisor (such as
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# git-mirror: Mirror a git repo in leader-followers configuration
|
# 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
|
# 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
|
# GNU Affero General Public License as published by the Free Software Foundation, either version 3
|
||||||
|
@ -60,10 +60,15 @@ echo "${branches[*]}"
|
||||||
|
|
||||||
IFS=$'\t'
|
IFS=$'\t'
|
||||||
|
|
||||||
|
up_to_date=( )
|
||||||
errors=( )
|
errors=( )
|
||||||
|
|
||||||
error() {
|
error() {
|
||||||
echo "XXX $1" >&2
|
tput bold
|
||||||
|
tput setaf 1
|
||||||
|
echo -n "XXX"
|
||||||
|
tput sgr0
|
||||||
|
echo " $1" >&2
|
||||||
errors[${#errors[*]}]="$1"
|
errors[${#errors[*]}]="$1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,33 +89,49 @@ for branchspec in "${branches[@]}"; do
|
||||||
if [ "$branch" = HEAD ]; then continue; fi
|
if [ "$branch" = HEAD ]; then continue; fi
|
||||||
|
|
||||||
for remote in "${followers[@]}"; do
|
for remote in "${followers[@]}"; do
|
||||||
echo
|
|
||||||
echo "Updating $remote/$branch"
|
|
||||||
|
|
||||||
follower_ref="refs/remotes/$remote/$branch"
|
follower_ref="refs/remotes/$remote/$branch"
|
||||||
|
|
||||||
|
msg=""
|
||||||
if ! ref_exists "$follower_ref"; then
|
if ! ref_exists "$follower_ref"; then
|
||||||
echo "Branch doesn't yet exist at remote, creating"
|
msg="Creating $remote/$branch"
|
||||||
git checkout "$leader_sha" --
|
elif ! is_ref_at_sha "$follower_ref" "$leader_sha"; then
|
||||||
git push "$remote" "+HEAD:$branch" || { error "$remote $branch: failed to push"; continue; }
|
msg="Updating $remote/$branch"
|
||||||
|
|
||||||
elif is_ref_at_sha "$follower_ref" "$leader_sha"; then
|
|
||||||
echo "Already up to date"
|
|
||||||
|
|
||||||
else
|
else
|
||||||
echo "Branch exists at remote, updating"
|
up_to_date[${#up_to_date[*]}]="$remote/$branch"
|
||||||
git checkout "$follower_ref" --
|
fi
|
||||||
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; }
|
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
|
fi
|
||||||
|
|
||||||
done
|
done
|
||||||
done
|
done
|
||||||
|
|
||||||
|
if [[ "${#up_to_date[*]}" -gt 0 ]]; then
|
||||||
|
echo
|
||||||
|
echo "Already up to date:"
|
||||||
|
echo "${up_to_date[@]}"
|
||||||
|
fi
|
||||||
|
|
||||||
echo
|
echo
|
||||||
if [[ "${#errors[*]}" -gt 0 ]]; then
|
if [[ "${#errors[*]}" -gt 0 ]]; then
|
||||||
|
tput bold
|
||||||
|
tput setaf 1
|
||||||
echo "Errors:"
|
echo "Errors:"
|
||||||
echo "${errors[@]}"
|
tput sgr0
|
||||||
|
tput bold
|
||||||
|
for (( i=0; i < ${#errors[*]}; i++ )); do
|
||||||
|
echo "${errors[$i]}"
|
||||||
|
done
|
||||||
|
tput sgr0
|
||||||
|
|
||||||
|
exit 1
|
||||||
else
|
else
|
||||||
echo "No errors."
|
echo "No errors."
|
||||||
fi
|
fi
|
||||||
|
|
Loading…
Reference in a new issue