Git 筆記 reset 與 checkout 的差異

本文將會介紹 GIT 中 reset 與 checkout 的運作方式與差別。

在開始前需要了結的 Git 小觀念。

## Git 小觀念

HEAD

Role: Last commit snapshot, next parent

一般指向一個 Branch 的最新一個 Commit,也是使用者目前所能看到的 Git 內容。

新增的 Commit 必定接在目前 HEAD 後面。

Index

Role: Proposed next commit snapshot

又稱為 Staging area 暫存區,算是 Commit 前的過渡區,告知 Git 哪些檔案需要包含在此次 Commit 內。

Working Directory

Role: Sandbox

對目前內容 HEAD 進行的修改,都會存放在此沙盒中。

了解 GIT 這三個部分後,在 GIT 建立支點過程中,首先我們會在 Working Directory 中進行文件的新增、編輯或刪除,之後在需要納入新支點的文件 add,使沙盒中的修改進入到暫存區中,再透過 commit 指令使在暫存區的內容全部包含在一個新支點,然後移動 HEAD 到該支點上。

這邊就不對 add 與 commit 多做介紹。

而 Reset 與 Checkout 則可以幫助我們移動 HEAD 、將暫存區的內容移出等等。

Reset

移動 HEAD 指向的 Branch ,有三種模式可以使用。

Soft

reset --soft [commit]

單純移動 HEAD 與其 Branch。

Mixed (預設指令)

reset [commit]

除了移動 HEAD 與其 Branch 外,也將 Index 的內容移出。

Hard

reset --hard [commit]

除了移動 HEAD 與其 Branch 外,也將 Working Directory 與 Index 的內容移出。

如果不加任何的 CommitID 則會以 HEAD 為移動的目的地。

Checkout

checkout [commit]

checkout is working-directory safe - it will check to make sure it’s not blowing away files that have changes to them.

也就是說在進行 checkout 時,會檢查你的沙盒是否有更改,如果有且此更改會因為 checkout 而失去,便會阻止你。

checkout 移動的是 HEAD 本身,並不會連其 Branch 一起移動,一般使用在切換分支。

雖然使用上看起來像 reset --hard,但 reset --hard 並不會檢查你的沙盒並且會移動你的分支。

對檔案進行操作

兩者皆可以針對單一檔案進行內容移動。

reset [commit] [paths]

git reset -- xxx.html 將 xxx.html 的 Index 的內容移出。

checkout [commit] [paths]

git checkout -- xxx.html 將 xxx.html 的 Working Directory 與 Index 的內容移出。

checkout 如上所說如同 reset --hard,但在進行檔案操作時,就不是 working-directory safe 了,所以使用時請三思。

對 file 操作時,無論是 reset 或者 checkout 建議在檔案名稱前面加上`--`來標示

詳細可參考 Difference between "git checkout <filename>" and "git checkout -​- <filename>" - Stack Overflow

參考資料

[Git - Reset Demystified]

[【狀況題】剛才的 Commit 後悔了,想要拆掉重做… - 為你自己學 Git 高見龍]