Gitでコミットをやり直したいときはgit resetを使うが、HEADとか—hardとか何もわからなかったので調べた
初期設定
[16:07:49] /tmp/tmp.Cp2OWt1dgq
% git init
Initialized empty Git repository in /tmp/tmp.Cp2OWt1dgq/.git/
[16:07:50] /tmp/tmp.Cp2OWt1dgq <main #>
% cat << END >> .git/config
heredoc> [commit]
heredoc> gpgsign = false
heredoc> END
HEADとHEAD~をcat-fileしてみる
[16:08:12] /tmp/tmp.Cp2OWt1dgq <main #>
% echo first > text
[16:09:44] /tmp/tmp.Cp2OWt1dgq <main #%>
% git add text
[16:09:51] /tmp/tmp.Cp2OWt1dgq <main +>
% git commit -m "(initial) first"
[main (root-commit) 8336769] (initial) first
1 file changed, 1 insertion(+)
create mode 100644 text
[16:09:56] /tmp/tmp.Cp2OWt1dgq <main>
% echo second >> text
[16:10:03] /tmp/tmp.Cp2OWt1dgq <main *>
% git diff
diff --git a/text b/text
index 9c59e24..66a52ee 100644
--- a/text
+++ b/text
@@ -1 +1,2 @@
first
+second
[16:10:06] /tmp/tmp.Cp2OWt1dgq <main *>
% git commit -a -m "update: second"
[main 5153aec] update: second
1 file changed, 1 insertion(+)
[16:10:13] /tmp/tmp.Cp2OWt1dgq <main>
% git cat-file -p HEAD
tree 5f98b597243c7df4465c0123746750bc72422b10
parent 8336769be4f7cb274c691533116ab2401593dd68
author watasuke102 <[email protected]> 1683789013 +0900
committer watasuke102 <[email protected]> 1683789013 +0900
update: second
[16:10:16] /tmp/tmp.Cp2OWt1dgq <main>
% git cat-file -p HEAD~
tree eea7d20df35fda0d13e9b9692ea3a2cca8abdf7d
author watasuke102 <[email protected]> 1683788996 +0900
committer watasuke102 <[email protected]> 1683788996 +0900
(initial) first
git resetの準備(thirdコミット)
[16:10:19] /tmp/tmp.Cp2OWt1dgq <main>
% echo third >> text
[16:10:28] /tmp/tmp.Cp2OWt1dgq <main *>
% git commit -a -m "update: third"
[main 43bdda1] update: third
1 file changed, 1 insertion(+)
[16:10:33] /tmp/tmp.Cp2OWt1dgq <main>
% git log
commit 43bdda196e6093d02dc8158828c94116986db638 (HEAD -> main)
Author: watasuke102 <[email protected]>
Date: Thu May 11 16:10:33 2023 +0900
update: third
commit 5153aecc0341a10475dde1539ab24a12952a836e
Author: watasuke102 <[email protected]>
Date: Thu May 11 16:10:13 2023 +0900
update: second
commit 8336769be4f7cb274c691533116ab2401593dd68
Author: watasuke102 <[email protected]>
Date: Thu May 11 16:09:56 2023 +0900
(initial) first
[16:10:39] /tmp/tmp.Cp2OWt1dgq <main>
% git cat-file -p HEAD
tree 7dff423aba8439f7a205241a8621927e19b7f6c9
parent 5153aecc0341a10475dde1539ab24a12952a836e
author watasuke102 <[email protected]> 1683789033 +0900
committer watasuke102 <[email protected]> 1683789033 +0900
update: third
[16:10:43] /tmp/tmp.Cp2OWt1dgq <main>
% git cat-file -p HEAD~
tree 5f98b597243c7df4465c0123746750bc72422b10
parent 8336769be4f7cb274c691533116ab2401593dd68
author watasuke102 <[email protected]> 1683789013 +0900
committer watasuke102 <[email protected]> 1683789013 +0900
update: second
git reset —soft
HEAD^とHEAD~は同じ?
[16:18:10] /tmp/tmp.Cp2OWt1dgq <main>
% git reset --soft HEAD^
[16:18:22] /tmp/tmp.Cp2OWt1dgq <main +>
% git log
commit 5153aecc0341a10475dde1539ab24a12952a836e (HEAD -> main)
Author: watasuke102 <[email protected]>
Date: Thu May 11 16:10:13 2023 +0900
update: second
commit 8336769be4f7cb274c691533116ab2401593dd68
Author: watasuke102 <[email protected]>
Date: Thu May 11 16:09:56 2023 +0900
(initial) first
[16:21:04] /tmp/tmp.Cp2OWt1dgq <main +>
% git status
On branch main
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: text
[16:18:42] /tmp/tmp.Cp2OWt1dgq <main +>
% cat text
first
second
third
[16:19:02] /tmp/tmp.Cp2OWt1dgq <main +>
% git reset --soft 43bdda196e6093d02dc8158828c94116986db638 # thirdコミットのハッシュ
[16:19:15] /tmp/tmp.Cp2OWt1dgq <main>
% git log
commit 43bdda196e6093d02dc8158828c94116986db638 (HEAD -> main)
Author: watasuke102 <[email protected]>
Date: Thu May 11 16:10:33 2023 +0900
update: third
commit 5153aecc0341a10475dde1539ab24a12952a836e
Author: watasuke102 <[email protected]>
Date: Thu May 11 16:10:13 2023 +0900
update: second
commit 8336769be4f7cb274c691533116ab2401593dd68
Author: watasuke102 <[email protected]>
Date: Thu May 11 16:09:56 2023 +0900
(initial) first
[16:21:29] /tmp/tmp.Cp2OWt1dgq <main>
% cat text
first
second
third
git reset —hard
[16:20:07] /tmp/tmp.Cp2OWt1dgq <main>
% git reset --hard HEAD^
HEAD is now at 5153aec update: second
[16:20:17] /tmp/tmp.Cp2OWt1dgq <main>
% git log
commit 5153aecc0341a10475dde1539ab24a12952a836e (HEAD -> main)
Author: watasuke102 <[email protected]>
Date: Thu May 11 16:10:13 2023 +0900
update: second
commit 8336769be4f7cb274c691533116ab2401593dd68
Author: watasuke102 <[email protected]>
Date: Thu May 11 16:09:56 2023 +0900
(initial) first
[16:22:38] /tmp/tmp.Cp2OWt1dgq <main>
% git status
On branch main
nothing to commit, working tree clean
[16:20:20] /tmp/tmp.Cp2OWt1dgq <main>
% cat text
first
second
[16:20:26] /tmp/tmp.Cp2OWt1dgq <main>
% git reset --hard 43bdda196e6093d02dc8158828c94116986db638
HEAD is now at 43bdda1 update: third
[16:20:37] /tmp/tmp.Cp2OWt1dgq <main>
% git log
commit 43bdda196e6093d02dc8158828c94116986db638 (HEAD -> main)
Author: watasuke102 <[email protected]>
Date: Thu May 11 16:10:33 2023 +0900
update: third
commit 5153aecc0341a10475dde1539ab24a12952a836e
Author: watasuke102 <[email protected]>
Date: Thu May 11 16:10:13 2023 +0900
update: second
commit 8336769be4f7cb274c691533116ab2401593dd68
Author: watasuke102 <[email protected]>
Date: Thu May 11 16:09:56 2023 +0900
(initial) first
[16:20:41] /tmp/tmp.Cp2OWt1dgq <main>
% cat text
first
second
third
git reset —mixed
[16:25:13] /tmp/tmp.Cp2OWt1dgq <main>
% git reset --mixed HEAD^
Unstaged changes after reset:
M text
[16:28:17] /tmp/tmp.Cp2OWt1dgq <main *>
% git log
commit 5153aecc0341a10475dde1539ab24a12952a836e (HEAD -> main)
Author: watasuke102 <[email protected]>
Date: Thu May 11 16:10:13 2023 +0900
update: second
commit 8336769be4f7cb274c691533116ab2401593dd68
Author: watasuke102 <[email protected]>
Date: Thu May 11 16:09:56 2023 +0900
(initial) first
[16:28:25] /tmp/tmp.Cp2OWt1dgq <main *>
% git status
On branch main
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: text
no changes added to commit (use "git add" and/or "git commit -a")
[16:28:28] /tmp/tmp.Cp2OWt1dgq <main *>
% cat text
first
second
third
[16:28:31] /tmp/tmp.Cp2OWt1dgq <main *>
% git reset --mixed 43bdda196e6093d02dc8158828c94116986db638
[16:28:59] /tmp/tmp.Cp2OWt1dgq <main>
% git log
commit 43bdda196e6093d02dc8158828c94116986db638 (HEAD -> main)
Author: watasuke102 <[email protected]>
Date: Thu May 11 16:10:33 2023 +0900
update: third
commit 5153aecc0341a10475dde1539ab24a12952a836e
Author: watasuke102 <[email protected]>
Date: Thu May 11 16:10:13 2023 +0900
update: second
commit 8336769be4f7cb274c691533116ab2401593dd68
Author: watasuke102 <[email protected]>
Date: Thu May 11 16:09:56 2023 +0900
(initial) first
[16:29:02] /tmp/tmp.Cp2OWt1dgq <main>
% cat text
first
second
third
まとめ(わかったこと)
- initial commitは親を持たない
- initial commitの次にコミットをすると、そのコミットはinitial commitを親として指す
- そしてindexはその新しいコミットを指す
- HEADは今のindex、HEAD~はその親(即ち1つ前のコミット)
- HEAD^と同じ意味?
- ほぼyes(後述)
HEAD~~もある- HEAD~2と同じ意味
- ただし^2とは異なる
- HEAD^2は「HEADの2つ目の親」を指す
- つまり、親を複数持つHEAD(マージコミット など?他にもある?)に対して用いる
- HEAD~は「HEADの1つ目の親」と言うこともできる
- HEAD~2は「(HEADの1つ目の親)の1つ目の親」である
- HEAD^3~2は「{(HEADの3番目の親)の1つ目の親}の1つ目の親」
- ^と~の違いは数字を指定した時だけであると言える
- HEAD^2は「HEADの2つ目の親」を指す
- HEAD^と同じ意味?
- git resetはHEADの移動
- 例えばgit reset —(soft|mixed|hard)でコミットAからBに移動した時を考える
- Bである変更が発生して、それをコミットしたのがA(時系列的にBが先)
- ここでは、この変更を diff(A,B) で表すとする
- —softを指定すると、diff(A, B)がindexに登録された状態になる(ステージされた状態になる)
- VSCodeで「Undo Last Commit」した時の挙動?
- HEADを移動させるだけ
- indexとworking treeはそのまま
- —mixedを指定すると、diff(A, B)がworking treeに残される
- 何も指定しなかった場合はこれになる(つまり—mixedがデフォルト)らしい
- HEADを移動させて、移動後のHEAD^(つまりBの前のコミット)をindexに適用する
- indexとworking tree感に差が生じる
- —hardを指定すると、diff(A, B)が消えたように見える
- HEADを移動させて、移動後のHEAD^をindex・working tree双方に適用する
- index・working treeが全てHEAD^と同一になる
- HEADを移動させて、移動後のHEAD^をindex・working tree双方に適用する
- Bである変更が発生して、それをコミットしたのがA(時系列的にBが先)