Github で fork したリポジトリの簡便な同期と運用


オープンソース(本家)の Github リポジトリ(upstream)を fork し,upstream のアップデートを 自身の Github リポジトリ (origin)に手動で取得することで簡便に同期し,運用する方法の備忘録です.upstream の対象ブランチは master (永続ブランチ)とします.なお,本家へのプルリクエストは想定せず(してもよいですが),masterupstream の純粋なコピーを維持する方針とします.

upstreamの永続ブランチ master と originの永続ブランチ master および main を用意

実際の開発は master から分岐した main を永続ブランチとして Github-flow で管理し,main から分岐した feature ブランチ(名前は適宜変更)で開発・修正を行い,Github の プルリクエスト で main に マージ します.本家の master がアップデートされたら適当なタイミングで上記を実行します.

本家のリポジトリを upstream として登録

upstream として指定する URLhttps://github.com/jsasaki-utokyo/***.git のような Clone するときの HTTPSのURLです.

git remote add upstream URL
git remote -v  # 確認

upstream を ローカルリポジトリに取得

fetch コマンドで upstream をローカルリポジトリに取得します.ローカルの作業ディレクトリ(ワークツリー)への反映は行われません(作業ディレクトリの変更なし).
fetch の引数についてはこちらが参考になります.

git fetch upstream

作業前の確認

featureブランチで作業中の場合,以下のようにmasterブランチへの切り替えができません.

$ git checkout master
error: Your local changes to the following files would be overwritten by checkout:
        ...
Please commit your changes or stash them before you switch branches.
Aborting

featureでコミットしておくか,またはスタッシュに隠しておく必要があります.まだ作業中であればスタッシュが標準選択でしょう.

git stash

後でfeatureに戻って来たら元に戻します.

git checkout feature
git stash pop

upstream を ローカル に マージ し,origin に プッシュ

現在のブランチを master にして,取得した upstream/master を ローカルの master に マージ します.次に,ローカルの masterorigin/master に プッシュ します.

git checkout master
git merge upstream/master
git push origin master

これで本家(upstream/master)と ローカルの master および origin/master の同期が完了です.

2021年8月13日以降,パスワードではなく,アクセストークンでの認証 が必要になっています.アクセストークンをコピーし,Password for 'https://***@github.com': にペーストします.何も表示されませんが,そのままEnterを入力します.アクセストークンは1ヶ月有効ですが,それが表示されたページから移動すると再表示できません.Githubにログインした状態で こちら で再作成表示できます.

今後,同期を継続するには,本家がアップデートされる度に,同じように git fetch upstream でローカルリポジトリに upstream/master を取得し,mergepush の一連の作業を実行します.

さらに tag を同期

このままでは tag が同期されませんので,tag が存在する場合は以下を実行します.

git pull upstream master --tags
git push origin master --tags

master を main に マージ

更新された mastermain にマージし,プッシュします.main ブランチが存在しない初回は master ブランチにおいて,git checkout -b main により,master から 分岐した main ブランチを作成します.

git checkout main
git merge master
git push origin main

コンフリクトが発生する場合は,後述の通り対応します.また,初回git remote set-head origin main を実行し,リモートリポジトリ origin のデフォルトブランチ を main にしておきます.Github でもデフォルトブランチを main に変更する手続きが必要のようです.

更新された main ブランチを feature ブランチに マージ

feature ブランチで作業中に(コミットまたはスタッシュしておきます) upstream/master の更新を取得して main ブランチが更新された場合を想定し,その main ブランチを feature ブランチに マージ します.この作業が必要なのは main から feature へ分岐後に main が更新された場合です.main の更新がない場合は次の プルリクエスト で main へ マージ に飛びます.

git checkout feature
git merge main

ターミナルに CONFLICT (content): Merge conflict in coawst.bash のように CONFLICT で始まる行が現れたら,その行で示されたファイル中にコンフリクト(競合)の内容が書き込まれています.そのファイルをエディタで開き,適切に編集します.
以下のコンフリクト内容の例では <<<<<<< HEAD から ======= までが feature の,======= から >>>>>>> main までが main の内容となっており,両者に競合があることが分かります.

<<<<<<< HEAD
#export   NETCDF_CONFIG=/usr/bin/nc-config
=======
export   NETCDF_CONFIG=/usr/bin/nf-config
#export   NETCDF_CONFIG=/vortexfs1/apps/impistack-1.0/bin/nf-config
>>>>>>> main

これを例えば以下のように不要な行を削除する等,適切に編集します.この例では main を残しました.

export   NETCDF_CONFIG=/usr/bin/nf-config
#export   NETCDF_CONFIG=/vortexfs1/apps/impistack-1.0/bin/nf-config

また,以下のようなCONFLICTにおいて,削除すると決めた場合は git rm で,残す場合は git add で対処します.以下は消去の場合です.

CONFLICT (modify/delete): mydir/myfile deleted in main and modified in HEAD. Version HEAD of mydir/myfile left in tree.

git rm mydir/myfile 

編集が完了したら 更新ファイルを add した後,コミット します.コミット時のコメントをファイル毎に変える必要がなければ,すべてのファイルへの対応完了後にまとめてコミットしても構いません.自動マージ可能なファイル(自身では編集しなかったファイル)もコミットする必要があります.

git add file_name  # ファイル毎に
git add -u         # 更新されたファイルをまとめて
git commit -m "comment" 

プルリクエスト(プルリク) で feature を main にマージ

feature での作業が完了し,main に マージ するときは変更理由等をわかりやすく履歴として残すため Github の プリリクエスト を用いることとします.まず,Github (origin) に feature を プッシュ します.

git push origin feature

このプッシュ直後に Github に移ると,Compare & pull request のボタンが一番上に現れていると思います.これをクリックします.現れていない場合は pull request を探して,クリックください.
左側にマージする先,右側に今プッシュしたブランチが現れ,左向きの矢印 ← で繋がれています.左側が目的のマージ先になっているか確認して適切に設定します.おそらくデフォルトは upstream の master リポジトリになっていると思いますので,それが意図したものでなければ修正します.ここでは origin main にしました.
その下のタイトルとコメントを入力し,Create pull request をクリックします.
コンフリクトがなければ下に現れる Merge pull request をクリックし,続けて Confirm merge をクリックします.
上記の流れで行う限り,コンフリクトはローカルで main を feature にマージしたところで解消されているはずですので,この プルリクエスト ではコンフリクトは起こらないはずです.この記事での プルリクエスト の目的はあくまで改変の記録をわかりやすく管理するためです.

ローカルリポジトリの更新

origin/main が更新されましたので,これをローカルリポジトリに反映させます.さらにローカルリポジトリにおいて,この更新された main から feature が分岐するようにします.この過程ではコンフリクトは発生せず,Fast-forward merge となります.

git checkout main
git pull origin main
git checkout feature
git merge main

スパコン専用ブランチの運用

スパコンのローカルリポジトリには永続ブランチの main とスパコン専用ブランチ sc を持たせ,main を sc にマージするものとします(sc を main にマージする場合は上記の通り,Githubのプルリクで対応するものとします).main をチェックアウトし,Github (origin) の main から更新を取り込み,sc にマージします.

git checkout main
git pull origin main
git checkout sc
git merge main

これまでと同様にコンフリクトに対応し,Github (origin) にプッシュします.

git push origin sc

さらに origin/main に取り込む場合は Github のプルリクで対応します.

デフォルトブランチの変更

Githubでデフォルトブランチを変更するには左上のブランチのボタンをクリックし,下端の View all branches をクリックし,デフォルトブランチバー右端の ボタンをクリックし,次の画面でも ボタンをクリックして設定を進めます.

例えば,Githubのデフォルトブランチを master から main に変更し,ローカルブランチも同様に変更したつもりでも以下のように変わらないことがありました.

remotes/origin/HEAD -> origin/master

これを remotes/origin/HEAD -> origin/mainに変更するには main ブランチにおいて,以下のようにします.

git remote set-head origin main

feature のプッシュを取り消したい場合

こちらこちらを参考に, feature において git reset --soft HEAD^でローカルの変更を残しながらコミットを取り消し,git push origin +feature で origin の feature ブランチへ強制的にプッシュします.なお +feature はfeatureブランチ名の先頭に + を付けており,これが強制を意味します.

Github に ssh 接続

ディレクトリ ~/.ssh/ に移動し,秘密鍵と公開鍵を作成します.-t: 暗号化方式を指定,-b: 暗号化強度を指定,-C: コメントを設定 です.

ssh-keygen -t rsa -b 4096 -C "[email protected]"

秘密鍵の入力を求められますが,デフォルトとするため,何も入力せずに Enter を押します.続いて passphrase を2回入力します.

Github にログインし,右上ボタンのプルダウンで SettingsSSH and GPG keys に移動します.右上の New SSH key ボタンをクリックし,Title (ロカールマシン名等,適当な名前)と作成した公開鍵を Key に貼り付け,Add SSH key をクリックします.

秘密鍵を ssh-agent に登録する

passphrase を聞かれますので,入力します.

ssh-add ~/.ssh/id_rsa

以下を実行して,passphrase を入力し,Hi your_account! You've successfully authenticated, but GitHub does not provide shell access. のようなメッセージが現れれば成功です.

参考資料