2017年07月13日

git ブランチを付け替える

ブランチを統合する操作として "merge" がある。
もう一つ別の方法として、 "rebase" がある。





基本的な操作


git_rebase01.png



"new_branch" ブランチを "master" ブランチへ "merge" すると、以下のようになる。

$ git checkout master
$ git merge new_branch

git_rebase02.png
$ git log --oneline --graph
* e379414 Merge branch 'new_branch' Conflicts -> modified
|\
| * 0792fc6 new_branch 追加 3
| * ef693eb new_branch 追加 2
| * 24edebf new_branch 追加1
* | 762bccf master 追加 3
* | 9fe9714 master 追加 2
* | 1c0a080 master 追加1
|/
* 07c5066 master branch :変更 1
* 830f4ca Add new file :index.html


これを "rebase" を使って操作してみる。

"rebase" は、「re-base」のこと。ブランチの分岐元を付け替える操作。
分岐元を変更したい("rebase" したい)ブランチへ切り替える。今は、"new_branch" を変更する。

$ git checkout new_branch


"new_branch" ブランチの分岐元を、"master" ブランチの "HEAD" に切り替える。

$ git rebase master


コンフリクトが起きた場合は、コンフリクトを修正後、修正ファイルをステージし、継続する。

$ git add index.html
$ git rebase --continue


"rebase"が終了すると、以下のようになる。
git_rebase03.png
$ git log --oneline --graph
* 22d32e0 new_branch 追加 3
* d7e8b73 new_branch 追加 2
* 5893adb new_branch 追加1
* 762bccf master 追加 3
* 9fe9714 master 追加 2
* 1c0a080 master 追加1
* 07c5066 master branch :変更 1
* 830f4ca Add new file :index.html

"new_branch" は分岐元が付け替えられている。そして、各コミットも改めてコミットされてたのでコミットIDが変わっている。

この状態で、"master" ブランチで、"merge" を行うと、

$ git checkout master
$ git merge new_branch

コミット状態がきれいになっているので Fast-forward マージ が行われる。
Updating 762bccf..22d32e0
Fast-forward
index.html | 3 +++
1 file changed, 3 insertions(+)

git_rebase04.png
$ git log --oneline --graph
* 22d32e0 new_branch 追加 3
* d7e8b73 new_branch 追加 2
* 5893adb new_branch 追加1
* 762bccf master 追加 3
* 9fe9714 master 追加 2
* 1c0a080 master 追加1
* 07c5066 master branch :変更 1
* 830f4ca Add new file :index.html


ログを見ると、単にマージしたときと統合内容は同じだが、こちらのほうがブランチの分岐の履歴が無く、すっきりとした状態になる。

ただし、作業した結果が残らない履歴は、個人的には好みではない。

使うのであれば、本流のブランチへ統合するときに行うのではなく、バグ修正や、機能開発などの作業ブランチにおいて、個人の作業範疇でさらにブランチを切る必要があった場合に、最終的なブランチの結果としてコミットをまとめるときに使うことをすすめる。これであれば、個人単位での作業としては履歴が残ることと、後から履歴を見たときに作業の都合のために切ったブランチが全体の見通しを悪くしてしまうことを避けることができる。





onto オプション


"new_branch" ブランチを切って開発中に、開発のためにバグ修正が必要だったので "sub_branch" ブランチを切って修正した。このバグ修正が他の機能開発でも必要だとわかったので "master" ブランチへ統合したい。
git_rebase05.png

"new_branch" ブランチはまだ開発途中で取り込めない。"sub_branch" のみ取り込みたい。
必要なコミットは、コミット(X):0cb061a、コミット(Y):0a8d056 の2つのみ。
ここで "rebase" をしてみる。

$ git checkout sub_branch
$ git rebase master

"master" ブランチへマージする。

$ git checkout master
$ git merge sub_branch

Updating 762bccf..ce98d22
Fast-forward
index.html | 3 +++
1 file changed, 3 insertions(+)

$ git log --oneline --graph
* ce98d22 sub_branch 追加 2
* 216520c sub_branch 追加 1
* b4d8495 new_branch 追加1
* 762bccf master 追加 3
* 9fe9714 master 追加 2
* 1c0a080 master 追加1
* 07c5066 master branch :変更 1
* 830f4ca Add new file :index.html


git_rebase06.png

この場合、今はまだ取り込みたくなかった コミット(1):24edebf が一緒に取り込まれてしまった。

このような変則的な取り込みを行うときに、"onto" オプションを使う。

指定がややこしいが、以下のようにブランチを指定する。
現在、チェックアウトしているブランチに対して、

$ git rebase --onto <どこへ> <どこから>



今の操作であれば、"sub_branch" ブランチをチェックアウトした状態で、"new_branch" から、"master" へ、切り替える操作。

$ git checkout sub_branch
$ git rebase --onto master new_branch

"master" ブランチへマージする。

$ git checkout master
$ git merge sub_branch

Updating 762bccf..9617339
Fast-forward
index.html | 3 +++
1 file changed, 3 insertions(+)

$ git log --oneline --graph
* 9617339 sub_branch 追加 2
* 66d8fb8 sub_branch 追加 1
* 762bccf master 追加 3
* 9fe9714 master 追加 2
* 1c0a080 master 追加1
* 07c5066 master branch :変更 1
* 830f4ca Add new file :index.html

git_rebase07.png


これは、ちょっと特殊な場面だったが、次のような場合も、"oonto" オプションを使えば解決できる。

"new_branch" ブランチから、新たなブランチを切って作業を進めようとしていたが、誤って、"master" ブランチから、ブランチを切って作業していたことに気づいた。"new_branch" ブランチも履歴が進んでしまった。本当は コミット(1):24edebf からブランチを切りたかった。
git_rebase08.png

こういう場合に、"onto" オプションをつけて "rebase" をすることで修正できる。
(付け替え先はブランチ名ではなく、コミットIDを指定する。ブランチ名だと、先頭のコミットが付け替え先になる。)

$ git checkout sub_branch
$ git rebase --onto 24edebf master

$ git log --oneline --graph
* 026323a sub_branch 追加 2
* 29540b6 sub_branch 追加 1
* 24edebf new_branch 追加1
* 07c5066 master branch :変更 1
* 830f4ca Add new file :index.html

git_rebase09.png





rebase と cherry-pick


上記のような "rebase" の操作は、実は連続で cherry-pick を実行することでも同じ結果が得られる。
少ないコミットであれば、cherry-pick で操作すれば済むが、ブランチ丸ごとに対して操作することに対して、簡単に cherry-pick 操作できるようしたものが "rebase" だともいえる。





まとめ


"rebase" することのメリットとしては、
  • コミットログがきれいになる。
    無数に入り組んだ履歴ではなく、必要な情報が俯瞰できるようになり、後から履歴を見たときにわかりやすくなる。その結果、運用、保守、生産性の効率が期待できる。

という点で、作業の効率化のためにもどんどんブランチを切って作業し、それを整理していくことは良いことだと思う。
ただ、これが許されるのは閉じられた世界での話。

チーム作業で公開してしまったブランチに対してはダメ。
ブランチを作り、リモートリポジトリに push した後、他のメンバーがそのブランチから新たにブランチを切って作業していたら、もうそのブランチは "rebase" してはいけない。禁止。

"rebase" してしまうと、過去のコミットIDが変わってしまう。派生させたブランチは親ブランチを追いかけることができなくなってしまう。"merge" するときに多大なる迷惑をかけてしまう。

なので、push する前のローカルなブランチであれば "rebase" で整理して、全体の見通しを良くすることは、以降の開発効率を上げるための一手間としておススメ。





gitをインストール
gitサーバーのセットアップ
git ブランチについて
git 変更を一時的に退避 stash
git ブランチを合流するマージ
git コミット履歴を変更する
git コミットを取り消す
git 変更をリセットする
git リモートでの操作
git ファイルの追跡
git リリース準備
git リモートブランチを追加
git チェックアウトをもっと便利に使う
git プロジェクトの構成
git 変更をpatchファイルにする
git コンフリクトに対処する
git 失敗したときの復元
posted by Zorinos at 20:00| Comment(0) | Linux | 更新情報をチェックする
この記事へのコメント
コメントを書く
コチラをクリックしてください