Previous Post | Top | Next Post |
TOC
Gitを使う際に、アップストリームのレポの更新に合わせて、 自分がフォークしたレポを如何にスムーズに更新していくかは、 フォークしたレポの開始方法やブランチ名の設定や実行するコマンド 手順に複数のアプローチや複数の対応方法があるだけに、いつも 混乱して悩まされます。
備忘録を兼ねて、アップストリームがGITHUBを使っている 場合を軸にメモを作成します。
世の流れで、デフォルトブランチ名に「master
」ではなく「main
」等を使うことが最近増えています。その場合は適宜以下も読み替えてください。
GITを使うフォークの管理手順(基本)
簡単のために以下の前提を置きます。(追跡=tracking)
- 他人が管理する、アップストリームのリモートのレポ名を、「
upstream
」(任意名ですが慣習名)とします。 - 他人が管理する、アップストリームのリモートのレポ上の「
master
」ブランチを追跡します。(コピー元) - 自分が管理する、フォークしたリモートのレポ名を、「
origin
」とします。 - 自分が管理する、フォークしたリモートのレポ上の「
master
」ブランチに追跡コピーを保管します。(コピー先) - アップストリームのレポにあるbranch名やtag名とぶつかるbranch名やtag名を、フォークしたレポに勝手に作らないようにします。
この際の、GITを使うフォークの管理手順は以下です。
-
アップストリームのレポのGITHUBウエッブページで「Fork」をクリックして、 自分のアカウントにフォークされたリモートのレポを作成
-
フォークされたレポをローカルに「
git clone
」して、ローカルのレポを作成$ git clone git@github.com:my_name/project_name.git ; cd project_name
-
自分が書き換える開発ブランチ(ここでは「
devel
」)を作成$ git checkout -b devel
-
ファイルを編集し、開発ブランチにコミット
-
アップストリームのリモートのレポをローカルにリモート「
upstream
」として追加。$ git remote add upstream https://github.com/upstream_name/project_name.git
-
フォークされたレポの「
master
」ブランチをアップストリームのレポの「master
」ブランチに同期$ git checkout master ; git fetch -p upstream ; git pull upstream master ; git push origin master
-p
は--prune
のショートハンドで、不要なリモート追跡ブランチを削除してくれます。 -
開発ブランチに戻り、開発再開
$ git checkout devel
-
状況に合わせて、merge/rebase等をする。(
rebase
したブランチのpushは要注意)$ git merge master
$ git rebase -i master
これは QMKプロジェクト 等で推奨されるフォーク手順です。
GITブランチ操作のヒント集
GITのブランチの作成・ブランチ間の移動・ブランチのチェックアウト等の
多くの操作は、gitk --all
をした後、右マウスクリックで表示される
GUIメニューから出来ます。
ただリモートレポURLの登録・変更や、リモートのレポ上のブランチの作成・設定変更 等にはコマンドライン入力操作が必要です。
- レポのリモートの設定の状況確認
$ git remote -v
- 現在のブランチ設定の状況確認
$ git branch -vv
- 現在のコミットの最新タグ名を含めた参照名の確認
$ git describe
- 現在のローカルチェックアウトの全状況の確認
$ git status
git
挙動を規定する設定リスト出力git config -l
– 全設定git config --global -l
– ユーザー設定git config --worktree -l
– レポ単位設定
- リモートレポの名前を
origin
からupstream
に変更$ git remote rename origin upstream
origin
という名前をつけたリモートのURLをhttps://foo/bar.git
に変更$ git remote set-url origin https://foo/bar.git
upstream
という名前をつけたリモートへのpushの禁止$ git remote set-url --push upstream DISABLED_FOR_PUSH
- 上記操作で
.git/config
ファイルに「pushurl = DISABLED_FOR_PUSH
」 というラインが追加されます この行頭に#
を挿入しコメントアウトすると、この設定を無効化できます。
- ローカルのブランチ
dev_branch
を作成後、それをリモートorigin
へ pushできるように設定$ git checkout -b dev_branch $ git push -u origin dev_branch
-u
は--set-upstream
のショートハンド
- ローカルのブランチ名を
oldname
からnewname
に変更$ git branch -m oldname newname
(-m
は--move
のショートハンド)
-
リモートブランチを削除する(新・旧の2アプローチ有り)
$ git push -d origin remote_branch_name
(注、-d
は--delete
のショートハンド)$ git push origin :remote_branch_name
(注、:
の前はスペース)
-
削除したブランチを復活
$ git reflog ...git remote set-url --push upstream DISABLED_FOR_PUSH $ git branch new_branch_name HEAD@{6}
-
間違って
git add filename
だけをしたが、まだコミット無しの状態 の場合に、ユーザー編集中のファイルに手を付けずに、レポの状態をadd前の 状態に復元$ git rm --cached filename
-
レポ中に存在するコミットと直接の親子関係のないコミットのためのブランチ
unconnected
を作成$ git checkout --orphan unconnected
-
git
のデフォールト挙動設定例- DOSファイルフォーマット自動変更をしない。(必須)
git config --global core.autocrlf false
- pushのデフォールトを
current
にする。(同名ブランチにpush)git config --global push.default current
- 上記はブランチ名を変えたりするなら、レポ毎デフォルトの
simple
に設定
- pullのデフォールトをrebaseにする。(ヒストリーが綺麗)
git config --global pull.rebase true
- デフォールトブランチを
main
にする。(BLM時代です)git config --global init.defaultBranch main
- デフォールトブランチを
master
に一時的に変更。git config init.defaultBranch master
- 過去(2021)は
dgit
のバグ回避で必要な操作だった。 v=9.14以降は不要。
- DOSファイルフォーマット自動変更をしない。(必須)
-
pushのデフォールト
nothing
: 超コンサバ(必ずブランチ名を詳細指定)simple
:過去の-u
指定に従い既存同名にpushcurrent
: 同名にpush(必要に応じ新規リモートブランチ作成)upstream
: 既存-u
指定に従いブランチ名が違ってもpush
GITブランチ関連操作の応用例
作業中のブランチ履歴の非公開保存
作業中履歴をそのままリモートの公開共有レポに残すと、履歴が錯綜し 他の人に迷惑で、初歩的ミスが晒され格好も悪いし、コード変更の レビューも困難にします。
作業中履歴はローカルへのコミットだけにして、git rebase
操作で
綺麗に整理されたあとの履歴をリモートの公開共有レポにアップする
のが普通かと理解しています。ただこれだと、何らかの事故で作業途中の
ローカルデーターを失うと、全ての直近の作業結果が無くなってしま
います。もちろんローカルシステムのバックアップが良いタイミングで
リモートにされていれば良いのですが、それを保証するのは難しい面が
あります。またHDDやSSDというものはいつ死んでも不思議はない
ので、同一デバイス上のスナップショット記録等は当てにすべきでは
ありません。
こんな場合には、共有のmaster
にコミットする代わりに作業用のブランチ
として例えばwip
を作成し作業中履歴をそこにコミットしgit push
する回避策等が考えられます。ただそれでも他人に見られるので格好が
良くないことは否めません。
またDebianのパッケージング操作で、gbp ...
等を使用する場合ツール
インフラ上ブランチ名を作業用のブランチ名に変えるのを避けたい事も
あります。
ブランチ名を変えたくないが作業中履歴を簡単に保存したい時には、 リモートを変更する策があります。例えば、USBメモリー等に作った 非公開レポをリモートに設定します。
$ cd /path/to
$ git clone https://some_site/repo_name.git
$ cd repo_name
$ git remote set-url --push origin DISABLED_FOR_PUSH
$ mkdir -p /media/usbmemory/repo_name
$ cd /media/usbmemory/repo_name
$ git init --bare
$ cd /path/to/repo_name
$ git remote add usbmemory /media/usbmemory/repo_name
$ git push --all -u usbmemory
ここまですれば、作業中履歴がそのまま非公開レポにも記録され
るようになっています。ここでは、うっかり公開レポにgit push
しな
いように、git remote set-url ...
操作で安全錠を掛けています。
... hack source
$ git push --all
$ git fetch -p origin
$ git rebase -i origin/master
... gack more
$ git push --all
上記のように作業を進め、要点毎に非公開レポにもgit push
記録します。
さらに念のため公開レポのmaster
の最新内容にgit rebase
して同期して
いきます。作業結果が満足となった時点で、安全錠を外して公開レポに綺麗な
形でgit push
します。
$ git remote set-url --delete --push origin ""
$ git push -u origin master
...
ここで、合計2回行ったgit remote set-url ...
操作は間違ってリモートの
公開共有レポにアップするのを防ぐオプショナルな操作で必須ではありませ
ん。ただ今回使ったgit version 2.26.2
では--delete
操作が少々
トリッキーでした。ここは、単純に.git/config
ファイルのpushurl
設定行
をエディターで直接消す方が確実な気がしました。
非公開レポはUSBメモリーではなく、ssh
とgit
が使えるサーバーに作って
も良いでしょう。
Debianのパッケージング操作の場合
アップストリームのブランチ名とローカルのブランチ名を変えるのは、 技術的にはできますが、我々の正気を保つため基本的に避けたい状況です。
Debianのパッケージング操作等では、パッケージング操作用レポ上の「upstream
」
と「master
」というブランチ名を普通デフォルトでパッケージング特定用途に
用いています。実際、アップストリームのGITのmaster
ブランチの
リリースをベースによく自動生成されたファイルを追加して作成されたTARBALL
をベースにパッケージング操作用レポ上の「upstream
」中にコミット作成、
パッケージングデーターを追加してパッケージング操作用レポ上の「master
」
中にコミット作成しするのがデフォルトです。両方のレポをトラッキングしよう
とするとアップストリームとパッケージングのブランチ名「master
」がかち合う
のでこれを避ける工夫が必要です。git-buildpackage
を使う場合には、
debian/gbp.conf
を用いて、パッケージング操作用レポ上にある
パッケージングデーターを追加して結果がコミットされるブランチ名を「debian
」
等という別のブランチ名を用いるようにするのが良いようです。dgit
を使う場合
には、マニュアルででもdebian/gbp.conf
を用いるとともに、git-config
を
使い調整することに触れられています。
上記の正攻法が、何らかの理由でうまくいかない際には、避けたいといったアプローチ
ですが、アップストリームの「master
」ブランチを追跡するローカルブランチの名前を
「master
」以外の別の名前から選ぶことで逃げる手があります。
例えばフォークされたレポでは「upstream-master
」を追跡に用いるブランチの名前
とします。「upstream-master
」ブランチのコンテントをアップストリームの
「master
」ブランチのコンテントに同期させる操作は次のようになります。
$ git clone https://upstream_site/repo_name.git
$ cd repo_name
$ git branch upstream-master
$ git remote rename origin upstream
$ git remote set-url --push upstream DISABLED_FOR_PUSH
$ git remote add origin git@salsa.debian.org:myname/repo_name.git
$ git push -u origin
...
$ git checkout upstream-master
$ git fetch -p upstream
$ git pull upstream master
$ git push origin upstream-master
$ git checkout master
...
上記でローカルの「upstream-master
」ブランチが、アップストリームの
リモートの「master
」ブランチ(gitk
が「remotes/upstream/master
」
と表示)を追跡するようになります。
また、ローカルの「upstream-master
」ブランチは、自分のリモートの
「upstream-master
」ブランチ(gitk
が「remotes/origin/upstream-master
」
と表示)にpushされ保存されます。
push対象のローカルの「upstream-master
」ブランチが、現在Checkoutしている
デフォルトブランチで、push先のリモートでもブランチ名が同じ
「upstream-master
」だから、pushの際のコマンドラインへの入力文字列
をかなり省略できるので短くて済んでます。
上記の後半の操作を繰り返すことで、ローカルの「upstream-master
」が、
常にアップストリームが更新するアップストリームのリモートの「master
」
ブランチ(gitk
が「remotes/upstream/master
」と表示)を追跡していけます。
上記のようにDebianのパッケージングの際に用いるGitレポではupstream
ブランチはアップストリームがリリースしたtarballを展開した内容を
コミットして作ることが原則です。一方リリースされるtarballは単純に
アップストリームのGitレポそのままでないことがよくあります。こんな
場合はアップストリームのGitレポのヒストリーとうまく繋がりません。
そんな場合には、「upstream-master
」をパッケージング用レポの
「master
」上に作ることはできません。
こんな場合でもアップストリームとパッケージングのレポからの
チェックアウトを共用ローカルディレクトリーにすると、gitk
で
upstream/master
にある最新のアップストリーム変更からパッチを
cherry-pickして使えるので便利です。そのためだけなら、ローカルの
upstream-master
ブランチの作成や更新にあたる作業をスキップする
のも手です。例えば、過去のパッケージ履歴を含むパッケージ用のGit
レポを、gbp import-descs ...
等で作成し、更に
git remote add upstream upstream_url
(このupstream
はremotes名)
してリモート名を登録、ここで単純にgit fetch -p upstream
すること
までにし、アップストリームのレポ中のmaster
ブランチのみをfetch
すれば、ローカルのブランチ名との競合を気にせずgitk --all
で
アクセスできるアップストリームのレポ履歴がローカルに落とせます。
履歴は繋がってませんがcherry-pickするだけならこれで充分です。
こうしてできた履歴に、gitk --all
でアクセスしてローカルブランチ名を
後からにupstream-master
等とGUIで設定すれば、ローカルチェックアウトも
できます。まあ、ローカルとリモートでブランチ名が変わるのが嫌ですが。
どこにも繋がらない履歴のブランチ作成
gbp
のような、どこにも繋がらない履歴のブランチ作成はちょっとトリッキーなので、ここに2ケースの例をメモしておきます。
新規のREADME.mdがコミットされたどこにも繋がらない履歴を、ブランチ名orphan_branch_name
で新規作成するのは以下です。
$ git checkout --orphan orphan_branch_name
$ git rm -rf .
$ editor README.md
....
$ git add README.md
$ git commit -m 'Initial commit'
別のリモートのREPO(another
)にあるブランチ(例えばmaster
)の内容のどこにも繋がらない履歴を、既存のローカルREPO内にブランチ名another-master
で作成するのは以下です。
$ git remote add another http://another.example.org/another
$ git fetch another master:another-master
トラッキング
ブランチがトラッキングするリモートレポの設定は、上記のように最初に
プッシュする際にgit push -u ...
とするのも手ですが、直接変更するのは
git branch -u ...
です。
git remote
の際にLONGオプションを用いると話がややこしくなるので要注意です。
完全なリセット(gitattributes
設定とautocrlf
関連)
当方では改行関係に変な事が起こらないようにしています。
$ git config --global core.autocrlf false
他人のレポで、.gitattributes
設定でeol=lf
されていて、折角の上記設定が
効かないときに、どいうわけがCR入りでファイルがコミットをされていて、その
コミットにgitk
でブランチをリセットしようとしたら勝手にCRを外した
ローカルファイルに変更され困りました。
以下で、問題解決しました。
$ git rm --cached -r .
$ git reset --hard
$ git clean -d -f -x
GITHUB/GITLAB
GITHUBとGITLABは、ともに類似の無償のGITレポのホスティングを提供している 非常にポピュラーなWEBサービスです。ここではGITHUBとGITLABの サービスの細かな違い や ワークフロー流儀の細かな違い には深入りしません。
簡単に特徴をまとめると、GITHUBは先発のクローズドソフトプラットフォーム でユーザー数が多いのが特徴で、GITLABは後発ですが基本のソフトプラット フォームがオープンなFLOSS(Free and open-source software)として開放され ていて、Debian等のFLOSSプロジェクトが自らのソースコードWEBサービスの ホスティングに採用してているのが特徴です。
「Debianのパッケージング操作」で行ったGITHUBやGITLABのウエッブページ
を使わずにフォークしたレポを、git clone ...
経由でDebianのサーバー上
に作成した操作手法は、コマンドライン環境だけでアップストリームと交流
することが前提です。
GITHUBやGITLAB上のウエッブサービスを利用する場合には状況によっては 別の配慮が必要です。例えばGITHUBやGITLAB内のレポ間フォークの場合、 GITHUBやGITLAB上でウエッブページを使いフォークしないとPULL request等 のウエッブ連携操作に支障がでる恐れがあります。
デフォールトのブランチ名
ブランチ名を変えずにフォークしたレポの「master
」は、アップストリーム
の「master
」を同じ内容なので、オープニングのページで表示される
README.MD
がアップストリームを同じ内容になります。これでは折角のフォークが
隠れてしまいます。これは、ログインしてGITHUBやGITLABの設定に入り、
Default branch(デフォルトのブランチ)をもとの「master
」ではない、
フォークした内容がコミットされたブランチに設定することで解決します。
自由なブランチ名の設定
特段の理由なくローカルやリモートでブランチ名が変わる複雑な設定をする のは無用な混乱を起こすのでできるだけ避けるべきです。以下はあくまで 参考情報です。
この様なことをすると、push を便利なcurrent
に設定できなくなり、
同名のブランチにpushするにも必ずgit push
コマンドラインの最後引数
を明示する必要が出ます。
さて本題です。
例えばgitk
で見つけた既存のリモートブランチ(例えばgitk
が
「remotes/upstream/foo
」と表示するブランチ)のある最終コミットに
GUIでローカルのブランチ(例えば「bar
」)を新規追加した場合を考え
ましょう。
この「bar
」ブランチを、自分が公開しているorigin
という
リモートレポに、他人からは「baz
」ブランチと呼ばれることと
なるブランチとして、(別の見方では自分のgitk
で「remotes/origin/baz
」
と表示されるブランチとして)、最初pushするには以下の操作をします。
$ git checkout bar
$ git push -u origin bar:baz
一度この操作をすると、.git/comfig
ファイルにこの設定が記録され
ます。この設定はgit comfig
コマンドで調整できますし、また
エディターで.git/comfig
ファイルを直接編集しても調整できます。
さらにこの状況は以下のようにして確認できます。
$ git config --list
...
branch.bar.remote=origin
branch.bar.merge=refs/heads/baz
こう設定した後、「bar
」ブランチをチェックアウトして、ファイル
を変更しローカルにコミット後、アップストリームのGITレポからの変更
を取り込むには以下とします。(設定していれば--rebase
は不要。)
$ git pull --rebase origin
ローカルのコミットは最新アップストリームにrebaseされます。
2回目以降のpushでは、必ずブランチ名の明示指定が必要です。(一方、今回は-u
不要)
(push.default
をupstream
に設定していれば別ですが、、、)
$ git checkout bar
... hack
$ git push origin bar:baz
ややこしいですが、「bar
」ブランチの最新コミットがgitk
で
「remotes/origin/baz
」と表示されるorigin
というリモートレポ上
のリモートブランチ「baz
」にpushされます。
参考Cookbookサイト
- Flight rules for Git
- rename both a Git local and remote branch name
- rename a Git local branch name
- rename a Git remote branch name
Previous Post | Top | Next Post |