Home > git > gitの付き合い方(4)

gitの付き合い方(4)

5月 27th, 2010

gitにはrevertというコマンドがあり、任意のコミットをなかったものとすることができます。resetコマンドとの違いは、resetコマンドが指定したコミット以降のコミットを消去してなかったものとするのに対して、revertコマンドはコミットを消去することなく、新たなコミットを付け足すことで指定のコミットをなかったものとすることです。

$ git revert HEAD
$ git revert HEAD^
$ git revert [revision]

はそれぞれ、直前のコミットの取り消し、ひとつ前のコミットの取り消し、特定のコミットの取り消しを意味します。resetコマンドと違い、revertコマンドは取り消そうとするコミット以降のコミットには影響を及ぼさないことに注意しましょう。つまりresetとrevertは本質的に異なるものです。revertするコミット以降のコミットで行われた作業は取り消されません。 git revertの効力をレポジトリを指定コミット時の状態に戻すと説明されている記事を多く見ますが、誤解されているような。(私が誤解してるのでなければ) 少なくとも実験してみた結果、取り消されるのは指定したコミットによる変更だけです。

さて、revertに指定したコミット以降のコミットが取り消そうとする指定コミットに依存している場合に問題が起きます。たとえばあるバグを直してコミットし、そのバグ修正に微妙な間違いがあったために修正をして再度コミットしたとします。最初のコミットをrevertしようとすると、次の修正コミットがその修正の元となったコミットを失うために困って(^^;;しまうのです。

これをコンフリクトと呼びます。コンフリクトはgitを使い込むようになると頻繁に遭遇する事象で、コンフリクトの解消をきちんと行っていくことは極めて大切な作業です。

それではここまでの作業を実験してみます。

$ git log
commit 44d2408d06cb8d2cf64d29468afd022606d4fca4
Author: XXX
Date:   Wed May 26 08:32:54 2010 +0300

file2 changed

commit 2dfdd066032fdf9f7c9d3ccd7becd399a4c4d11a
Author: XXX
Date:   Wed May 26 08:31:14 2010 +0300

file1 bugfix

commit f39be3e18efaadaf9e54702cf0f89a06824be8f5
Author: XXX
Date:   Wed May 26 08:30:02 2010 +0300

initial commit

ここでfile1のbugfixのコミットを取り消します。

$ git revert 2dfdd066032fdf9f7c9d3ccd7becd399a4c4d11a
Finished one revert.
Created commit 603bb65: Revert “bugfix”
1 files changed, 1 insertions(+), 1 deletions(-)

bugfixのコミットを取り消すコミットが作られ、作業ファイルの内容も更新されました。続いて、コンフリクトが発生するケースを見てみます。

$ git log
commit f78890b498ba86e5b021543cf668838c0bbfa4c6
Author: XXX
Date:   Wed May 26 08:46:33 2010 +0300

file2 changed

commit edcdd50773bd26f761bed16bc440773c6626293e
Author: XXX
Date:   Wed May 26 08:46:11 2010 +0300

file1 bugfix correction

commit 42ff19a73c5f990f3278ef8f57b3c0465384cdc3
Author: XXX
Date:   Wed May 26 08:45:41 2010 +0300

file1 bugfix

$ git revert  42ff19a73c5f990f3278ef8f57b3c0465384cdc3
Auto-merged file1
CONFLICT (content): Merge conflict in file1
Automatic revert failed.  After resolving the conflicts,
mark the corrected paths with ‘git add <paths>’ or ‘git rm <paths>’ and commit the result.

取り消そうとしたコミットに依存するコミットがあるためにコンフリクトが発生しています。コンフリクトが発生したファイルには以下のようなマーカで区切られた部分が作られます。=======の上の部分が最新のコミットの状態を示し、下の部分が取り消そうとしているコミットの内容です。コンフリクトはgitがユーザに判断を仰いでいる状態で、マニュアルでこの部分を修正します。

<<<<<<< HEAD:file1
abcdef
=======
abc
>>>>>>> 603bb65… Revert “bugfix”:file1

修正後にステージングとコミットを行うとrevertが完了します。commitコマンドにすべての変更のステージングとコミットを一度に行うオプションがありますので使ってみます。

$ git commit -a
Created commit 7cae97f: Revert “Revert “bugfix”"
1 files changed, 1 insertions(+), 1 deletions(-)

ちなみにバグフィックス修正のコミット(edcdd50773bd26f761bed16bc440773c6626293e)をrevertする場合には、コンフリクトが起きないので素直にrevertできるのがわかるでしょうか。

コンフリクトはなかなか手間がかかる作業なので、これを解消する作業を効率化するためにいくつかツールが用意されています。これについてはいずれmergeコマンドについて説明するときに紹介することにします。

今回はrevertコマンドの話をしました。次回は以前のコミットからレポジトリの一部、あるいは全部を取り出すcheckoutコマンドについて見てみることにします。

余談ですが、リビジョン名を指定する際には長いリビジョン名のすべてを指定する必要はなく、リビジョンが特定できるに十分の名前を与えれば良いことになってます。個人的には手打ちで入力するよりコピペすることが多いのであまり気にしたことはないですけど。

git

  1. No comments yet.
  1. No trackbacks yet.