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

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

[markdown]

> * [Git – 歴史の書き換え](http://git-scm.com/book/ja/Git-%E3%81%AE%E3%81%95%E3%81%BE%E3%81%96%E3%81%BE%E3%81%AA%E3%83%84%E3%83%BC%E3%83%AB-%E6%AD%B4%E5%8F%B2%E3%81%AE%E6%9B%B8%E3%81%8D%E6%8F%9B%E3%81%88)
> * [git – 2つのコミット履歴を1つに統合する – Qiita [キータ]](http://qiita.com/TechMeetMeet/items/5db3d020b143b085697d)
> * [gitのコミットの歴史を改変する(git rebase) 1 / 2 – けんごのお屋敷](http://tkengo.github.io/blog/2013/05/16/git-rebase-reference/)
> * [gitのコミットの歴史を改変する(git rebase) 2 / 2 – けんごのお屋敷](http://tkengo.github.io/blog/2013/06/08/git-rebase-reference2/)

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

履歴の編集には git rebase を使いますが、必ず守らなければならない方針があります。
「[公開リポジトリにプッシュしたコミットをリベースしてはいけない](http://git-scm.com/book/ja/Git-%E3%81%AE%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81%E6%A9%9F%E8%83%BD-%E3%83%AA%E3%83%99%E3%83%BC%E3%82%B9)」ということ。

> * [Git – リベース](http://git-scm.com/book/ja/Git-%E3%81%AE%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81%E6%A9%9F%E8%83%BD-%E3%83%AA%E3%83%99%E3%83%BC%E3%82%B9)
> * [反則技 git push -f – Qiita [キータ]](http://qiita.com/ppworks/items/94c0107d98e55f903ea9)

## git rebase

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

“`
% git log
commit c56b8b9d676a51da3e776005b484d81bb1dd8cbe
Author: Taro Yamada
Date: Wed Aug 28 21:21:15 2013 +0900
Assertions
commit add6fe813d1132aca1ea4ccce9fbee09ff1a10da
Author: Taro Yamada
Date: Wed Aug 28 21:16:10 2013 +0900
Assertions
commit a68b4ef225e16ca85ad8b5c989676a849b72cbc5
Author: Taro Yamada
Date: Wed Aug 28 14:46:34 2013 +0900
added test data
commit e069a5f35a891999265d38b6c40e39b638a41d9f
Author: Taro Yamada
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)
“`

まだまだ勉強が必要。

[/markdown]