Initial commit
This commit is contained in:
commit
e15fa41170
2 changed files with 116 additions and 0 deletions
41
README.md
Normal file
41
README.md
Normal file
|
@ -0,0 +1,41 @@
|
|||
# Git mirror
|
||||
|
||||
Run this script to synchronize a repository once.
|
||||
|
||||
## Dependencies
|
||||
* bash
|
||||
* git
|
||||
* Tor and torify (see section "Tor")
|
||||
|
||||
## Usage
|
||||
```
|
||||
./git-mirror.sh <workdir> <leader> <follower...>
|
||||
```
|
||||
|
||||
## Get started
|
||||
Create a git repo, add remotes for the leader and the followers:
|
||||
```bash
|
||||
mkdir ~/git-mirror-my-repo; cd ~/git-mirror-my-repo
|
||||
git init
|
||||
git remote add github https://github.com/interesting/repo
|
||||
git remote add gitea ssh://git@git.example.org/me/interesting-repo
|
||||
git remote add gitlab ssh://git@git.example.com/myself/interesting-repo
|
||||
```
|
||||
|
||||
Make sure Tor is running (see section "Tor"). Then run the mirroring script:
|
||||
```bash
|
||||
cd
|
||||
git clone https://git.zeus.gent/midgard/git-mirror.git; cd git-mirror
|
||||
./git-mirror.sh ~/git-mirror-my-repo github gitea gitlab
|
||||
```
|
||||
The first remote, github is the leader. The others are followers that are updated.
|
||||
|
||||
## Tor
|
||||
The leader is fetched over Tor through torify. Make sure Tor is running, or edit the script,
|
||||
changing `torify git fetch` into `git fetch`.
|
||||
|
||||
## Motivation
|
||||
GitHub has always been hypocritical, promoting open source while keeping its own stack closed. When
|
||||
GitHub was bought by Microsoft, the author decided to stop using it. Unfortunately a lot of
|
||||
software still only has a presence on GitHub. To make it easier to work with those, this simple
|
||||
mirror script was written.
|
75
git-mirror.sh
Executable file
75
git-mirror.sh
Executable file
|
@ -0,0 +1,75 @@
|
|||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
IFS=$'\n'
|
||||
|
||||
if [[ $# -lt 3 ]]; then
|
||||
echo "Usage: $0 <workdir> <leader> <follower...>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "$1"
|
||||
|
||||
leader="$2"
|
||||
shift 2
|
||||
followers=( "$@" )
|
||||
|
||||
echo "Working directory: $PWD"
|
||||
echo "Leader remote: $leader"
|
||||
echo "Follower remotes: ${followers[*]}" | tr '\n' ' '
|
||||
echo; echo
|
||||
|
||||
torify git fetch --prune --multiple "$leader"
|
||||
git fetch --prune --multiple "${followers[@]}"
|
||||
echo
|
||||
|
||||
echo "Leader remote information:"
|
||||
git remote show -n "$leader"
|
||||
echo
|
||||
echo "Follower remotes information:"
|
||||
git remote show -n "${followers[@]}"
|
||||
echo
|
||||
|
||||
branches=( $(git show-ref | sed -n 's| refs/remotes/'"$leader"'/|\t|p') )
|
||||
echo -e "${#branches[*]} branches at leader:"
|
||||
echo "${branches[*]}"
|
||||
|
||||
IFS=$'\t'
|
||||
|
||||
errors=( )
|
||||
|
||||
error() {
|
||||
echo "XXX $1" >&2
|
||||
errors[${#errors[*]}]="$1"
|
||||
}
|
||||
|
||||
for branchspec in "${branches[@]}"; do
|
||||
set $branchspec
|
||||
leader_sha="$1"
|
||||
branch="$2"
|
||||
|
||||
for remote in "${followers[@]}"; do
|
||||
echo
|
||||
echo "Updating $remote/$branch"
|
||||
|
||||
# Prepare state to push
|
||||
follower_ref="refs/remotes/$remote/$branch"
|
||||
if ! git show-ref --verify --quiet "$follower_ref"; then
|
||||
echo "Branch doesn't exist yet at remote, creating"
|
||||
git reset --hard "$leader_sha" --
|
||||
else
|
||||
echo "Branch existed at remote, updating"
|
||||
git reset --hard "$follower_ref" --
|
||||
git merge --ff-only "$leader_sha" || { error "$remote $branch: FF not possible"; continue; }
|
||||
fi
|
||||
|
||||
git push "$remote" "+HEAD:$branch" || { error "$remote $branch: failed to push"; continue; }
|
||||
|
||||
done
|
||||
done
|
||||
|
||||
if [[ "${#errors[*]}" -ge 0 ]]; then
|
||||
echo "Errors:"
|
||||
echo "${errors[@]}"
|
||||
else
|
||||
echo "No errors."
|
||||
fi
|
Loading…
Reference in a new issue