GitHub Actions の schedule + cron で本家に追従したい
GitHub で fork したリポジトリで、フォーク元に変更があった場合にフォーク先も自動で追随させたい。
しかも GitHub だけで完結させたい。
つまり、ローカルでの cron
実行や、他の外部サーバーやサービスに依存させたくないのです。
具体的な追随方法はシンプルです。現在の master
に、フォーク元である upstream/master
の変更を rebase
で merge
して、リモート先の origin/master
に反映(push
)することでフォーク元に追随させたいのです。
この時、外部の CI サービスなどを使わずに GitHub Actions の schedule
イベントで cron
を使って変更をマージさせたいのです。
TL; DR (action、追随の同期息切れに cron)
# Follow Changes of Forked/Upstream Repository.
#
# This workflow rebase-marge changes from upstream's master to origin's master.
# - Ref:
# - https://stackoverflow.com/a/61574295/12102603 by N1ngu @ StackOverflow (EN)
# - https://qiita.com/KEINOS/items/3bcaa6cea853f6b63475 by KEINOS @ Qiita (JA)
name: Merge upstream branches
# Triggers the action as scheduled
on:
# Runs on 10 minutes past every hour(毎 n 時 10 分に実行)
schedule:
# Ref:
# - https://help.github.com/en/actions/reference/events-that-trigger-workflows#scheduled-events-schedule
# - https://crontab.guru/examples.html
# Cron format:
# ┌───────────── minute (0 - 59)
# │ ┌───────────── hour (0 - 23)
# │ │ ┌───────────── day of the month (1 - 31)
# │ │ │ ┌───────────── month (1 - 12 or JAN-DEC)
# │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT)
# │ │ │ │ │
# │ │ │ │ │
# │ │ │ │ │
# * * * * *
- cron: '10 */1 * * *'
jobs:
merge:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Merge upstream
# 以下の設定を変更してください。REPO_FORK が fork 元です。
env:
NAME: KEINOS
EMAIL: github+fork-qiita-news@keinos.com
REPO_FORK: https://github.com/yyano/Qiita-News.git
# 追従処理
run: |
git config --global user.name ${NAME}
git config --global user.email ${EMAIL}
: # git rebase をデフォルトに設定
git config --global pull.rebase merges
: # "git checkout master" は不要です。デフォルトで設定されます。
: # しかし下記の設定は重要です。過去のコミットが取得されないと、コミット歴に不統合が
: # 発生した旨のエラーが出ます。
git pull --unshallow
: # フォーク元のリポジトリをリモート先として "upstream" に命名
git remote add upstream ${REPO_FORK}
: # upstream のブランチをローカルに取得
git fetch upstream
: # marster ブランチの変更をマージし、clone 元の master に push
: # ブランチ名を main などに変更していたり、別のブランチにしている場合は注意
git checkout master
git merge --no-edit upstream/master
git push origin master
🐒 【注意点】コンフリクトとクォータ
自分の master
(origin/master
) をいじりすぎてフォーク元と異なる場合、かなりの高い頻度でコンフリクトを起こします。ブランチを切ってから作業する習慣がない(master
に直接コミットしている)場合には、余計な操作が増えるだけなのでオススメしません。
また、当然ですが、自分の master
(origin/master
) からブランチを切ると、この GitHub Action のワークフロー(YAML
ファイル)も一緒に付いてきます。
その状態でフォーク元(upstream/master
)に PR をするとワークフローも一緒に PR してしまうことになります。相手がよくわからないでマージすると、勝手にアクションが実行されエラーになるので、相手に迷惑をかけないように注意します。フォーク元には PR しないで、同期だけが必要なリポジトリで使うことをオススメします。
俺様カスタム用のリポジトリの場合、筆者は master
を original
とリネームし、orphan
ブランチを main
(もしくは master
)で作成して、追随は original
ブランチにするようにしています。
なお、GitHub Actions で無料で使える実行時間は約 33 時間/月です。これを越えると、翌月まで使えなくなります。
動作サンプル・リポジトリ
- フォーク元: https://github.com/yyano/Qiita-News
- from 「Qiitaの新着記事を見たい。なのでQiita APIを叩こう。」 @ Qiita
- フォーク先: https://github.com/KEINOS/Fork_Qiita-News
- 注釈: フォーク元がアーカイブ(閉鎖)されたことにより、現在は同期を止めています。
GitHub App
GitHub Actions でなく、サードパーティーが提供している GitHub Apps を使うなら wei/pull
も簡単。
TS; DR
設定方法
- リポジトリをフォークして、フォーク元のリポジトリ URL(
HTTPS
の.git
付き URL)をコピーしておきます。 - フォークしたリポジトリの GitHub 上にある "Actions" タブから "
set up a workflow yourself
" を選び、上記(TL; DR)の YAML の内容を設置(コピペ)します。ファイル名は、わかりやすければ何でも構いませんが、拡張子は.yml
である必要があります。 -
cron
を実行するタイミング/ユーザー/メールアドレス/フォーク元のリポジトリ URL を変更します。 -
Start commit
→Commt new file
でコミットします。
フォークしたリポジトリの ./.github/workflows
ディレクトリにワークフローが追加され、cron
で指定したタイミングで同期が始まるので、GitHub の Action タブで成功しているか確認します。
YAML ファイルの設定内容の概要
name: Merge upstream branches
on:
(以下略)
name: Merge upstream branches
on:
schedule:
# cron の設定: https://crontab.guru/examples.html
# GitHub にはユーザーごとに実行可能な時間の制限があります。合計時間が制限を
# 超えないように必要最低限のインターバルで実行するようにします。
- cron: '10 */1 * * *'
jobs:
(以下略)
name: Merge upstream branches
on:
schedule:
- cron: '10 */1 * * *'
jobs:
merge:
runs-on: ubuntu-latest
steps:
- (以下略)
name: Merge upstream branches
on:
schedule:
- cron: '10 */1 * * *'
jobs:
merge:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: (以下略)
name: Merge upstream branches
on:
schedule:
- cron: '10 */1 * * *'
jobs:
merge:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Merge upstream
run: |
# コミット/マージの実行ユーザー情報
# NAME、EMAIL は下記 env 項目で設定。
# なお、GitHub のパスワード/トークンは checkout アクションで設定済み。
git config --global user.name ${NAME}
git config --global user.email ${EMAIL}
# デフォルトで git rebase の --rebase-merges を付加
git config --global pull.rebase merges
# "git checkout master" は checkout アクションで実行済みなので不要。
# unshallow オプションで更新情報のみを pull してくる。これを設定しないと、
# アップストリーム(Fork 元)から pull するときにも、すべてのブランチデータを
# 持ってきてしまう。
git pull --unshallow
# フォーク元のリポジトリの URL をリモート先として登録し、"upstream" と名付ける。
# REPO_FORK は env で設定。
git remote add upstream ${REPO_FORK}
# アップストリームのブランチ情報を取得
git fetch upstream
# upstream/master の変更をマージして origin/master にプッシュ
git checkout master
git merge --no-edit upstream/master
git push origin master
env:
# コミット/マージを行うユーザー情報とフォーク元の git リポジトリの URL(要変更)
NAME: KEINOS
EMAIL: github+fork-qiita-news@keinos.com
REPO_FORK: https://github.com/yyano/Qiita-News.git
参考文献
- Can forks be synced automatically in gitHub? @ StackOverflow
-
$ git pull --unshallow
| git-pull @ Git 公式マニュアル -
$ git config pull.rebase merges
| git-config @ Git 公式マニュアル - 【GitHub Actions】CIを使って毎日自動でGitHubに草を生やそうwww @ Qiita
- GitHubでFork/cloneしたリポジトリを本家リポジトリに追従する @ Qiita