[Git] git rebase でコミット履歴をまとめる

コミットの履歴をまとめたり編集するためには、rebase コマンドを使います。

公開リポジトリにプッシュしたコミットをリベースしてはいけない

履歴の編集には git rebase を使いますが、必ず守らなければならない方針があります。
公開リポジトリにプッシュしたコミットをリベースしてはいけない」ということ。

git rebase

log を確認します。Assertions をまとめたい。

% git log
commit c56b8b9d676a51da3e776005b484d81bb1dd8cbe
Author: Taro Yamada <taro.yamada@gmail.com>
Date:   Wed Aug 28 21:21:15 2013 +0900
    Assertions
commit add6fe813d1132aca1ea4ccce9fbee09ff1a10da
Author: Taro Yamada <taro.yamada@gmail.com>
Date:   Wed Aug 28 21:16:10 2013 +0900
    Assertions
commit a68b4ef225e16ca85ad8b5c989676a849b72cbc5
Author: Taro Yamada <taro.yamada@gmail.com>
Date:   Wed Aug 28 14:46:34 2013 +0900
    added test data
commit e069a5f35a891999265d38b6c40e39b638a41d9f
Author: Taro Yamada <taro.yamada@gmail.com>
Date:   Tue Aug 27 21:42:44 2013 +0900
    add README.md

rebase で、例えば直近5件のコミットを編集します。
ブランチ名やチェックサムの指定も可能。

% git rebase -i HEAD~5

テキストエディタが開き、編集画面が表示されます。
チェックサムが c56b8b9 のコミットを、直前の add6fe8 のコミットへまとめます。

pick fbbdc47 Excercise fix
pick e069a5f add README.md
pick a68b4ef added test data
pick add6fe8 Assertions
squash c56b8b9 Assertions
# Rebase 2af7444..c56b8b9 onto 2af7444
#
# 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
#
# 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

結果。

% git rebase -i HEAD~5
[detached HEAD c3a3b0d] Assertions
 14 files changed, 165 insertions(+), 246 deletions(-)
 create mode 100644 app/assets/javascripts/store.js.coffee
 create mode 100644 app/assets/stylesheets/layout.css.scss
 create mode 100644 app/assets/stylesheets/store.css.scss
 create mode 100644 app/controllers/store_controller.rb
 create mode 100644 app/helpers/store_helper.rb
 create mode 100644 app/views/store/index.html.erb
 delete mode 100644 public/index.html
 create mode 100644 test/functional/store_controller_test.rb
 create mode 100644 test/unit/helpers/store_helper_test.rb
Successfully rebased and updated refs/heads/master.
% git show-branch --more=10
[master] Assertions
[master^] added test data
[master~2] added READEME.md
[master~3] Validation
[master~4] Depot Scaffold
[master~5] first commit

複数のコミットをいくつかのコミットに、一度の編集でまとめることもできました。

% git rebase -i HEAD~10
[detached HEAD 2dd1e9f] Depot Scaffold
 26 files changed, 460 insertions(+), 8 deletions(-)
 create mode 100644 app/assets/images/.htaccess
 create mode 100644 app/assets/images/cs.jpg
 create mode 100644 app/assets/images/logo.png
 create mode 100644 app/assets/images/rtp.jpg
 create mode 100644 app/assets/images/ruby.jpg
 create mode 100644 app/assets/javascripts/products.js.coffee
 create mode 100644 app/assets/stylesheets/products.css.scss
 create mode 100644 app/assets/stylesheets/scaffolds.css.scss
 create mode 100644 app/controllers/products_controller.rb
 create mode 100644 app/helpers/products_helper.rb
 create mode 100644 app/models/product.rb
 create mode 100644 app/views/products/_form.html.erb
 create mode 100644 app/views/products/edit.html.erb
 create mode 100644 app/views/products/index.html.erb
 create mode 100644 app/views/products/new.html.erb
 create mode 100644 app/views/products/show.html.erb
 create mode 100644 db/migrate/20130827053957_create_products.rb
 create mode 100644 db/schema.rb
 rewrite db/seeds.rb (100%)
 create mode 100644 test/fixtures/products.yml
 create mode 100644 test/functional/products_controller_test.rb
 create mode 100644 test/unit/helpers/products_helper_test.rb
 create mode 100644 test/unit/product_test.rb
[detached HEAD 4f37d8a] Validation
 4 files changed, 98 insertions(+), 16 deletions(-)
Successfully rebased and updated refs/heads/master.

git push -f

このまま git push しても reject されてしまいます。

% git push origin master
To git@github.com:DriftwoodJP/Agile-Web-Development-with-Rails.git
 ! [rejected]        master -> master (non-fast-forward)
error: failed to push some refs to 'git@github.com:DriftwoodJP/Agile-Web-Development-with-Rails.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Merge the remote changes (e.g. 'git pull')
hint: before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

rebase したコミットはチェックサムが変わっているようで、このためでしょうか。

% git push -f origin master
Counting objects: 111, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (86/86), done.
Writing objects: 100% (92/92), 45.58 KiB | 0 bytes/s, done.
Total 92 (delta 25), reused 0 (delta 0)
To git@github.com:DriftwoodJP/Agile-Web-Development-with-Rails.git
 + e069a5f...43fba31 master -> master (forced update)

まだまだ勉強が必要。