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

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

Git 小觀念

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 到該支點上。

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

Reset

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

Soft

reset --soft [commit]

單純移動 HEAD 與其 Branch

Mixed (預設指令)

reset [commit]

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

Hard

reset --hard [commit]

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

如果不加任何的 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.htmlxxx.htmlIndex 的內容移出。

checkout [commit] <paths>

git checkout -- xxx.htmlxxx.htmlWorking DirectoryIndex 的內容移出。

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

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

詳細可參考 Difference between “git checkout “ and “git checkout -​- “ - Stack Overflow

參考資料

Git - Reset Demystified

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