2017年07月18日

git コミットを取り消す

コミットしたものを取り消したい場面、
例えば、ある機能をコミットした後で、仕様変更が入り、運悪く、その機能がドロップしてしまった。
そのため、コミットしたものを削除することに。
再度、削除してコミットしても良いが、ケアレスミスで削除ミスが発生するかも。
コミットしたものを丸ごとなかったことにするのが確実。


コミットの取り消し


git_revert01.png
$ git log --oneline --graph
* e3ac1eb new_branch 追加 3
* 5cb8c6a new_branch 追加 2
* 4f42c71 new_branch 追加 1
* 1f391e3 master 追加 2
* 6edb23d master 追加 1

コミット(2):5cb8c6a と、コミット(3): e3ac1eb の差分を確認すると、
$ git diff 5cb8c6a e3ac1eb
diff --git a/index.html b/index.html
index 7743992..65aebf5 100755
--- a/index.html
+++ b/index.html

@@ -13,5 +13,6 @@
<h2>new_branch</h2>
<p>new_branch 追加 1</p>
<p>new_branch 追加 2</p>
+ <p>new_branch 追加 3</p>
</body>
</html>


コミット(3): e3ac1eb を取り消してみる。

$ git revert e3ac1eb

$ git log --oneline --graph
* 2e3f015 Revert "new_branch 追加 3"
* e3ac1eb new_branch 追加 3
* 5cb8c6a new_branch 追加 2
* 4f42c71 new_branch 追加 1
* 1f391e3 master 追加 2
* 6edb23d master 追加 1

コミット(3):e3ac1eb と、HEADコミット: 2e3f015 の差分を確認すると、
追加されていた変更が削除されている。
$ git diff e3ac1eb 2e3f015
diff --git a/index.html b/index.html
index 65aebf5..7743992 100755
--- a/index.html
+++ b/index.html

@@ -13,6 +13,5 @@
<h2>new_branch</h2>
<p>new_branch 追加 1</p>
<p>new_branch 追加 2</p>
- <p>new_branch 追加 3</p>
</body>
</html>


"revert" 操作は、指定したコミットを打ち消す内容を作成し、コミットする。

コミットした内容を無かったことにするのではなく、コミットした履歴も、コミットを訂正した履歴も両方ともにきちんと残る。またコミットした内容を取り消すときに、gitが訂正内容を準備するので、ヒューマンエラーによるミスを防ぐことにもつながり、訂正するときに便利。
git_revert02.png





複数のコミットの取り消し


取り消したいコミットが複数ある場合を考える。
git_revert01.png
$ git log --oneline --graph
* e3ac1eb new_branch 追加 3
* 5cb8c6a new_branch 追加 2
* 4f42c71 new_branch 追加 1
* 1f391e3 master 追加 2
* 6edb23d master 追加 1

コミット(1):4f42c71 と、コミット(3): e3ac1eb の差分を確認すると、
$ git diff 4f42c71 e3ac1eb
diff --git a/index.html b/index.html
index 200b61d..65aebf5 100755
--- a/index.html
+++ b/index.html

@@ -12,5 +12,7 @@
<h2>new_branch</h2>
<p>new_branch 追加 1</p>
+ <p>new_branch 追加 2</p>
+ <p>new_branch 追加 3</p>
</body>
</html>


コミット(3):e3ac1eb と、コミット(2): 5cb8c6a を取り消してみる。
コミットを複数取り消す場合、コミットした順番と逆の順序で、"revert" することで目的を達する。
$ git revert e3ac1eb
$ git revert 5cb8c6a

$ git log --oneline
3ff18a9 Revert "new_branch 追加 2"
06f718a Revert "new_branch 追加 3"
e3ac1eb new_branch 追加 3
5cb8c6a new_branch 追加 2
4f42c71 new_branch 追加 1
1f391e3 master 追加 2
6edb23d master 追加 1

git_revert03.png

単純だが、これだと訂正したいコミット数だけ、訂正コミットを行うので手間がかかるし、後から見たときに見通しが良くない。

ただ、確実に1つ1つ対応しないと不安だという場合は、このようにすべきであるが、
せめて後から履歴を眺めたときに見通しをよくするために、訂正コミットをすべて行った後、"git rebase -i" で "squash" するのがおすすめ。
訂正時に1つ1つ対応することで安心できるし、コミット履歴が整理されるので見通しが良くなる。



せめて "rebase" の手間ぐらい省きたい場合は、"revert" 操作に、"-n" or "--no-commit" オプションを指定するとよい。"-n" オプションは、逆マージまで行い、コミットを行わない操作。
コミットした順版と逆順でマージ操作のみを行い、最後にコミットする。

$ git revert -n e3ac1eb
$ git revert -n 5cb8c6a
$ git commit

$ git log --oneline
eaac52c Revert "new_branch 追加 1" & "new_branch 追加 2"
e3ac1eb new_branch 追加 3
5cb8c6a new_branch 追加 2
4f42c71 new_branch 追加 1
1f391e3 master 追加 2
6edb23d master 追加 1

git_revert04.png
後から、"squash" する必要がないので、少し手間が省ける。





マージコミットの取り消し


ブランチを切って対応した機能を本流にマージした後に仕様ドロップになってしまった場合を考える。
git_revert05.png
$ git log --oneline --graph
* ca27af6 Merge branch 'new_branch'
|\
| * 5cb8c6a new_branch 追加 2
| * 4f42c71 new_branch 追加 1
* | 509957a master 追加 3
|/
* 1f391e3 master 追加 2
* 6edb23d master 追加 1


マージコミット(D):ca27af6 に対して、"revert" 操作を行うと、
$ git revert ca27af6
error: Commit ca27af63e56738811fb79d06a44b35e5de60dd21 is a merge but no -m option was given.
fatal: revert failed

と、エラーメッセージが出る。
つまりは、マージコミットに対しては普通には "revert" できない。"-m" オプションを指定しなさいと。

"-m" or "--mainline" を使うときは続けて、"parent-number" を指定する。
"parent-number" は、"git show" を見るとわかる。
$ git show ca27af6
commit ca27af63e56738811fb79d06a44b35e5de60dd21
Merge: 509957a 5cb8c6a
・・・

マージすると、親コミットが複数存在する。"git show" で示される、①509957a と、②5cb8c6a が親コミット。

マージコミットに対して "revert" で訂正した場合、どのブランチの流れで訂正するのか?
git_revert06.png

これを指定するのが、"-m" オプション。
"git show" の結果で、"master" ブランチ側は1、"new_branch" ブランチ側が2 とわかった。
"new_branch" ブランチを、"master" ブランチへマージしたことを訂正したいので、"-m 1" を指定する。

$ git revert -m 1 ca27af6

$ git log --oneline --graph
* a30ed5c Revert "Merge branch 'new_branch'"
* ca27af6 Merge branch 'new_branch'
|\
| * 5cb8c6a new_branch 追加 2
| * 4f42c71 new_branch 追加 1
* | 509957a master 追加 3
|/
* 1f391e3 master 追加 2
* 6edb23d master 追加 1






マージコミット取り消しの注意点


マージするのが早かったと思い、一旦、"revert" でマージコミットを取り消し、取り消したブランチ側で継続して作業を行い、再度マージしたとする。
git_revert07.png
$ git log --oneline --graph
* a6ea348 new_branch 追加 4
* 20655ff new_branch 追加 3
* 5cb8c6a new_branch 追加 2
* 4f42c71 new_branch 追加 1
* 1f391e3 master 追加 2
* 6edb23d master 追加 1

コミット(1):4f42c71 と、コミット(4): a6ea348 の差分を確認する。
$ git diff 4f42c71 a6ea348
diff --git a/index.html b/index.html
index 200b61d..7743992 100755
--- a/index.html
+++ b/index.html

@@ -12,5 +12,6 @@
<h2>new_branch</h2>
<p>new_branch 追加 1</p>
+ <p>new_branch 追加 2</p>
</body>
</html>
diff --git a/readme.txt b/readme.txt
new file mode 100644
index 0000000..02ab331
--- /dev/null
+++ b/readme.txt

@@ -0,0 +1,3 @@
+readme
+readme 変更
+



この状態でマージしてみる。

$ git checkout master
$ git merge new_branch

$ git log --oneline --graph
* 77c32e4 Merge branch 'new_branch'
|\
| * a6ea348 new_branch 追加 4
| * 20655ff new_branch 追加 3
* | a30ed5c Revert "Merge branch 'new_branch'"
* | ca27af6 Merge branch 'new_branch'
|\ \
| |/
| * 5cb8c6a new_branch 追加 2
| * 4f42c71 new_branch 追加 1
* | 509957a master 追加 3
|/
* 1f391e3 master 追加 2
* 6edb23d master 追加 1



マージ前後の差分を確認してみる。コミット:a30ed5c と、コミット: 77c32e4 の差分を確認。
$ git diff a30ed5c 77c32e4
diff --git a/readme.txt b/readme.txt
new file mode 100644
index 0000000..02ab331
--- /dev/null
+++ b/readme.txt

@@ -0,0 +1,3 @@
+readme
+readme 変更
+



すると、訂正したマージコミット分の差分(コミット(1):4f42c71 、コミット(2):5cb8c6a)が反映されていないことがわかった。
git_revert08.png

これは、マージしたことをブランチ操作として管理しているが、"revert" はブランチ管理外の操作のため、マージが訂正され、本流から削除されてしまったことはブランチの動きとして把握していない。
そのため前回マージされたコミット位置(コミット(2): 5cb8c6a)が基準となり、今回のマージが作成された。結果、コミット(1):4f42c71 、コミット(2):5cb8c6a がマージに含まれない状態でマージされている。

この動作を理解できていないと、マージしたつもりでも実際にはマージできていないので注意が必要。


では、この場合はどうするのか?

この場合、マージコミットを "revert" したものを、再度 "revert" し直すしかない。
git_revert09.png





まとめ


コミットした内容を取り消すには、再度、元の形に変更したファイルでコミットし直せば良い。
ただ、ヒューマンエラーを起こさないためにも、git に備わる機能で "revert" という便利な機能を使って、スマートな対応をしたい。
ただし、マージコミットを訂正した場合は、その後の動作を理解していないと嵌る。無駄な労力を使わないためにも、しっかりと理解して使いたい。


gitをインストール
gitサーバーのセットアップ
git ブランチについて
git 変更を一時的に退避 stash
git ブランチを合流するマージ
git ブランチを付け替える
git コミット履歴を変更する
git 変更をリセットする
git リモートでの操作
git ファイルの追跡
git リリース準備
git リモートブランチを追加
git チェックアウトをもっと便利に使う
git プロジェクトの構成
git 変更をpatchファイルにする
git コンフリクトに対処する
git 失敗したときの復元


posted by Zorinos at 20:00| Comment(0) | Linux | 更新情報をチェックする
この記事へのコメント
コメントを書く
コチラをクリックしてください
ブログランキング・にほんブログ村へ
×

この広告は180日以上新しい記事の投稿がないブログに表示されております。