git便利だけど難しい。ということでrebaseをつかわざるを得ないタイミングが合ったので実践したメモ。
参考:https://qiita.com/ykawakami/items/0d6826c529ad7c7b37dd
現象
コミットにミスがあった。10個コミットがあったとして、コミット2はどこからか紛れ込んできたミスである。
邪魔なのでrevertするコミットを2回に分けて、コミット4、コミット5としてコミットした。
その後、コミット2が正しい開発内容でリリースしたら内容が反映されない。自分がコミット4とコミット5をrevertしたせいだ。
履歴がカオスになってきたので、コミット2の取り込みと、コミット4/コミット5のrevertの履歴自体を取り消す。
コミット10
コミット9
コミット8
コミット7
コミット6
コミット5 ←これ
コミット4 ←これ
コミット3
コミット2 ←これ
コミット1
実践
git rebaseを使って直してみる。
$ git rebase -i [コミット1]
Interactive rebase already started
既にrebaseが始まっている??開幕から思ってたのと違う感じに。一旦abortします
$ git rebase --abort
再度実行
$ git rebase -i [コミット1]
Press Enter or type command to continue
pick [コミット0] [bugfix]...
# Rebase
#
# 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
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
rebaseコマンド叩いてから1分くらい待たされました。長いですね。
うまくいったっぽく見えたんですけど、pickに表示されてるコミット履歴が全部 [コミット1]よりも過去のもの。何か失敗したかな?一旦 :q
でvimモードを脱出します。
$ git log --oneline
コミット0
コミット1より上のコミットが全部消えました。ナンテコッタイ
一旦reflogで戻ります
$ git reflog
$ git reset --hard HEAD HEAD@{1}
$ git log --oneline
コミット10
コミット9
...
よかった、戻りました。怖い怖い
調べてみたら、一旦ここでコミット1よりも前のものを取り込んでから、随時rebaseしていく感じらしいです。調べ不足でした。
再度リベンジ
$ git rebase --abort
$ git rebase -i [コミット1]
何もせず保存
Automatic cherry-pick failed. After resolving the conflicts,
mark the corrected paths with 'git add <paths>', and
run 'git rebase --continue'
Could not apply ...
うわぁなんかコンフリクトしてますね。めんどくさい予感。
解決します。
$ git status
Not currently on any branch.
both modified:
both added:
なんか今いるブランチが不明扱いになってますね。怖くなってきた
とりあえず2件差分がでたので、コンフリクトを解消させます。
その後は、コメントに書いてある通りに git rebase --continue
を実行
$ git rebase --continue
ここで再度めちゃくちゃコンフリクトがおきます。
思っていた挙動と違いますし、怖くなってきたので一旦またreflogで戻りました。
なんか調べてた挙動と違うけど?
rebaseコマンドの表示されるコミットも、削除するためのdropコマンドもでてないんだけど。。
もしかして?と思ってversion確認
$ git --version
git version 1.7.1
やばい多分これめちゃくちゃ古いですね、適当にyumで入れた弊害がでてきました
調べてみたらgit version1.7.1 のリリースは 2010/04/24らしいです。これ使うの色々とよくないですね
gitの最新確認してみたら2.10~以降のバージョンがありました https://github.com/git/git/releases
バージョンアップを試してみます。 https://qiita.com/sirone/items/2e233ab9697a030f1335
怖いので、Dockerコンテナを1つ複製してgitの現状のコードをリモートリポジトリにアップしておきました。
これでぶっ壊れても安心だぜ!
自分の環境はCentOS6.6です。
$ sudo yum remove git
$ sudo yum install gcc curl-devel expat-devel gettext-devel openssl-devel zlib-devel perl-ExtUtils-MakeMaker
$ wget https://www.kernel.org/pub/software/scm/git/git-2.2.0.tar.gz
$ tar -zxf git-2.2.0.tar.gz
$ cd git-2.2.0
$ make prefix=/usr/local all
$ make prefix=/usr/local install
$ git --version
git version 2.2.0
OK、再挑戦します
$ git rebase -i e9909a0
It seems that there is already a rebase-merge directory, and
I wonder if you are in the middle of another rebase. If that is the
case, please try
git rebase (--continue | --abort | --skip)
If that is not the case, please
rm -fr "/var/www/smart/.git/rebase-merge"
and run me again. I am stopping in case you still have something
valuable there.
また --abort が必要みたいですね。というかさっきよりメッセージが詳しくなってるw
$ git reset --abord
$ git log --oneline
コミット-10
なんかめちゃくちゃ前の履歴に戻されました?もう嫌だ・・・
諦めずにとりあえずreflogで戻ります。
再再挑戦
$ git rebase -i [コミット1]
pick git [コミット2]
pick git [コミット3]
...
pick git [コミット10]
うおおおおおおきたぞ!いらないコミットの行を削除して保存します。
When you have resolved this problem, run "git rebase --continue".
If you prefer to skip this patch, run "git rebase --skip" instead.
To check out the original branch and stop rebasing, run "git rebase --abort".
コンフリクトしました。まぁこれは仕方ない。普通に修正します
vim ○○.pm # コンフリクト修正
git add ○○.pm
rebaseを再開します
git rebase --continue
またコンフリクトしました。
$ git status
deleted by them: hoge.pm
なんすかこれ・・・始めて見たステータス。
参考:https://qiita.com/yuya_presto/items/5d99499cf96c0ebb09f8
マージ元で削除された場合のコンフリクトパターンだとこのステータスになるらしいです。
関係ない話で申し訳ないですが、初めて知ったのでメモ。
$ git rm hoge.pm
continueします
そして…
Successfully rebased and updated [ブランチ名]
やったぜ。rebaseできました。 ログを確認します
$ git log --oneline
コミット10
コミット9
コミット8
コミット7
コミット6
コミット5
コミット3
コミット1
うげ、コミット5を消し忘れました。
もう一回rebaseします。
$ git rebase -i [コミット6]
コミット5を消して保存。そしたら
The previous cherry-pick is now empty, possibly due to conflict resolution.
If you wish to commit it anyway, use:
git commit --allow-empty
Otherwise, please use 'git reset'
rebase in progress; onto 6c1d39e
You are currently rebasing branch 'feature/JIRA_2482_develop' on '6c1d39e'.
nothing to commit, working directory clean
また新キャラ。前回のrebaseで空のcherry-pickがあるとか言ってきてますね。
とにかくコミットするなら(OKなら) git commit --allow-empty
しろって言ってるので叩きます。
$ git commit --allow-empty
コミットできました。rebase続けます。 continue
Successfully rebased and updated [ブランチ名]
やったぜ。今度こそ完了です。
結論
gitのバージョンが古い場合は気をつけよう!