Skip to content

前情提要

首先,工作目錄暫存區提交紀錄 的檔案內容是一致的。

當實體檔案被異動後,工作目錄 的檔案內容會與 暫存區提交紀錄 的不一致:

  • 若檔案不曾被提交過,此時的檔案狀態為 Untracked files
  • 若檔案曾被提交過,此時的檔案狀態為 Changes not staged for commit

接著,當我們執行 git add <file>... 後,會將這些異動的檔案內容加入 暫存區 中 (Changes to be committed)。此時,工作目錄暫存區 的檔案內容是一致的,但卻與 提交紀錄 (HEAD) 的檔案內容不一致。

最後,執行 git commit 並將所有異動的檔案內容提交 (push) 至 Repository 中。待建立出新的 Commit 結點後,工作目錄暫存區提交紀錄 中的檔案內容便會保持一致。

情境 1:單一檔案退版

  1. 退回 "檔案狀態"
bash
# Unstage file
git reset HEAD <file>
  1. 退回 "檔案內容"
bash
# Discard changes in working directory
git checkout <file>

補充:git checkout -- <file>... 是一個危險的命令, 對指定檔案所做的任何修改都會消失 —— Git 只是複製了另一個檔案來覆蓋它。除非你很肯定地知道你不想要那個檔案了,否則千萬不要使用這個命令

情境 2:本地檔案退版

假設以下情境:

~工作目錄
(Working Tree)
暫存區
(Staging Area)
提交紀錄異動內容
HEAD~3--commit1change1.txt
HEAD^^
(HEAD~2)
--commit2change2.txt
HEAD^
(HEAD~1)
--commit3 (HEAD)change3.txt
本地端change4.txt---

使用 Reset 的三種模式

  1. --soft:這個模式下會保留工作目錄和暫存區的檔案 (本次異動),提交紀錄的異動內容會直接放在暫存區,所以看起來就只有 HEAD 的移動而已
bash
git reset --soft HEAD
~工作目錄
(Working Tree)
暫存區
(Staging Area)
提交紀錄異動內容
本地端change4.txtchange3.txtcommit2 (HEAD)-
  1. --mixed (預設):這個模式會把暫存區的檔案移動到工作目錄 (本次異動),提交紀錄內異動的內容會直接放在工作目錄,不會留在暫存區
bash
git reset HEAD
~工作目錄
(Working Tree)
暫存區
(Staging Area)
提交紀錄異動內容
本地端change3.txt
change4.txt
-commit2 (HEAD)-
  1. --hard:這個模式下,不論是本次異動或提交紀錄內異動的內容都會移除
bash
git reset --hard HEAD
~工作目錄
(Working Tree)
暫存區
(Staging Area)
提交紀錄異動內容
本地端--commit2 (HEAD)-

以記錄退版

  • git reflog:每當 HEAD 有移動的時候,Git 就會在 Reflog 裡記上一筆
  • git log:加入 -g 參數,同樣可以看到 Reflog
bash
git reset --hard <log>

以標籤退版

bash
git reset --hard <tag>

以 VitePress 建置,內容以 CC BY-NC-SA 4.0 釋出。