GitHubな話 〜git rebase -i編〜

GitHubな話 〜git rebase -i編〜

ペパボに入ってはや1ヶ月が経とうとしています。
おかげさまで毎日楽しく、新鮮な日々を過ごしています。
入社後2週間は研修やらオリエンテーションを実施してもらえたので
実務に入ってから2週間たったところです。
技術的な壁やコードがわからないといった状況は今のところ
ないのですが、チームで開発するにあたって、まだまだ適応できていない
部分があるので週末ちょっと整理してみました。
ペパボではコードの履歴管理や業務でGitHubを利用しています。

github-logo
既存コードの改修を行う際は、改修の単位でブランチを立てて、
プルリク投げて、各々ブランチを育てて、改修が終わったら
チームメンバーがチェックしてマージするというのが基本的な流れで、
僕自身まだちょっとうまくやれてない感じです。

問題点

  • PR(プルリク)の記載情報、スコープがダサい
  • コミットの単位がばらばら

特にコミットの単位がばらばらなのがちょっとつらたんで、
コミットの単位がばらばらだと何が悪いかというと、

  • そのコミットがなにを修正したのかわかりづらい
  • 同じような意図のコミットが散在して確認が大変
  • バグ修正や手戻りのコミットが増えるとわけがわからなくなる

これを解決するために、
git rebase -i
git reset -soft + git add -p
2つのコマンドを抑えていきます。
この2つを抑えておけばコミットログが整理出来るようになり、
見渡しのいいコミットログになります。
学習に際して、簡単なファイル、実装する内容、起きうるトラブルシナリオを扱います。

使用するファイル

まずfile1.txtとfile2.txtというファイルに下記の内容を記述します。
[Shell]
if(value==A) {
echo “Aが呼ばれた”;
else if(value==B){
echo “Bが呼ばれた”;
}
[/Shell]

変更する内容

次にこのファイルに対して下記の変更を加えていくものとします。

  • 実装内容1.if条件Aの削除
  • 実装内容2.if条件BをCへ変更
  • 実装内容3.if条件Dを追加

トラブルシナリオ

そして起きうるトラブルとして、
シナリオ1
if条件Aをfile2.txtから削除し忘れたまま
実装内容2、3が終わってしまった。

シナリオ2
実装内容2のコミット忘れてしまった

この2つを扱っていきましょう。

やってみる

ではまずシナリオ1から。
まずは条件Aをfile1.txtから削除して、git diffを取ります。
シナリオ1ではfile2.txtからの削除を忘れてしまうので、

[Diff]
~/git_learn/scenario1 (master) % git diff [14:25:29]
diff –git a/file1.txt b/file1.txt
index 48ab8d6..65d968d 100644
— a/file1.txt
+++ b/file1.txt
@@ -1,5 +1,3 @@
-if(value==A) {
– echo “Aが呼ばれた”;
-else if(value==B){
+if(value==B){
echo “Bが呼ばれた”;
}
[/Diff]
このようにfile1.txtの差分しか出ません。
その後、「if条件BをCへ変更」、「if条件Dを追加」を実行した後のファイルがこちら。
[Shell]
~/git_learn/scenario1 (master) % cat file1.txt [14:36:53]
if(value==C){
echo “Bが呼ばれた”;
}else if(value==D){
echo “Dが呼ばれた”;
}
~/git_learn/scenario1 (master) % cat file2.txt [14:36:59]
if(value==A) {
echo “Aが呼ばれた”;
else if(value==C){
echo “Bが呼ばれた”;
}else if(value==D){
echo “Dが呼ばれた”;
}
[/Shell]

コミットログ
[Shell]
2014-09-28 14:36 ka-yamashita o [master] 3.if条件Dを追加
2014-09-28 14:35 ka-yamashita o 2.if条件BをCへ変更
2014-09-28 14:34 ka-yamashita o 1.if条件Aの削除
2014-09-28 14:33 ka-yamashita I シナリオ1開始
[/Shell]

こんな状態になってから、

ぬぉぉぉぉーーー、file2.txtのif条件A消し忘れとるーーー!!!

ということに気づいて、file2.txtの条件を削除した後に、コミットをきると
コミットログはこんな感じになります。

[Shell]
2014-09-28 14:37 ka-yamashita o [master] [バグ修正]if条件Aの削除漏れ
2014-09-28 14:36 ka-yamashita o 3.if条件Dを追加
2014-09-28 14:35 ka-yamashita o 2.if条件BをCへ変更
2014-09-28 14:34 ka-yamashita o 1.if条件Aの削除
2014-09-28 14:33 ka-yamashita I シナリオ1開始
[/Shell]

まあこれでもいいんですけど、後から見た時に確認しづらいですし、
ダサいですよね。
これを解決してくれるのが、git rebase -iというコマンドです。
具体的にどういう動作をするかというと、一時的に1.if条件Aの削除
コミットを切る前の状態まで戻った後に不足分の作業を行なって再コミットを行うような
ことをやります。

まずはgit logコマンドでコミットのハッシュ値を調べます。

[Shell]
~/git_learn/scenario1 (master) % git log [14:44:
commit 5e8e0a7719a4064004fa4fdb2f4e5da696d7ea89
Author: ka-yamashita
Date: Sun Sep 28 14:36:14 2014 +0900

3.if条件Dを追加

commit f00f3e698a8b714d2ab06075dfbd325683bd5f6c
Author: ka-yamashita
Date: Sun Sep 28 14:35:01 2014 +0900

2.if条件BをCへ変更

commit 5ac9988a232fdad021a32f8a706a785fe16e352b
Author: ka-yamashita
Date: Sun Sep 28 14:34:13 2014 +0900

1.if条件Aの削除

commit 8008d1f9f84c83b3289d2d8a8890d2134386f181
Author: ka-yamashita
Date: Sun Sep 28 14:33:17 2014 +0900

シナリオ1開始
[/Shell]
今回は1.if条件の削除の漏れがあったので、発行するコマンドはこうなります。

git rebase -i 8008d1f9f84c83b3289d2d8a8890d2134386f181

このコマンドを発行するとvimが開き下記の内容が記載されています。
[Shell]
1 pick 5ac9988 1.if条件Aの削除
2 pick f00f3e6 2.if条件BをCへ変更
3 pick 5e8e0a7 3.if条件Dを追加
4
5 # Rebase 8008d1f..5e8e0a7 onto 8008d1f
6 #
7 # Commands:
8 # p, pick = use commit
9 # r, reword = use commit, but edit the commit message
10 # e, edit = use commit, but stop for amending
11 # s, squash = use commit, but meld into previous commit
12 # f, fixup = like “squash”, but discard this commit’s log message
13 # x, exec = run command (the rest of the line) using shell
14 #
15 # These lines can be re-ordered; they are executed from top to bottom.
16 #
17 # If you remove a line here THAT COMMIT WILL BE LOST.
18 #
19 # However, if you remove everything, the rebase will be aborted.
20 #
21 # Note that empty commits are commented out
[/Shell]

注目すべきはこの部分。
[Shell]
1 pick 5ac9988 1.if条件Aの削除
2 pick f00f3e6 2.if条件BをCへ変更
3 pick 5e8e0a7 3.if条件Dを追加
[/Shell]
これは各々のコミットをどう扱うかを指定する部分で、pickはこのコミットをそのまま採用するという意味です。
よく使うのはedit(編集)とfixup(前のコミットに統合する)でしょうか。
今回は編集したいので、下記のように書き換えてvimを保存終了します。
[Shell]
1 edit 5ac9988 1.if条件Aの削除
2 pick f00f3e6 2.if条件BをCへ変更
3 pick 5e8e0a7 3.if条件Dを追加
[/Shell]

するとターミナルがこんな表示になって、リポジトリの状態が一時的に、
if条件Aの削除のコミットを切る直前の状態となります。
[Shell]
~/git_learn/scenario1 (master) % git rebase -i 8008d1f9f84c83b3289d2d8a8890d2134386f181 [14:44:37]
Stopped at 5ac9988… 1.if条件Aの削除
You can amend the commit now, with

git commit –amend

Once you are satisfied with your changes, run

git rebase –continue

~/git_learn/scenario1 (git)-[master|rebase-i] %
[/Shell]

この時点でfile2.txtからif条件Aを削除し忘れた過去を書き換えたいので、
作業をしていきます。

作業前の状態
[Shell]
~/git_learn/scenario1 (git)-[master|rebase-i] % cat file2.txt [14:55:32]
if(value==A) {
echo “Aが呼ばれた”;
else if(value==B){
echo “Bが呼ばれた”;
}
[/Shell]

ファイルを編集してgit diffを取っていきます。

[Diff]
~/git_learn/scenario1 (git)-[master|rebase-i] % git diff [15:00:19]
diff –git a/file2.txt b/file2.txt
index 48ab8d6..65d968d 100644
— a/file2.txt
+++ b/file2.txt
@@ -1,5 +1,3 @@
-if(value==A) {
– echo “Aが呼ばれた”;
-else if(value==B){
+if(value==B){
echo “Bが呼ばれた”;
}
[/Diff]

あとはgit addコマンドで編集したfile2.txtをインデックスに登録し、
git commit –amendコマンドで再コミットを行い、
git rebase –continueで最新のコミットまで追いかけ処理を
行うと、ファイルもあるべき状態になり、
[Shell]
~/git_learn/scenario1 (master) % cat file1.txt [15:06:07]
if(value==C){
echo “Bが呼ばれた”;
}else if(value==D){
echo “Dが呼ばれた”;
}
~/git_learn/scenario1 (master) % cat file2.txt [15:06:14]
if(value==C){
echo “Bが呼ばれた”;
}else if(value==D){
echo “Dが呼ばれた”;
}
[/Shell]

コミットログも整然としています。

[Shell]
2014-09-28 14:36 ka-yamashita o [master] 3.if条件Dを追加
2014-09-28 14:35 ka-yamashita o 2.if条件BをCへ変更
2014-09-28 14:34 ka-yamashita o 1.if条件Aの削除
2014-09-28 14:33 ka-yamashita I シナリオ1開始
[/Shell]

このコマンドをマスターしておけば、めっちゃ手戻りとか、
開発中のバグ多いのに、
コミットログ上では完璧に仕事をこなすなんとなく仕事ができるやつ感を
漂わせることが出来るでしょう。
次回はもうちょっとガツンとコミットログを編集できる、
git reset –soft + git app -p(e)
シナリオ2で扱いたいと思います。
それでは良い休日を。

コメントは受け付けていません。