如果我們想修改的不是最新的一筆紀錄,而是前幾筆,例如下面的紀錄:
1db41c6 (HEAD -> master) docs: 新增 helloWorld.txt 註解
05ca78e docs: 新增 test.txt
042ee26 docs: 新增道別規矩
dfaa0f3 初始版本
我們想修改的是 025e6f4 這筆紀錄,我們可以使用 git reset
:
$ git reset dfaa0f3
上面是使用 git reset
退回到「絕對」歷史紀錄,我們也可以使用「相對」的方式:
$ git reset 1db41c6^^^
^ 表示前一次,所以 1db41c6^^^ 會是從 1db41c6 往前三個紀錄,也就是會回到 dfaa0f3 這個版本紀錄,但如果要往前好幾筆紀錄需要打很多 ^,所以我們也可以寫成 1db41c6~3。
另外,在這裡 HEAD、master 也都指向 1db41c6,所以也可以將 1db41c6 寫成 HEAD~3 或是 master~3。
執行完 git reset
後,在來看一下歷史紀錄:
$ git log ---oneline
dfaa0f3 (HEAD -> master) 初始版本
會發現只剩 dfaa0f3 這一個紀錄,而我們的檔案內容並沒有跟著回到這一版本的狀態,所以可以放心的重新將內容 commit 上去。
Reset 參數:--mixed、--soft、--hard
在使用 reset 時可以加上 --mixed、--soft、--hard 參數,雖然我們在上面使用 git reset
時並沒有帶上參數,但預設參數為 --mixed,而這三個參數會影響到拆掉 commit 後的檔案狀態:
--mixed
使用 git reset
時如果不加上任何參數則會預設使用 --mixed。
而在使用此參數的時候,會將拆出來的檔案狀態回到加入暫存區前,我們對剛才的範例使用 git status
來檢查檔案追蹤狀態:
On branch master
Changes not statged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: helloWorld.txt
Untracked files:
(use "git add <file>..." to include in what will be committed)
test.txt
nothing added to commit but untracked files present (use "git add" to track/or "git commit -a")
兩個檔案都回到使用 git add
前的狀態。
--soft
當在使用時加上 --soft 參數時,會將拆出來的檔案回到使用 git add
的狀態,一樣使用同個範例來檢查狀態:
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
modified: helloWorld.txt
new file: test.txt
可以看到兩個檔案都是處在準備被 commit 的狀態。
--hard
使用此參數時,會直接將拆出來的檔案丟掉,也就是除了暫存區以外,工作目錄的檔案狀態也直接回到 dfaa0f3 的狀態。
我們用 git status
來檢查狀態前先使用 git log -p
來看一下哪些地方被新增、修改:
$git log -p
commit 1db41c66adf334829c309996a93bcec41c3fe6b4 (HEAD -> master)
Author: 使用者 <使用者 email>
Date: Sun May 8 00:44:02 2022 +0800
docs: 新增 helloWorld.txt 註解
diff --git a/helloWorld.txt b/helloWorld.txt
index 9b4edc2..0e5c9af 100644
--- a/helloWorld.txt
+++ b/helloWorld.txt
@@ -1,3 +1,5 @@
Hello, world!
You need to say hi to everyone in the morning. And say goodbye when you leave.
+
+Please follow the rules.
commit 05ca78e586618389fe56263c764526a4a1239645
Author: 使用者 <使用者 email>
Date: Sun May 8 00:43:47 2022 +0800
docs: 新增 test.txt
diff --git a/test.txt b/test.txt
new file mode 100644
index 0000000..836ac19
--- /dev/null
+++ b/test.txt
@@ -0,0 +1 @@
+keep alive
commit 042ee2612075318ab1c9171cdf03c688621818fb
Author: 使用者 <使用者 email>
Date: Sun May 8 00:43:15 2022 +0800
docs: 新增道別規矩
diff --git a/helloWorld.txt b/helloWorld.txt
index 56bbc32..9b4edc2 100644
--- a/helloWorld.txt
+++ b/helloWorld.txt
@@ -1,3 +1,3 @@
Hello, world!
-You need to say hi to everyone in the morning.
+You need to say hi to everyone in the morning. And say goodbye when you leave.
上面的資訊 + 為新增,- 為刪除,這樣可以得到 helloWorld.txt 在 dfaa0f3 的內容為:
Hello, world!
You need to say hi to everyone in the morning.
在 1db41c6 時內容為:
Hello, world!
You need to say hi to everyone in the morning. And say goodbye when you leave.
Please follow the rules.
而 test.txt 則是在 05ca78e 新增,而內容為:
keep alive
接下來使用 git reset --hard
回到 dfaa0f3,在使用 git status
來檢查狀態
$ git reset --hard dfaa0f3
$ git status
On branch master
nothing to commit, working tree clean
會發現沒有任何檔案有備追蹤,接下來用 ls
來看一下工作目錄底下的檔案:
$ ls
helloWorld.txt
只剩 helloWorld.txt 這個檔案,test.txt 不見了。再來檢查一下 helloWorld.txt 裡面的檔案內容:
Hello, world!
You need to say hi to everyone in the morning.
會發現少了一個斷行以及 Please follow the rules. 這句話,而這就是使用 --hard 參數會把拆出來的檔案直接丟掉的意思。
使用 --hard 參數後的檔案還救得回來嗎?
首先我們要知道使用 git reset
把 commit 拆掉並不真的拆掉它,這是為了方便理解所使用的,而比較正確的解釋是要「前往」到某個指定的 commit 紀錄,所以即使使用了 --hard 參數也可以隨時把紀錄撿回來。
我們在上面介紹 --hard 參數時把 commit 往前回到了 dfaa0f3:
$ git log --oneline
dfaa0f3 初始版本
而我們在一開始有說 git reset
是「前往」指定的 commit,所以我們如果要回到文章一開始的紀錄的話只需要使用 git reset
回到 1db41c6:
$ git reset 1db41c6
這樣剛才使用 --hard 參數拆掉的 commit 就又回來了,如果在使用 --hard 參數後有做檔案的修改,但在那之後想回到使用 git reset --hard
之前並且不要那些修改紀錄時,可以在這裡使用 --hard 強迫放棄修改的檔案。
如果忘記 commit 值(SHA-1 值)
如果沒記下要回去的 commit 值時,我們可以用 git reflog
或是 git log -g
來查看變更紀錄,在這裡以剛才的範例為例:
$ git reflog
dfaa0f3 HEAD@{0}: reset: moving to dfaa0f3
1db41c6 HEAD@{1}: commit: docs: 新增 helloWorld.txt 註解
05ca78e HEAD@{2}: commit: docs: 新增 test.txt
042ee26 HEAD@{3}: commit: docs: 新增道別規矩
dfaa0f3 HEAD@{0}: reset: moving to dfaa0f3
這段是我們使用 git reset
回到 dfaa0f3 的變更紀錄,而下面的 1db41c6 HEAD@{1}: commit: docs: 新增 helloWorld.txt 註解
就是我們在使用 git reset --hard
前的變更紀錄。
參考資料
- 高見龍,《為你自己學 Git》