Gitコマンド入門::Gitブランチ機能(rebase,その4)第六十九回

6 min read読了の目安(約5600字

みなさんこんにちは! 今日も前回に続いて、rebaseの続きを学習していきます。「リベースした場合のリベース」(笑)そんなタイトルになっていますけど、ある程度まで、gitが自動判断して、リベースしてくれそうです! まあ~、同じ内容のものが重複をしていたなら、省くってだけの事ですけどね~ まずは、試して行きましょう!

誤植のお詫び

後で気が付いたのですが、前回の最後、my_01ブランチに、you_05ブランチをマージすると記載してあったのですが、実際のコマンド例では、you_04をマージしていましたね。尚、you_04、you_05のブランチは、全く同じ内容でしたので、結果に、差異はありませんでしたけど、読者の方には、ちょっと混乱させてしまったかもしれません。m(_)m

今日の学習は、こちら!

https://git-scm.com/book/ja/v2/Git-のブランチ機能-リベース
こちらのページの下段、Figure 47. 同じ作業を再びマージして~の下にいくと、「リベースした場合のリベース」 とありますので、今回は、ここを学習して行きます。

前回の記事はこちらから!

https://zenn.dev/shiozumi/articles/8582dabe623069

git本家本元の情報はこちらから!

https://git-scm.com/book/ja/v2

今回の環境は、git clone してください。

$ git clone https://github.com/shiozumi-makoto/20210402.git
Cloning into '20210402'...

// 中略!

// clone で、作成されたフォルダーに移動して!
$ cd 20210402

// ブランチは、こんな感じになります!
$ git branch -avv
* my_01                 8f3b141 [origin/my_01] C7
  remotes/origin/HEAD   -> origin/my_01
  remotes/origin/my_01  8f3b141 C7
  remotes/origin/you_04 4bc46c0 C6
  remotes/origin/you_05 1f4e654 C4

// 続けて、origin/you_04 も取り込んでくださあ~い!
$ git checkout -b you_04 origin/you_04
Branch 'you_04' set up to track remote branch 'you_04' from 'origin'.
Switched to a new branch 'you_04'

// origin/you_05 も!
$ git checkout -b you_05 origin/you_05
Branch 'you_05' set up to track remote branch 'you_05' from 'origin'.
Switched to a new branch 'you_05'

$ git branch -avv
  my_01                 8f3b141 [origin/my_01] C7
  you_04                4bc46c0 [origin/you_04] C6
* you_05                1f4e654 [origin/you_05] C4
  remotes/origin/HEAD   -> origin/my_01
  remotes/origin/my_01  8f3b141 C7
  remotes/origin/you_04 4bc46c0 C6
  remotes/origin/you_05 1f4e654 C4
  
// これで、全てのブランチが整いましたね!
  1. origin/my_01 こちらは、前回と同様でマージ前
  2. origin/you_04 こちらも、前回と同様、you_05とはマージ済
  3. origin/you_05 こちらは、リベースしたものです。

my_01 のマージ前の状態です。

$ git log --oneline --graph my_01
*   8f3b141 (origin/my_01, origin/HEAD, my_01) C7
|\
| *   4bc46c0 (origin/you_04, you_04) C6
| |\
| | * 061bab3 C5
| * | 41f5a21 C4
| |/
* | 6093ed7 C3
* | 7ff068f C2
|/
* 9d381c2 C1

you_04 は、you_05とマージ後の状態です。

$ git log --oneline --graph you_04
*   4bc46c0 (origin/you_04, you_04) C6
|\
| * 061bab3 C5
* | 41f5a21 C4
|/
* 9d381c2 C1

you_05は、you_04とリベース後です。

$ git log --oneline --graph you_05
* 1f4e654 (HEAD -> you_05, origin/you_05) C4
* 061bab3 C5
* 9d381c2 C1

本家サイトの画像を貼り付けておきます!

本家の解説では、他の人が後からリベースして、pushした、ブランチです!

前回の復習も兼ねて、もう一度、my_01 と、you_05 をマージするとこから、やって行きます!

git merge you_05
// マージコメントを聞かれるので、そのまま、wq で保存。
// コメントは、Merge branch 'you_05' into my_01 となります!

$ git log --graph --oneline
*   f3a5d72 (HEAD -> my_01) Merge branch 'you_05' into my_01
|\
| * 1f4e654 (origin/you_05, you_05) C4
* |   8f3b141 (origin/my_01, origin/HEAD) C7
|\ \
| * \   4bc46c0 (origin/you_04, you_04) C6
| |\ \
| | |/
| | * 061bab3 C5
| * | 41f5a21 C4
| |/
* | 6093ed7 C3
* | 7ff068f C2
|/
* 9d381c2 C1

本家サイトの画像を貼り付けておきます!
C8 = f3a5d72 Merge branch 'you_05' into my_01
C4' = 1f4e654 [新]C4

前回と同じような、履歴になっていますね。C5 から枝分かれして、「新」C4と、C6に繋がっています。you_04 と、you_05 の両方をマージした状態です。

今日の本題! git rebase you_05 を実行!

// git switch my_01 で、ローカルmy_01ブランチに切り替えてから!

$ git rebase you_05
First, rewinding head to replay your work on top of it...
Applying: C2
Applying: C3
Applying: C4
Using index info to reconstruct a base tree...
Falling back to patching base and 3-way merge...
No changes -- Patch already applied.

$ git log --oneline --graph my_01
* 1548e15 (HEAD -> my_01) C3
* 37bfc60 C2
* 1f4e654 (origin/you_05, you_05) C4
* 061bab3 C5
* 9d381c2 C1

C1 → C5 → C4「新」→ C2 → C3 と履歴がリベースされましたね!

本家のドキュメントでは、teamone/master となっています。ここでは、you_05 に置き換えて実行しています。尚、ローカルyou_05ブランチとして、git checkout -b you_05 origin/you_05 を実行しない場合は、git rebase origin/you_05 ですね!

本家サイトにある処理フローから!

  1. my_01 = C1, C2, C3, [旧]C4, C5, C6, C7, [新]C4, 最終マージコミット[1]
  2. you_05 = C1, C5, [新]C4

ここで、my_01とyou_05のコミットを比較して、my_01 にしかない物を、ピックアップする。結果は、C2, C3, [旧]C4, C6, C7, 最終マージコミットの6つが対象となります。

次に、マージコミットは省くとなっているので、C6, C7, 最終マージコミットを除くので、残りは、C2, C3, [旧]C4 がリベース処理の対象コミットとなります。さらに、[旧]C4と[新]C4は同じですから、[旧]C4も対象外となるので、my_01 からは、C2, C3 のみが必要となりますね。ということで、you_05 のC1, C5, [新]C4の後に、C2, C3 コミットを繋げて完成です。

結果、C1 → C5 → C4「新」→ C2 → C3 ですね!

$ git log --oneline --graph my_01
* 1548e15 (HEAD -> my_01) C3  // <!-- 本家では、C3'
* 37bfc60 C2           // <!-- 本家では、C2'
* 1f4e654 (origin/you_05, you_05) C4 // <!-- 本家では、C4'
* 061bab3 C5
* 9d381c2 C1

分かりやすいように、本家サイトの画像も、貼り付けておきますね!

本家から引用:Figure 48. リベース後、強制的に~

これがうまくいくのは、あなたの C4 と他のメンバーの C4' がほぼ同じ内容のパッチである場合だけです。 そうでないと、これらが重複であることを見抜けません (そして、おそらくパッチの適用に失敗するでしょう。その変更は、少なくとも誰かが行っているだろうからです)。

本家サイトの解説は、こんな感じです。(^▽^;)
C4 は、[旧]C4、 C4' は、 [新]C4 と置き換えて読んでくださいね。

まとめ

さあ、いかがでしょうか? 実際にコマンドを叩くまでは、本当にそうなるのかな? な~んて、不安一杯でしたけど、案外、すんなりと予想どおりの結果となりましたね。まあ、処理フロー的には、コミットデータの重複を省いて、その後ソートするだけですから、簡単なことですけどね。

それでは、今回はここまで、お疲れ様でした!

https://zenn.dev/shiozumi/articles/71b2e0d07ab75d
https://twitter.com/esmile2013

つぶやき・・・

まあ~、ぶっちゃけ、Gitは全てのスナップショットを保存している。出だしからその特徴を説明しているぐらいですからね。それなら、コミットの比較も容易ですし、過去の履歴が多少前後したり、最悪欠落したりしても、最新のコミットはあればなんとなるんでしょうね。また、過去のコミットの管理も、ブランチを切ったり、タグを貼り付けておけば、実務でもなんとかなるってことなんでしょうね~ (⌒∇⌒)

脚注
  1. ハッシュ値:f3a5d72 コメント:Merge branch 'you_05' into my_01 ↩︎