54
64

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

一言でいうと「git merge は、ファン目線=物まねで満足」「git rebase は、ストーカー目線=相手の家に押しかける」

Last updated at Posted at 2019-03-08

これは何?

  • git mergegit rebase の違いを図で説明します。
  • 個人的に「commit を1つの箱と見立て、上に積み上げるイメージ」でも、うまく書けそうな気がしたので試してみました。
  • 結果、箱が積み重なった図が家(ビル)に見えてきました。
  • そうすると 『git merge は、ファン目線=物まねで満足」「git rebase は、ストーカー目線=相手の家に押しかける』 だなぁ。と感じ始めました。

リポジトリの初期状態

  • この状態から、git merge あるいは git rebase を行います。
    • 今現在、2つのブランチ origin/develop feature があります。
    • 現在位置(HEAD) は feature です。

1-original.png

git merge origin/develop (自分 feature に、相手 origin/develop の commit を積む)

  • git merge origin/develop すると次のようになります。
  • 自分 feature に、相手 origin/develop の全ての成果物(commit)を取り込みます。
    • 共通の祖先である A を基準とします。
    • 基準以降の相手の成果物である、C E が取込対象となります。
    • 取込対象は1つにまとめられ、C'E' として 自分に commit されます。
    • このように「相手の複数の成果物を1つにまとめて取り込む」のが、この場合の git merge の動きです。

2-git-merge.png

git rebase origin/develop (相手 origin/develop に、自分 feature の commit を積み直す)

  • git rebase origin/develop すると次のようになります。
  • 相手 origin/develop に、自分 feature の成果物(commit)を付け直します。
    • 共通の祖先である A を基準とします。
    • 基準以降の自分の成果物である B D が移動対象になります。
    • 移動対象は1commitずつ、相手に移動します。(正確には、移動ではなく、全く同じ内容でコピーが行われます。つまり、ハッシュ値が変わります)
  • ちなみに、B D は、git log 上からは見えなくなりますが、完全に削除されたわけではなく、git reflog HEAD で見えます。(詳細は、以下の参考を参照ください)

3-git-rebase.png

まとめ

  • 違いを簡潔に説明すると、、、
    • git merge は、自分に相手のcommitを積む。git rebase は、相手に自分のcommitを積み直す。」
    • git merge は、相手の家財道具と同じものを購入して自宅に置く。git rebase は、自宅の家財道具一式持って、相手の家に引っ越す」
    • git merge は、相手の物まねをする。git rebase は、自宅は引き払って相手の家に住む」
    • つまり「git merge は、ファン目線。git rebase は、ストーカー目線」

参考:上で説明したケースの実例

git merge の例

  • 実行コマンド
(
# set -x

mkdir try-git-merge
cd try-git-merge

git init

git config user.name "hoge"
git config user.email "hoge@example.com"

sleep 1
git checkout -b develop
echo "aaa" > a.txt
git add a.txt
git commit -m "add a.txt"

sleep 1
git checkout -b feature
echo "bbb" > b.txt
git add b.txt
git commit -m "add b.txt"

sleep 1
git checkout develop
echo "ccc" > c.txt
git add c.txt
git commit -m "add c.txt"

sleep 1
git checkout feature
echo "ddd" > d.txt
git add d.txt
git commit -m "add d.txt"

sleep 1
git checkout develop
echo "eee" > e.txt
git add e.txt
git commit -m "add e.txt"

git log --all --graph --oneline --date-order

sleep 1
git checkout feature
git merge --no-edit develop

git log --all --graph --oneline --date-order
git reflog HEAD
)
  • 実行結果
Initialized empty Git repository in /home/ubuntu/20190307/try-git-merge/.git/
Switched to a new branch 'develop'
[develop (root-commit) 9ce6cfc] add a.txt
 1 file changed, 1 insertion(+)
 create mode 100644 a.txt
Switched to a new branch 'feature'
[feature c6edd06] add b.txt
 1 file changed, 1 insertion(+)
 create mode 100644 b.txt![3-git-rebase.png](https://qiita-image-store.s3.amazonaws.com/0/275337/de3dcaaa-f3c8-ee43-cacb-cf5c778685c1.png)

Switched to branch 'develop'
[develop b0e661e] add c.txt
 1 file changed, 1 insertion(+)
 create mode 100644 c.txt
Switched to branch 'feature'
[feature 861542b] add d.txt
 1 file changed, 1 insertion(+)
 create mode 100644 d.txt
Switched to branch 'develop'
[develop 05140da] add e.txt
 1 file changed, 1 insertion(+)
 create mode 100644 e.txt
* 05140da (HEAD -> develop) add e.txt ・・・・ merge 前
| * 861542b (feature) add d.txt
* | b0e661e add c.txt
| * c6edd06 add b.txt
|/  
* 9ce6cfc add a.txt
Switched to branch 'feature'
Merge made by the 'recursive' strategy.
 c.txt | 1 +
 e.txt | 1 +
 2 files changed, 2 insertions(+)
 create mode 100644 c.txt
 create mode 100644 e.txt
*   35d2fc8 (HEAD -> feature) Merge branch 'develop' into feature ・・・ merge 後
|\  
| * 05140da (develop) add e.txt
* | 861542b add d.txt
| * b0e661e add c.txt
* | c6edd06 add b.txt
|/  
* 9ce6cfc add a.txt
35d2fc8 (HEAD -> feature) HEAD@{0}: merge develop: Merge made by the 'recursive' strategy.
861542b HEAD@{1}: checkout: moving from develop to feature
05140da (develop) HEAD@{2}: commit: add e.txt
b0e661e HEAD@{3}: checkout: moving from feature to develop
861542b HEAD@{4}: commit: add d.txt
c6edd06 HEAD@{5}: checkout: moving from develop to feature
b0e661e HEAD@{6}: commit: add c.txt
9ce6cfc HEAD@{7}: checkout: moving from feature to develop
c6edd06 HEAD@{8}: commit: add b.txt
9ce6cfc HEAD@{9}: checkout: moving from develop to feature
9ce6cfc HEAD@{10}: commit (initial): add a.txt

git rebase の例

  • 実行コマンド
(
# set -x

mkdir try-git-rebase
cd try-git-rebase

git init

git config user.name "hoge"
git config user.email "hoge@example.com"

sleep 1
git checkout -b develop
echo "aaa" > a.txt
git add a.txt
git commit -m "add a.txt"

sleep 1
git checkout -b feature
echo "bbb" > b.txt
git add b.txt
git commit -m "add b.txt"

sleep 1
git checkout develop
echo "ccc" > c.txt
git add c.txt
git commit -m "add c.txt"

sleep 1
git checkout feature
echo "ddd" > d.txt
git add d.txt
git commit -m "add d.txt"

sleep 1
git checkout develop
echo "eee" > e.txt
git add e.txt
git commit -m "add e.txt"

git log --all --graph --oneline --date-order

sleep 1
git checkout feature
git rebase develop

git log --all --graph --oneline --date-order
git reflog HEAD
)
  • 実行結果
Initialized empty Git repository in /home/ubuntu/20190307/try-git-rebase/.git/
Switched to a new branch 'develop'
[develop (root-commit) bf10f4f] add a.txt
 1 file changed, 1 insertion(+)
 create mode 100644 a.txt
Switched to a new branch 'feature'
[feature 532fb77] add b.txt
 1 file changed, 1 insertion(+)
 create mode 100644 b.txt
Switched to branch 'develop'
[develop fff94fd] add c.txt
 1 file changed, 1 insertion(+)
 create mode 100644 c.txt
Switched to branch 'feature'
[feature 5ef0acd] add d.txt
 1 file changed, 1 insertion(+)
 create mode 100644 d.txt
Switched to branch 'develop'
[develop 91dfce3] add e.txt
 1 file changed, 1 insertion(+)
 create mode 100644 e.txt
* 91dfce3 (HEAD -> develop) add e.txt ・・・ rebase 前
| * 5ef0acd (feature) add d.txt
* | fff94fd add c.txt
| * 532fb77 add b.txt
|/  
* bf10f4f add a.txt
Switched to branch 'feature'
First, rewinding head to replay your work on top of it...
Applying: add b.txt
Applying: add d.txt
* f097caa (HEAD -> feature) add d.txt ・・・ rebase 後
* cda4d58 add b.txt
* 91dfce3 (develop) add e.txt
* fff94fd add c.txt
* bf10f4f add a.txt
f097caa (HEAD -> feature) HEAD@{0}: rebase finished: returning to refs/heads/feature
f097caa (HEAD -> feature) HEAD@{1}: rebase: add d.txt ・・・ D がコピーされ、rebase後 D' (f097caa) となった
cda4d58 HEAD@{2}: rebase: add b.txt ・・・・・・・・・・・・・ B がコピーされ、rebase後 B' (cda4d58) となった
91dfce3 (develop) HEAD@{3}: rebase: checkout develop
5ef0acd HEAD@{4}: checkout: moving from develop to feature
91dfce3 (develop) HEAD@{5}: commit: add e.txt
fff94fd HEAD@{6}: checkout: moving from feature to develop
5ef0acd HEAD@{7}: commit: add d.txt ・・・・・・・・・・・・・・ rebase後、使われなくなった D(5ef0acd)
532fb77 HEAD@{8}: checkout: moving from develop to feature
fff94fd HEAD@{9}: commit: add c.txt
bf10f4f HEAD@{10}: checkout: moving from feature to develop
532fb77 HEAD@{11}: commit: add b.txt ・・・・・・・・・・・・・ rebase後、使われなくなった B(532fb77)
bf10f4f HEAD@{12}: checkout: moving from develop to feature
bf10f4f HEAD@{13}: commit (initial): add a.txt
54
64
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
54
64

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?