はじめに
master ブランチに最新版がマージされたあと、問題が見つかってリリース前に戻したいときがたまにあります。しかし git-revert
/git-reset
は普段使うことがないので、少し身構えてしまいますね。今回はこれらのコマンドを簡単なサンプルを見ながら動きを確認していきます。
git-revert/git-resetとは
どちらも変更点を打ち消すためのGitコマンドになります。
どのような違いがあるのか見てみましょう。
一応、公式のドキュメントに書いてある説明です。
難しいのでざっくり以下の認識でOKです。
どういうことか触りながらサンプルを見ながら説明します。
まずはおさらい git-rebase / git-merge
git-rebase
分岐先のコミットを古いものから順に舐めていき、分岐元へと順次取り込んでいく。
git-merge
分岐先の差分を分岐元に合体する。
ハンズオン
では、次に git-revert/git-reset のサンプルを見ながら手を動かしながら見てみましょう。
git-reset
以下のコードをコピペして実行してください。実行すると下図のような状態になります。
# msaterブランチを作成
mkdir gitHandsOn && cd gitHandsOn
git init
echo "A" >> work.txt
git add . && git commit -m "Commit A"
# featureブランチに切り替えてコミットAからコミットDを作成
git checkout -b feature
echo "B" >> work.txt
git add . && git commit -m "Commit B"
echo "C" >> work.txt
git add . && git commit -m "Commit C"
echo "D" >> work.txt
git add . && git commit -m "Commit D"
# git-rebase
git checkout master && git rebase - && git log --oneline
次にgit-resetしてみましょう。
まずはさきほどのコミットDを打ち消してみます。
git checkout master
# コミットログを表示
git log --oneline
---------------------------------------------------------------
8254890 (HEAD -> master, feature) Commit D
5a5afaf Commit C
09d38a1 Commit B
383454e Commit A
---------------------------------------------------------------
# コミットDを打ち消してみましょう
# まずは以下のようにコミットDのコミットログを指定して、git-resetを叩いてください
git reset --hard 8254890
git log --oneline
いかがですか、消えましたか?
消えませんね。
どういうことか。
git-resetは指定されたコミットにHEADを移動させる
コマンドなので、コミットDを指定してもコミットDは打ち消されません。
では改めてコミットDを打ち消してみましょう。
git checkout master
# コミットログを表示
git log --oneline
---------------------------------------------------------------
8254890 (HEAD -> master, feature) Commit D
5a5afaf Commit C
09d38a1 Commit B
383454e Commit A
---------------------------------------------------------------
# コミットDを打ち消してみましょう
# 改めて以下のようにコミットDのコミットログを指定して、git-resetを叩いてください
git reset --hard 5a5afaf
git log --oneline
---------------------------------------------------------------
5a5afaf (HEAD -> master) Commit C
09d38a1 Commit B
383454e Commit A
---------------------------------------------------------------
コミットDが無事に打ち消されました。
演習1
最初にコピペしたコードを使って以下の状態にしてください。
※ 答えは一番最後に載せておきます。
hard と soft の違いについて
hard
はコミットを打ち消すとともにローカルの内容も移動後のHEADの時点に戻します。
soft
オプションを使用すると、コミットは打ち消されるが、ローカルの内容はそのまま保持されます。これは、修正内容を維持しつつコミットだけを削除したい場合に適しています。
演習2
最初にコピペしたコードを使って以下の状態にしてください。
※ 答えは一番最後に載せておきます。
git-revert
以下のコードをコピペして実行してください。実行すると下図のような状態になります。
# msaterブランチを作成
mkdir gitHandsOn && cd gitHandsOn
git init
echo "A" >> work.txt
git add . && git commit -m "Commit A"
# featureブランチに切り替えてコミットAからコミットDを作成
git checkout -b feature
echo "B" >> work.txt
git add . && git commit -m "Commit B"
echo "C" >> work.txt
git add . && git commit -m "Commit C"
echo "D" >> work.txt
git add . && git commit -m "Commit D"
# git-merge
# mergeの際にコミットコメントが必要なのでそのまま保存をしてください
git checkout master && git merge --no-ff - && git log --oneline
git checkout master
# コミットログを表示
git log --oneline
---------------------------------------------------------------
5b96ca7 (HEAD -> master) Merge branch 'feature'
2757f8e Commit A
914017f (feature) Commit D
711f950 Commit C
b66b20c Commit B
---------------------------------------------------------------
# マージコミットを指定してrevertを実行しくてださい
git revert 5b96ca7
いかがですか、消えましたか?
消えませんね。
どういうことか。
マージコミットを打ち消したいときは mainline というオプションを付与してあげる必要があります。
そしてマージコミットを打ち消す場合には mainline に 1 を指定してあげます。
小話 - mainline
mainline とは Git の parent-number のことです。git-merge とは2つのブランチを合体させることですが、どのブランチのコミットを合体させたかを以下のコマンドで調べることができます。
$ git show マージコミットのID
commit 5b96ca711b150aa66108fead2442699f8203ad9d (HEAD -> master)
Merge: 2757f8e 914017f
Author: takiguchi-yu
Merge branch 'feature'
ここでいうと
2757f8e が mainline=1 で
914017f が mainline=2 ということになります。
では改めてマージコミットを打ち消してみましょう。
git checkout master
# コミットログを表示
git log --oneline
---------------------------------------------------------------
5b96ca7 (HEAD -> master) Merge branch 'feature'
2757f8e Commit A
914017f (feature) Commit D
711f950 Commit C
b66b20c Commit B
---------------------------------------------------------------
# マージコミットを指定してrevertを実行しくてださい
git revert --mainline 1 5b96ca7
git log --oneline
---------------------------------------------------------------
ce3046a (HEAD -> master) Revert "Merge branch 'feature'"
5b96ca7 Merge branch 'feature'
2757f8e Commit A
914017f (feature) Commit D
711f950 Commit C
b66b20c Commit B
---------------------------------------------------------------
無事できました。revert は reset と違ってコミットが残ります。
コミットログが残せる=一旦、チーム内でレビューを通せる
、などのメリットがありますね。
演習3
最初にコピペしたコードを使って以下の状態にしてください。
※ 答えは一番最後に載せておきます。
さいごに
結構業務だと対策前進してしまうことも多いのですが、こうしたコマンドを知っておくことで気軽に?切り戻しができますね!
演習の解答サンプル
演習1
git checkout master
git log --oneline
---------------------------------------------------------------
8254890 (HEAD -> master, feature) Commit D
5a5afaf Commit C
09d38a1 Commit B
383454e Commit A
---------------------------------------------------------------
# git-reset はHEADの移動させるコマンドなので、コミットAを指定してあげれば良い
git reset --hard 383454e
git log --oneline
---------------------------------------------------------------
383454e (HEAD -> master) Commit A
---------------------------------------------------------------
演習2
git checkout master
git log --oneline
---------------------------------------------------------------
8254890 (HEAD -> master, feature) Commit D
5a5afaf Commit C
09d38a1 Commit B
383454e Commit A
---------------------------------------------------------------
# softでresetすれば良い
git reset --soft 383454e
git log --oneline
---------------------------------------------------------------
383454e (HEAD -> master) Commit A
---------------------------------------------------------------
演習3
git checkout master
git log --oneline
---------------------------------------------------------------
5b96ca7 (HEAD -> master) Merge branch 'feature'
2757f8e Commit A
914017f (feature) Commit D
711f950 Commit C
b66b20c Commit B
---------------------------------------------------------------
# この場合は普通にコミットDのコミットIDを指定してあげれば良いですね
git revert 914017f
git log --oneline
---------------------------------------------------------------
ad37cf4 (HEAD -> master) Revert "Commit D"
76572dd Merge branch 'feature'
8b4e87e Commit A
3912023 (feature) Commit D
7454740 Commit C
99f5f37 Commit B
---------------------------------------------------------------