Reverting versions
前情提要¶
首先,工作目錄、暫存區 和 提交紀錄 的檔案內容是一致的。
當實體檔案被異動後,工作目錄 的檔案內容會與 暫存區 及 提交紀錄 的不一致:
* 若檔案不曾被提交過,此時的檔案狀態為 Untracked files
* 若檔案曾被提交過,此時的檔案狀態為 Changes not staged for commit
接著,當我們執行 git add <file>... 後,會將這些異動的檔案內容加入 暫存區 中 (Changes to be committed)。此時,工作目錄 及 暫存區 的檔案內容是一致的,但卻與 提交紀錄 (HEAD) 的檔案內容不一致。
最後,執行 git commit 並將所有異動的檔案內容提交 (push) 至 Repository 中。待建立出新的 Commit 結點後,工作目錄、暫存區 與 提交紀錄 中的檔案內容便會保持一致。
情境 1:單一檔案退版¶
- 退回 "檔案狀態"
# Unstage file
git reset HEAD <file>
- 退回 "檔案內容"
# Discard changes in working directory
git checkout <file>
補充:git checkout -- <file>... 是一個危險的命令, 對指定檔案所做的任何修改都會消失 —— Git 只是複製了另一個檔案來覆蓋它。除非你很肯定地知道你不想要那個檔案了,否則千萬不要使用這個命令
情境 2:本地檔案退版¶
假設以下情境:
| ~ | 工作目錄 (Working Tree) |
暫存區 (Staging Area) |
提交紀錄 | 異動內容 |
|---|---|---|---|---|
| HEAD~3 | - | - | commit1 | change1.txt |
| HEAD^^ (HEAD~2) |
- | - | commit2 | change2.txt |
| HEAD^ (HEAD~1) |
- | - | commit3 (HEAD) | change3.txt |
| 本地端 | change4.txt | - | - | - |
使用 Reset 的三種模式¶
--soft:這個模式下會保留工作目錄和暫存區的檔案 (本次異動),提交紀錄的異動內容會直接放在暫存區,所以看起來就只有 HEAD 的移動而已
git reset --soft HEAD
| ~ | 工作目錄 (Working Tree) |
暫存區 (Staging Area) |
提交紀錄 | 異動內容 |
|---|---|---|---|---|
| 本地端 | change4.txt | change3.txt | commit2 (HEAD) | - |
--mixed(預設):這個模式會把暫存區的檔案移動到工作目錄 (本次異動),提交紀錄內異動的內容會直接放在工作目錄,不會留在暫存區
git reset HEAD
| ~ | 工作目錄 (Working Tree) |
暫存區 (Staging Area) |
提交紀錄 | 異動內容 |
|---|---|---|---|---|
| 本地端 | change3.txt change4.txt |
- | commit2 (HEAD) | - |
--hard:這個模式下,不論是本次異動或提交紀錄內異動的內容都會移除
git reset --hard HEAD
| ~ | 工作目錄 (Working Tree) |
暫存區 (Staging Area) |
提交紀錄 | 異動內容 |
|---|---|---|---|---|
| 本地端 | - | - | commit2 (HEAD) | - |
以記錄退版¶
git reflog:每當HEAD有移動的時候,Git 就會在 Reflog 裡記上一筆git log:加入-g參數,同樣可以看到 Reflog
git reset --hard <log>
以標籤退版¶
git reset --hard <tag>