Git スカッシュコミット

Azhar Bashir Khan 2023年1月30日
  1. 対話的な git rebase ツールによる Git コミットのスカッシュ
  2. git merge -squash を使用して Git コミットをスカッシュする
Git スカッシュコミット

このチュートリアルでは、Git スカッシュについて学習します。基本的な考え方は、複数の連続したコミットを取り、それらを 1つに押しつぶすことです。

主な目的は、多くのコミットをいくつかの関連するコミットに凝縮することです。したがって、これを行うと、git の履歴が簡潔で明確に見えます。

別の見方をすれば、あるタスクに関連する複数のコミットを実行することです。しばらくして、満足のいく状態に達すると、多くのコミットメッセージが git の履歴を乱雑にします。

この時点で、さまざまなコミットを 1つにまとめて、git の履歴が明確になり、実行されたタスクを最もよく反映するようにすることができます。

もう 1つの使用例は、ブランチのマージを実行しながらスカッシュを実行することです。通常、一部の機能開発のために、メインブランチから機能ブランチを作成します。

機能の完了後、機能ブランチをメインブランチにマージします。ここでも、メインブランチにマージするときに、機能ブランチで行われたさまざまなコミットメッセージを 1つにまとめたい場合があります。

git squash コマンドがないことに注意してください。

Git スカッシュを実現するには 2つの方法があります。

  • コミットを潰すために使用されるインタラクティブツールとしての git rebase -i
  • マージ中に -squash オプションを使用する git merge -squash

対話的な git rebase ツールによる Git コミットのスカッシュ

次の git log を見てみましょう。これは、押しつぶすことに関心がある HEAD からの最後の 4つのコミットを示しています。

25c38c4 remove .class files
da66e6a Delete version.ini
f4e3f09 Delete .log
b0e6655 Delete .lock
da66e6a github git notes

ログには、関係のないさまざまなファイルを削除する操作を示す最初の 4つのコミットメッセージが表示されます。次に、これら 4つのコミットを 1つにまとめます。

以下は、インタラクティブリベースツールを使用して最後の X コミットを押しつぶすコマンドの構文です。

git rebase -i HEAD~[X]

したがって、4つのコミットを潰すには、次のようにします。

$ git rebase -i HEAD~4

このコマンドを発行した後、Git は、以下に示すように、スカッシュへのコミットの詳細を含むデフォルトのエディターを呼び出します。

pick b0e6655 Delete .lock
pick f4e3f09 Delete .log 
pick da66e6a Delete version.ini
pick 25c38c4 remove .class files

# Rebase 652d2fe..25c38c4 onto 652d2fe (4 command(s))
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit
#
# 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

エディターは、pick コマンドを使用してさまざまなコミットを表示します。また、使用可能なコマンドに関する情報も表示されます。squash(または s)コマンドを使用します。

以下に示すように、最初のコミットは pick コマンドで保持し、残りの 3つのコミットでは pick から s(スカッシュの場合)コマンドに変更します。

pick b0e6655 Delete .lock
s f4e3f09 Delete .log 
s da66e6a Delete version.ini
s 25c38c4 remove .class files

# Rebase 652d2fe..25c38c4 onto 652d2fe (4 command(s))
#
...

squash(または s)でマークされたコミットは、メインのコミットにマージされます。pick でマークされたもの。

次に、変更をエディターに保存して終了します。この後、rebase -i ツールは、以下のように、コミットメッセージを入力するための別のエディターを開きます。

# This is a combination of 4 commits. The first commit's message is:

Delete .lock

# This is the 2nd commit message:

Delete .log 

# This is the 3rd commit message:

Delete version.ini

# This is the 4th commit message:

remove .class files

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Sun Jan 3 16:39:23 2021 +0530
#
# interactive rebase in progress; onto 652d2fe
# Last commands done (4 commands done):
#    pick b0e6655 Delete .lock
#    s f4e3f09 Delete .log 
#    s da66e6a Delete version.ini
#    s 25c38c4 remove .class files
# No commands remaining.
# You are currently editing a commit while rebasing branch 'master' on '652d2fe'.
#
# Changes to be committed:
#       new file:   github-git-notes.txt
#

ここで、最初のコミットメッセージの先頭に新しいコミットメッセージを追加します。

Deleted irrelevant files

# This is a combination of 4 commits. The first commit's message is:

Delete .lock

# This is the 2nd commit message:

Delete .log
...

保存してエディタを終了すると、rebase -i ツールは次のメッセージを出力します。

HEAD~2
Rebasing (2/2)


[detached HEAD caab6e8] Deleted irrelevant files
 Date: Sun Jan 3 16:39:23 2021 +0530
 1 file changed, 54 insertions(+)
 create mode 100644 github-git-notes.txt
Successfully rebased and updated refs/heads/master.

ここで、git log を確認し、4つのコミットメッセージではなく、squashed コミット(つまり)単一のコミットメッセージを確認します。

$ git log --oneline
25c38c4 Deleted irrelevant files
da66e6a github git notes
...

git merge -squash を使用して Git コミットをスカッシュする

以下は、ブランチを現在のブランチ(通常は main)とマージし、ソースブランチのコミットを潰すためのコマンドの構文です。

git merge --squash <source_branch_name_to_squash>

ここで、機能ブランチをマージします。feature1``main ブランチで押しつぶします。

まず、メイン​​ブランチにチェックアウトします。

$ git checkout main
Switched to branch 'main'

次に、次のように squash オプションを使用して git merge を実行します。

$ git merge --squash feature1
Squash commit -- not updating HEAD
Automatic merge went well; stopped before committing as requested

--squash オプションを指定して merge を実行すると、Git は通常のマージの場合のように、宛先ブランチにマージコミットを作成しません。代わりに、Git はソースブランチのすべての変更を取得します。feature1 そしてそれを宛先ブランチの作業コピーである main にローカルな変更として反映させます。

下記を参照してください。

$ git status
On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	modified:   config.ini

ここで、ファイル config.ini には、feature1 ブランチで行われた変更が含まれています。

残っているのは、以下のように main ブランチに変更をコミットすることだけです。

$ git commit -am 'Merged and squashed the feature1 branch changes'
[main 573b923] Squashed and merged the feature1 branch
 1 file changed, 4 insertions(+)

したがって、feature1 ブランチのコミットメッセージを潰すこととともに、feature1 ブランチの変更を main ブランチにマージしました。現在、main ブランチにはコミットメッセージが 1つだけあります。

関連記事 - Git Rebase

関連記事 - Git Merge