gitコマンドの使い方 ~ git rebase ~

2020年4月6日git-command

git rebase コマンド概要

git rebase コマンドには以下の2つの機能があります。

  • 2つのcommitの履歴を一直線にする
  • 複数のcommitを1つのcommitにまとめる

共通していることは、commit履歴を綺麗にすることです。

2つのcommitの履歴を一直線にする

git rebaseの利用方法の一つである「2つのcommitの履歴を一直線にする」について説明します。

以下の図では2つのブランチ(masterとdevelop)があり、master側のcommit(C)の後続としてdevelop側のcommit(B)とcommit(D)を繋げてcommit履歴を一直線にしたい場合に利用します。

git rebase コマンドの使い方

git rebase [branch]

branchには接続元になるブランチを指定します。

上図の場合はdevelopブランチをcheckoutした状態で「git rebase master」を実行します。

 

実際に上図の操作をgitコマンドで行うとこうなります。

(master)
$ echo 'aaa' > file-A.txt

(master)
$ git add .

(master)
$ git commit -m 'commit-A'
[master (root-commit) f0a8fc2] commit-A
 1 file changed, 1 insertion(+)
 create mode 100644 file-A.txt

(master)
$ git branch develop

(master)
$ echo 'ccc' > file-C.txt

(master)
$ git add .

(master)
$ git commit -m 'file-C.txt'
[master a144d6f] file-C.txt
 1 file changed, 1 insertion(+)
 create mode 100644 file-C.txt

(master)
$ git checkout develop
Switched to branch 'develop'

(develop)
$ echo 'bbb' > file-B.txt

(develop)
$ git add .

(develop)
$ git commit -m 'commit-B'
[develop cbec331] commit-B
 1 file changed, 1 insertion(+)
 create mode 100644 file-B.txt

(develop)
$ echo 'ddd' > file-D.txt

(develop)
$ git add .

(develop)
$ git commit -m 'commit-D'
[develop 14c4d83] commit-D
 1 file changed, 1 insertion(+)
 create mode 100644 file-D.txt

(develop)
$ git log --oneline --all --graph
* 14c4d83 (HEAD -> develop) commit-D
* cbec331 commit-B
| * a144d6f (master) file-C.txt
|/
* f0a8fc2 commit-A

(develop)
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: commit-B
Applying: commit-D

(develop)
$ git log --oneline --all --graph
* 103d89a (HEAD -> develop) commit-D
* 607f8e8 commit-B
* a144d6f (master) file-C.txt
* f0a8fc2 commit-A

git rebaseコマンドの実行前はgit logでブランチの枝が分かれていますが、git rebaseコマンドの実行後はcommit履歴が一直線になっていますね。

 

git mergeで接続元ブランチの位置を移動

masterブランチの位置を最新のcommit(D)に移動させたい場合は、git mergeコマンドを実行しましょう。

git mergeすると以下の図のようにmasterブランチの位置が先頭のcommitに移動します。

(develop)
$ git checkout master
Switched to branch 'master'

(master)
$ git merge develop
Updating a144d6f..103d89a
Fast-forward
 file-B.txt | 1 +
 file-D.txt | 1 +
 2 files changed, 2 insertions(+)
 create mode 100644 file-B.txt
 create mode 100644 file-D.txt

(master)
$ git log --oneline --all --graph
* 103d89a (HEAD -> master, develop) commit-D
* 607f8e8 commit-B
* a144d6f file-C.txt
* f0a8fc2 commit-A

この状態でgit mergeコマンドを実行するとfast-forwardマージとなりコンフリクトは発生しません。

fast-forwardマージについては、以下の記事で紹介しています。

複数のcommitを1つのcommitにまとめる

git rebaseのもう一つの機能である「複数のcommitを1つのcommitにまとめる」について説明します。

利用用途として次のようなものがあります。

  • commitを細かく作成しすぎたので1つにまとめて管理したい
  • git rebase の前にcommitをまとめておくことでコンフリクトが発生した場合に対応しやすい

 

例えば、以下のようなcommit履歴があった場合に、commit(B)~commit(D)を1つのcommitにまとめる場合の手順について説明します。

 

まとめる前のcommit履歴を作成

rebase前の状態のcommit履歴を作成します。

最後のgit logの結果が図のrebase前の状態であることを確認してください。

(master)
$ echo 'aaa' > file-A.txt

(master)
$ git add .

(master)
$ git commit -m 'commit-A'
[master (root-commit) 2752dab] commit-A
 1 file changed, 1 insertion(+)
 create mode 100644 file-A.txt

(master)
$ echo 'bbb' > file-B.txt

(master)
$ git add .

(master)
$ git commit -m 'commit-B'
[master 588fb7c] commit-B
 1 file changed, 1 insertion(+)
 create mode 100644 file-B.txt

(master)
$ echo 'ccc' > file-C.txt

(master)
$ git add .

(master)
$ git commit -m 'commit-C'
[master e74ca24] commit-C
 1 file changed, 1 insertion(+)
 create mode 100644 file-C.txt

(master)
$ echo 'ddd' > file-D.txt

(master)
$ git add .

(master)
$ git commit -m 'commit-D'
[master 52f2eaa] commit-D
 1 file changed, 1 insertion(+)
 create mode 100644 file-D.txt

(master)
$ git log --oneline
52f2eaa (HEAD -> master) commit-D
e74ca24 commit-C
588fb7c commit-B
2752dab commit-A

git rebase -iコマンドでcommitをまとめる

次にrebaseコマンドでcommit(B)~(D)を1つにまとめます。

git rebaseのコマンドは以下のようにcommit-hashを指定します。

git rebase -i [commit-hash]
ポイント

指定するcommit-hashはまとめたいcommitの一つ前のcommit-hashを指定します。

git log でcommit(A)のcommit-hashを確認してgit rebase -i コマンドを実行します。

(master)
$ git log --oneline
52f2eaa (HEAD -> master) commit-D
e74ca24 commit-C
588fb7c commit-B
2752dab commit-A

(master)
$ git rebase -i 2752dab

 

git rebase -iコマンドを実行すると以下のようにエディタが起動します。

pick 588fb7c commit-B
pick e74ca24 commit-C
pick 52f2eaa commit-D

# Rebase 2752dab..52f2eaa onto 2752dab (3 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

commit(B)~(D)の3行が先頭に表示されています。

commitをまとめる場合は「pick」を「squash」に変更することで1つ前のcommitに含めることができます。

つまり、commit(C)とcommit(D)を「squash」することでcommit(B)にまとめることができます。

入力するとこうなります。

pick 588fb7c commit-B
s e74ca24 commit-C
s 52f2eaa commit-D

「squash」は省略して「s」とすることができます。

このように編集できたら、保存して終了します。

Vimの場合はEscキーでコマンドモードにし、「wq」と入力しましょう。

 

rebaseが正常に進むとcommitメッセージを編集する画面が表示されます。

commit(B)~(D)のcommitメッセージが表示されていますので、必要に応じて編集しましょう。

ここでは、「commit-B-C-D」と変更しました。

# This is a combination of 3 commits.
# This is the 1st commit message:

commit-B-C-D

# This is the commit message #2:

#commit-C

# This is the commit message #3:

#commit-D

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Mon Apr 6 15:52:50 2020 +0900
#
# interactive rebase in progress; onto 2752dab
# Last commands done (3 commands done):
#    s e74ca24 commit-C
#    s 52f2eaa commit-D
# No commands remaining.
# You are currently rebasing branch 'master' on '2752dab'.
#
# Changes to be committed:
#       new file:   file-B.txt
#       new file:   file-C.txt
#       new file:   file-D.txt

 

commitメッセージを編集を完了させると以下のようにrebaseの結果が表示されます。

(master)
$ git rebase -i 2752dab
[detached HEAD ad09fbf] commit-B
 Date: Mon Apr 6 15:52:50 2020 +0900
 3 files changed, 3 insertions(+)
 create mode 100644 file-B.txt
 create mode 100644 file-C.txt
 create mode 100644 file-D.txt
Successfully rebased and updated refs/heads/master.

 

git log コマンドでcommitがまとめられているか確認してみましょう。

(master)
$ git log --oneline
ad09fbf (HEAD -> master) commit-B-C-D
2752dab commit-A

git rebase の全てのオプションを確認する方法

以下のコマンドを実行するとブラウザでgit rebaseのヘルプページが表示される

git rebase --help

Gitコマンドの使い方一覧

git-command

Posted by snow