git checkout 和 git reset 的區別 —— Git 學習筆記 09

ARM的程式設計師敲著詩歌的夢發表於2018-09-02

git checkout 和 git reset 的區別

git checkout 和 git reset 有時候讓人困惑,因為它們的表現很相似。本文淺析二者之異同。

後接分支名稱

執行 git checkout [branch] 與執行 git reset --hard [branch] 非常相似,都會更新所有的三棵樹(關於三棵樹可以參考我的博文 git reset 命令詳解),使其看起來像 [branch],不過有兩點重要的區別。

首先不同於 reset --hardcheckout 對工作目錄是安全的,它會通過檢查來確保不會將已更改的檔案弄丟;而 reset --hard 則會不做檢查就全面地替換所有東西。

第二個重要的區別是如何更新 HEAD。 reset 會移動 HEAD 分支的指向(即 HEAD 指向的分支的指向),而 checkout 只會移動 HEAD 自身來指向另一個分支。
這裡寫圖片描述

例如,假設我們有 master 和 develop 分支,它們分別指向不同的提交(上圖左邊);我們現在在 develop 上(所以 HEAD 指向它)。 如果我們執行 git reset master,那麼 develop 會和 master 指向同一個提交; 而如果我們執行 git checkout master 的話,develop 不會移動,HEAD 自身會移動,指向 master。

所以,雖然在這兩種情況下我們都移動 HEAD 使其指向了提交 A,但做法是非常不同的。 reset 會移動 HEAD 分支的指向,而 checkout 則移動 HEAD 自身。

有人會問,git reset --hard [branch],這種用法有什麼用?我能想到的一個例子是,

假設倉庫是這樣:

這裡寫圖片描述

為了將本地的狀態回退到和遠端的一樣,可以執行:

$ git reset --hard origin/master   

執行後如下圖:

這裡寫圖片描述

後接路徑

執行 checkout 的另一種方式是指定一個檔案路徑,這會像 reset 一樣,不會移動 HEAD。 它就像是 git reset --hard [branch] file,不僅用某次提交中的那個檔案來更新索引,同時也會覆蓋工作目錄中對應的檔案 —— 這樣對工作目錄並不安全!

注:這裡的 [branch] 是分支名稱,也可以是 commit 或者是 HEAD 一類的符號引用。本質上,它們最終都定位到某個提交。

速查表

下面的速查表列出了命令對樹的影響。 “HEAD” 一列中的 “REF” 表示該命令移動了 HEAD 指向的分支引用,而‘HEAD’ 則表示只移動了 HEAD 自身。 特別注意 WD Safe? 一列 ,表示工作目錄是否安全,如果它標記為 NO,那麼執行該命令之前請仔細考慮一下。

這裡寫圖片描述

參考資料

《Pro Git》(Scott Chacon, Ben Straub Version 2.1.14, 2018-05-19)

相關文章