簡體   English   中英

“git reset”和“git checkout”有什么區別?

[英]What's the difference between "git reset" and "git checkout"?

我一直認為git resetgit checkout是一樣的,因為兩者都將項目帶回特定的提交。 但是,我覺得它們不能完全相同,因為那是多余的。 兩者之間的實際區別是什么? 我有點困惑,因為 svn 只有svn co來恢復提交。

添加

VonC 和 Charles 很好地解釋了git resetgit checkout之間的區別。 我目前的理解是git reset將所有更改還原回特定的提交,而git checkout或多或少地為分支做准備。 我發現以下兩個圖表對於理解這種理解非常有用:

http://a.imageshack.us/img651/1559/86421927.pnghttp://a.imageshack.us/img801/1986/resetr.png

添加 3

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 2.23 Q3 2019,這將是git restore ,不一定是git checkout

相比之下,由於 svn 沒有索引,只有一個工作樹, svn checkout會將給定的修訂復制到一個單獨的目錄中。
git checkout更接近的等價物是:

  • svn update (如果你在同一個分支,意思是同一個SVN URL)
  • svn switch (如果您檢出例如同一個分支,但來自另一個 SVN 存儲庫 URL)

所有這三個工作樹修改( svn checkoutupdateswitch )在 git 中只有一個命令: git checkout
但是由於 git 也有索引的概念(即 repo 和工作樹之間的“暫存區”),你也有git reset


Thinkeye 在評論中提到了文章“重置揭秘”。

例如,如果我們有兩個分支,' master ' 和' develop ' 指向不同的提交,並且我們當前在' develop '(所以 HEAD 指向它)並且我們運行git reset master ,' develop ' 本身現在將指向“ master ”所做的相同提交。

另一方面,如果我們改為運行git checkout master , ' develop ' 不會移動, HEAD本身會。 HEAD現在將指向“ master ”。

所以,在這兩種情況下,我們都將HEAD移動到指向提交A ,但我們這樣做的方式非常不同。 reset將移動HEAD指向的分支,checkout 將HEAD本身移動到另一個分支。

http://git-scm.com/images/reset/reset-checkout.png

不過,在這些方面:

LarsH 在評論中補充道:

但是,此答案的第一段具有誤導性:“ git checkout ... 僅在您簽出分支時才會更新 HEAD(如果沒有,您最終會得到一個分離的 HEAD)”。
不正確:即使您簽出一個不是分支的提交, git checkout也會更新 HEAD(是的,您最終得到了一個分離的 HEAD,但它仍然得到了更新)。

 git checkout a839e8f updates HEAD to point to commit a839e8f.

De Novo 在評論中表示同意:

@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覆蓋工作樹以及重置索引。

如果您當前已檢出分支,則在提供替代分支或提交時resetcheckout之間存在重大差異。 reset會將當前分支更改為指向選定的提交,而checkout將單獨保留當前分支,但會檢出提供的分支或提交。

其他形式的resetcommit涉及提供路徑。

如果您提供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 對同一篇文章中非常有用的文本和圖表摘錄的回答,我不會在此處重復。

當然,還有更多關於checkoutreset會對索引和工作樹產生什么影響的詳細信息,具體取決於使用的參數。 這兩個命令之間可能有很多相似之處和不同之處。 但在我看來,最關鍵的區別是它們是否移動了當前分支的尖端。

Atlassian為我們提供了有關git resetgit 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不會。

以下是對歧義的澄清:

  • git checkout 會將 HEAD 移動到另一個提交(也可以使用分支名稱進行更改),但是
    1. 在您所在的任何分支上,指向該分支尖端的指針(例如,“main”)將保持不變(因此您可能最終處於分離的頭部狀態)。

    2. 此外,暫存區和工作目錄將保持不變(與結帳前的狀態相似)。

例子:

git checkout 3ad2bcf <--- checkout to another commit
git checkout another-branch <--- checkout to another commit using a branchname
  • git reset也會移動 HEAD ,但同樣有兩個不同之處

    1. 它也將指向當前分支尖端的提交的指針移動。 例如,假設指向當前分支的指針命名為“main”,然后執行 git-reset,現在,主指針將指向另一個提交,而 HEAD 也將指向該提交(基本上, HEAD 通過指向主指針間接指向該提交,它仍然是一個附加的 head(!) ,但在這里沒有任何區別)。

    2. Git-reset 不一定會將暫存區和工作目錄保持在執行重置之前的相同狀態。 如您所知,共有三種類型的重置:軟、混合(默認)和硬:

      • 通過軟重置,暫存區和工作目錄都保持在重置前的狀態(在這方面類似於結帳,但不要忘記差異#1)。
      • 使用作為默認重置類型的混合重置,除了差異 #1 之外,暫存區建議的下一次提交(您已經 git 添加的內容)也將設置為新指向的 HEAD犯罪。 但是在工作目錄中,所有文件仍將具有您對它們的最新編輯(這就是為什么這種類型的重置是默認的,這樣您就不會丟失您的工作)。
      • 通過硬重置,除了差異 #1 之外,所有三棵樹 HEAD、staging-area 和 ALSO 工作目錄都將更改為新指向的 HEAD 提交。

例子:

git reset --soft 3ad2bcf
git reset da3b47

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM