![](/img/trans.png)
[英]What's the difference between git reset file and git checkout file?
[英]What's the difference between "git reset" and "git checkout"?
我一直認為git reset
和git checkout
是一樣的,因為兩者都將項目帶回特定的提交。 但是,我覺得它們不能完全相同,因為那是多余的。 兩者之間的實際區別是什么? 我有點困惑,因為 svn 只有svn co
來恢復提交。
VonC 和 Charles 很好地解釋了git reset
和git checkout
之間的區別。 我目前的理解是git reset
將所有更改還原回特定的提交,而git checkout
或多或少地為分支做准備。 我發現以下兩個圖表對於理解這種理解非常有用:
從http://think-like-a-git.net/sections/rebase-from-the-ground-up/using-git-cherry-pick-to-simulate-git-rebase.html ,結帳和重置可以模擬變基。
git checkout bar
git reset --hard newbar
git branch -d newbar
git reset
專門用於更新索引,移動 HEAD。git checkout
是關於更新工作樹(到索引或指定的樹)。 只有當您簽出分支時,它才會更新 HEAD(如果沒有,您最終會得到一個分離的 HEAD )。git restore
,不一定是git checkout
) 相比之下,由於 svn 沒有索引,只有一個工作樹, svn checkout
會將給定的修訂復制到一個單獨的目錄中。
git checkout
更接近的等價物是:
svn update
(如果你在同一個分支,意思是同一個SVN URL)svn switch
(如果您檢出例如同一個分支,但來自另一個 SVN 存儲庫 URL) 所有這三個工作樹修改( svn checkout
、 update
、 switch
)在 git 中只有一個命令: git checkout
。
但是由於 git 也有索引的概念(即 repo 和工作樹之間的“暫存區”),你也有git reset
。
例如,如果我們有兩個分支,'
master
' 和'develop
' 指向不同的提交,並且我們當前在'develop
'(所以 HEAD 指向它)並且我們運行git reset master
,'develop
' 本身現在將指向“master
”所做的相同提交。另一方面,如果我們改為運行
git checkout master
, 'develop
' 不會移動,HEAD
本身會。HEAD
現在將指向“master
”。所以,在這兩種情況下,我們都將
HEAD
移動到指向提交A
,但我們這樣做的方式非常不同。reset
將移動HEAD
指向的分支,checkout 將HEAD
本身移動到另一個分支。
不過,在這些方面:
但是,此答案的第一段具有誤導性:“
git checkout
... 僅在您簽出分支時才會更新 HEAD(如果沒有,您最終會得到一個分離的 HEAD)”。
不正確:即使您簽出一個不是分支的提交,git checkout
也會更新 HEAD(是的,您最終得到了一個分離的 HEAD,但它仍然得到了更新)。git checkout a839e8f updates HEAD to point to commit a839e8f.
@LarsH 是正確的。
第二個項目符號對 HEAD 的內容存在誤解,只有在您檢出分支時才會更新 HEAD。
HEAD 無處不在,就像影子一樣。
檢出一些非分支引用(例如,標簽)或直接提交,將移動 HEAD。 分離的頭部並不意味着您已經與 HEAD 分離,這意味着頭部與分支引用分離,您可以從例如git log --pretty=format:"%d" -1
看到。
- 附加的頭部狀態將以
(HEAD ->
,- detached 仍會顯示
(HEAD
,但不會有指向分支引用的箭頭。
在最簡單的形式中, reset
在不接觸工作樹的情況下重置索引,而checkout
在不接觸索引的情況下更改工作樹。
重置索引以匹配HEAD
,單獨留下工作樹:
git reset
從概念上講,這會將索引檢出到工作樹中。 要讓它真正做任何事情,你必須使用-f
來強制它覆蓋任何本地更改。 這是一項安全功能,可確保“無參數”表單沒有破壞性:
git checkout
一旦開始添加參數,確實存在一些重疊。
checkout
通常與分支、標簽或提交一起使用。 在這種情況下,它會將HEAD
和索引重置為給定的提交,並將索引簽出到工作樹中。
此外,如果您提供--hard
to reset
您可以要求reset
覆蓋工作樹以及重置索引。
如果您當前已檢出分支,則在提供替代分支或提交時reset
和checkout
之間存在重大差異。 reset
會將當前分支更改為指向選定的提交,而checkout
將單獨保留當前分支,但會檢出提供的分支或提交。
其他形式的reset
和commit
涉及提供路徑。
如果您提供reset
路徑,則無法提供--hard
並且reset
只會將所提供路徑的索引版本更改為所提供提交中的版本(如果未指定提交,則為HEAD
)。
如果您為checkout
提供路徑,如reset
它將更新提供的路徑的索引版本以匹配提供的提交(或HEAD
),但它始終將提供的路徑的索引版本檢出到工作樹中。
恢復更改時的一個簡單用例:
1. 如果要撤消修改文件的暫存,請使用重置。
2. 如果要放棄對未暫存文件的更改,請使用 checkout。
簡而言之,關鍵區別在於reset
移動當前分支引用,而checkout
不會(它移動 HEAD)。
正如 Pro Git 書在Reset Demystified下解釋的那樣,
reset
要做的第一件事是移動 HEAD 指向的內容。 這與更改 HEAD 本身不同(這是checkout
所做的);reset
移動HEAD 指向的分支。 這意味着如果 HEAD 設置為master
分支(即您當前在master
分支上),運行git reset 9e5e6a4
將首先使master
指向9e5e6a4
。 [強調]
另請參閱 VonC 對同一篇文章中非常有用的文本和圖表摘錄的回答,我不會在此處重復。
當然,還有更多關於checkout
和reset
會對索引和工作樹產生什么影響的詳細信息,具體取決於使用的參數。 這兩個命令之間可能有很多相似之處和不同之處。 但在我看來,最關鍵的區別是它們是否移動了當前分支的尖端。
Atlassian為我們提供了有關git reset , git checkout等的出色解釋,因此git revert 。 在本文中,將解釋這些命令在不同級別上的不同用法-文件,暫存快照和提交。
https://www.atlassian.com/git/tutorials/resetting-checking-out-and-reverting
簡短的助記符:
git reset HEAD : index = HEAD
git checkout : file_tree = index
git reset --hard HEAD : file_tree = index = HEAD
這兩個命令(reset 和 checkout)是完全不同的。
checkout X
reset --hard X
如果 X 是分支名稱,則checkout X
將更改當前分支,而reset --hard X
不會。
以下是對歧義的澄清:
在您所在的任何分支上,指向該分支尖端的指針(例如,“main”)將保持不變(因此您可能最終處於分離的頭部狀態)。
此外,暫存區和工作目錄將保持不變(與結帳前的狀態相似)。
例子:
git checkout 3ad2bcf <--- checkout to another commit
git checkout another-branch <--- checkout to another commit using a branchname
git reset也會移動 HEAD ,但同樣有兩個不同之處:
它也將指向當前分支尖端的提交的指針移動。 例如,假設指向當前分支的指針命名為“main”,然后執行 git-reset,現在,主指針將指向另一個提交,而 HEAD 也將指向該提交(基本上, HEAD 通過指向主指針間接指向該提交,它仍然是一個附加的 head(!) ,但在這里沒有任何區別)。
Git-reset 不一定會將暫存區和工作目錄保持在執行重置之前的相同狀態。 如您所知,共有三種類型的重置:軟、混合(默認)和硬:
例子:
git reset --soft 3ad2bcf
git reset da3b47
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.