Skip to content

Instantly share code, notes, and snippets.

@mathieucarbou
Last active June 1, 2024 17:45
Show Gist options
  • Save mathieucarbou/96ab30024f0d3fb44cac970219d23efc to your computer and use it in GitHub Desktop.
Save mathieucarbou/96ab30024f0d3fb44cac970219d23efc to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash
#
# Setup automatic sync from a Github upstream repository to a fork
# - a branch "actions" will be created (or re-used) to hold the Github action to run
# - sync is done each hour
# - branch 'actions' needs to be the default branch of your fork (=> settings)
# - the script is able to both create and update and rewrite the sync script if you modify this script file
#
# Author: Mathiue Carbou
# Date: April 2021
#
# Notes:
# - Github bug: action is not shown if pushed first before changing the default branch
#
# Good luck...
#
# BLOG: https://blog.mathieu.photography/post/649318432483033088/automatic-fork-syncing-with-github
#
usage() {
echo "github-fork-sync.sh <fork> <upstream> <branch-to-sync> <domain>"
echo "Example: github-fork-sync.sh mathieucarbou/terracotta-platform Terracotta-OSS/terracotta-platform master"
echo "Example: github-fork-sync.sh mathieucarbou/terracotta-platform Terracotta-OSS/terracotta-platform master github.com"
exit 1
}
if [ "$#" -ne 3 ] && [ "$#" -ne 4 ]; then
usage
fi
fork=$1
upstream=$2
branch=$3
domain="github.com"
tmp_dir=$(mktemp -d -t git)
echo "Temporary directory: $tmp_dir"
if [ "$#" -eq 4 ]; then
domain=$4
fi
# quic and fast clone
git clone --depth=1 git@$domain:$fork.git $tmp_dir
if [ $(git -C $tmp_dir branch --show-current) != "actions" ]; then
# default repository branch is NOT 'actions'
git -C $tmp_dir checkout actions
if [ $? -eq 1 ]
then
# branch 'actions' does not exist
git -C $tmp_dir checkout --orphan actions
git -C $tmp_dir rm -rf .
git -C $tmp_dir commit --allow-empty -am "root"
git -C $tmp_dir push origin actions
fi
echo ""
echo "========================================================"
echo ">>> WARNING <<<"
echo "========================================================"
echo "Please go to: https://$domain/$fork/settings/branches"
echo "Change your default branch to 'actions'"
echo "Press a key to continue."
echo "========================================================"
read
fi
# create workflow script
mkdir -p $tmp_dir/.github/workflows
cat << EOF > $tmp_dir/.github/workflows/fork-sync.yml
name: "Fork Sync"
on:
schedule:
- cron: '0 */2 * * *'
workflow_dispatch:
jobs:
sync-$branch:
runs-on: ubuntu-latest
name: "Sync from $upstream@$branch"
steps:
- name: "Checkout: $branch"
uses: actions/checkout@v2
with:
ref: $branch
token: \${{ github.token }}
- name: "Update: $branch"
id: sync-$branch
uses: mathieucarbou/Fork-Sync-With-Upstream-action@fork-sync
with:
domain: '$domain'
upstream_repository: $upstream
upstream_branch: $branch
target_branch: $branch
git_pull_args: --ff-only
# git_push_args: --force
- name: Timestamp
run: date
EOF
git -C $tmp_dir rm .github/workflows/sync.yml # remove old workflow script
git -C $tmp_dir add .github/workflows/fork-sync.yml
git -C $tmp_dir commit -am "fork-sync.yml"
git -C $tmp_dir push origin actions
# cleanup
rm -f -r $tmp_dir/.git
rm -f -r $tmp_dir
echo ""
echo "=========================================================================="
echo ">>> WARNING <<<"
echo "=========================================================================="
echo "Please go to: https://$domain/$fork/actions"
echo "Run the Sync task manually. It will run each hour automatically."
echo "=========================================================================="
@mathieucarbou
Copy link
Author

mathieucarbou commented Apr 24, 2021

GitHub does not provide a quick and fast way to automatically sync the branches of a fork with the upstream repository.

Until now... With GitHub actions!

If you don’t care about the HOW, then here are the quick steps:

  1. Download the github-fork-sync.sh script from my Gist
  2. Make it executable (chmod a+x)
  3. Run it: ./github-fork-sync.sh
  4. You will see the help
❯  ./github-fork-sync.sh
github-fork-sync.sh <fork> <upstream> <branch-to-sync>
Example: github-sync.sh mathieucarbou/terracotta-platform Terracotta-OSS/terracotta-platform master

image

The script takes 3 parameters:

  1. Your fork
  2. The upstream repository
  3. The branch to sync

The script will install a Gihub Action in your repository that will be run each hour by default.
The update takes about 20 seconds to run.
You will also be able to manually trigger an update.
This action will be pushed into a branch called "actions". This branch will be automatically created.

IMPORTANT: Follow the script output!

The script pauses at one point and asks you to go in your GiHub fork to change the default branch name. This is sadly required because GitHub has currently a bug preventing to discover the pushed GitHub actions not in a default branch.

Once the steps are done, you will be able to go in your fork and trigger an automatic update by clicking on the Run workflow button.

Screen Shot 2021-04-24 at 00 19 33

The GitHub action tab will show you the scheduled executions:

Screen Shot 2021-04-24 at 00 13 21

And you can even edit the action script to support the update of several branches in a fork. Example here.

Screen Shot 2021-04-24 at 00 13 41

If you want to have a look at the integration in my forks, you can go there.

@mathieucarbou
Copy link
Author

In the script, you can replace uses: mathieucarbou/Fork-Sync-With-Upstream-action@fork-sync by your own fork of https://github.com/aormsby/Fork-Sync-With-Upstream-action.

I am pointed to my fork so that I can control any updates done in the upstream repository. Moreover, I am syncing the master branch from https://github.com/aormsby/Fork-Sync-With-Upstream-action to my fork, but the script is pointing to my fork-sync, which is actually the one used, so that I can manually move code from master to fork-sync as I need.

This is for security reasons.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment