端末からgitコマンドで特定のコミットを削除したり、特定のコミットに戻る方法を紹介します。
1. 特定のコミットに戻す(git reset)
git reset --hard <commit id>
命令は以前に反映された特定のコミットに戻り、その後に反映されたコミットはすべて削除する方法です。
たとえば、次のように3つのコミットが反映されている場合、最近反映された2つのコミットを削除し、最初のコミットである ecb42ee
に戻りたいときは、
$ git log
commit 1edf17e135a8b4e2996b1cba8eec8d5635469bdd (HEAD -> master)
Author: farfs <farfs.dev@gmail.com>
Date: Sun Sep 18 15:32:37 2022 +0900
Add c.txt
commit 5b85a825bff96da466af7dcf21e5a1edb2d96e97
Author: farfs <farfs.dev@gmail.com>
Date: Sun Sep 18 15:32:23 2022 +0900
Add b.txt
commit ecb42ee4da1d63caec1282b006b687ee1a74f46f
Author: farfs <farfs.dev@gmail.com>
Date: Sun Sep 18 15:32:15 2022 +0900
Add a.txt
次のように git reset --hard <commit id>
命令を使用できます。
$ git reset --hard ecb42ee4da1d63caec1282b006b687ee1a74f46f
HEAD is now at ecb42ee Add a.txt
コマンド入力後、 git log
を入力してみると最新の commit(HEAD) が ecb42ee
になっています。
つまり、 ecb42ee
の後に反映されたコミットはすべて削除されました。
$ git log
commit ecb42ee4da1d63caec1282b006b687ee1a74f46f (HEAD -> master)
Author: farfs <farfs.dev@gmail.com>
Date: Sun Sep 18 15:32:15 2022 +0900
Add a.txt
上記のリセットコマンドは、以下のように簡単に入力することもできます。ちなみに、 HEAD
は最新のコミットを指し、 HEAD~1
は最も最近のコミットの1つ前のコミットを意味し、 HEAD~2
は2つの前のコミットである ecb42ee
を意味します。
$ git reset --hard HEAD~2
HEAD is now at ecb42ee Add a.txt
最後に、変更を remote branch に適用すると競合が発生する可能性があるため、-f
を使用して強制的に更新する必要があります。
$ git push -f origin <branch name>
1.2 commit を削除せずに、変更を staged 領域に戻す
git reset --soft <commit id>
コマンドを使うと、--hard
と同じようにcommit idに移動します。
2つの違いは、 --hard
は特定のコミットの後に適用したすべてのコミットを削除することを意味します。
$ git reset --soft ecb42ee4da1d63caec1282b006b687ee1a74f46f
$ git log
commit ecb42ee4da1d63caec1282b006b687ee1a74f46f (HEAD -> master)
Author: farfs <farfs.dev@gmail.com>
Date: Sun Sep 18 15:32:15 2022 +0900
Add a.txt
$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: b.txt
new file: c.txt
上記のようにステージング領域に変更がある場合は、一部の内容を変更して再コミットを適用できます。
$ git commit -m "Add b, c files"
[master 95ecebc] Add b, c files
2 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 b.txt
create mode 100644 c.txt
$ git log
commit 95ecebc740368ec9f2340b6794cd1b75f52184bf (HEAD -> master)
Author: farfs <farfs.dev@gmail.com>
Date: Sun Sep 18 15:54:13 2022 +0900
Add b, c files
commit ecb42ee4da1d63caec1282b006b687ee1a74f46f
Author: farfs <farfs.dev@gmail.com>
Date: Sun Sep 18 15:32:15 2022 +0900
Add a.txt
2. 特定のコミットの変更を削除し、コミットを登録する(git revert)
特定のコミットの変更をすべて削除し、削除した内容をコミットとして登録する方法です。通常revertと呼ばれます。
例えば、上で紹介したプロジェクトで以下のように最初の commit ecb42ee
を revert すると、現在のコードからこの修正のみが削除されます。
$ git revert ecb42ee4da1d63caec1282b006b687ee1a74f46f
Removing a.txt
[master 6581856] Revert "Add a.txt"
1 file changed, 0 insertions(+), 0 deletions(-)
delete mode 100644 a.txt
git log
で履歴を確認すると、 Revert "Add a.txt"
という名前で、最初のcommitの修正を削除する新しいcommitが登録されました。
$ git log
commit 65818566596380b0c888e9b840c5d61120bf72b9 (HEAD -> master)
Author: farfs <farfs.dev@gmail.com>
Date: Sun Sep 18 15:55:56 2022 +0900
Revert "Add a.txt"
This reverts commit ecb42ee4da1d63caec1282b006b687ee1a74f46f.
commit 1edf17e135a8b4e2996b1cba8eec8d5635469bdd
Author: farfs <farfs.dev@gmail.com>
Date: Sun Sep 18 15:32:37 2022 +0900
Add c.txt
commit 5b85a825bff96da466af7dcf21e5a1edb2d96e97
Author: farfs <farfs.dev@gmail.com>
Date: Sun Sep 18 15:32:23 2022 +0900
Add b.txt
commit ecb42ee4da1d63caec1282b006b687ee1a74f46f
Author: farfs <farfs.dev@gmail.com>
Date: Sun Sep 18 15:32:15 2022 +0900
Add a.txt
resetとrevertの違いを比較すると、 git reset
は以前のコミットに戻り、その後に反映したコミットをきれいに削除しました。
git revert
は特定のコミットの変更を削除しますが、以前に保存したコミットは削除せずにrevertの新しいコミットを追加します。
また、revertを使用した場合、Remote branchと衝突が発生しないため、resetのように -f
を使ってプッシュする必要はありません。