2010-03-29 145 views
41

雖然resetcheckout大多數時候有不同的用法,但我不明白這兩者之間有什麼區別。「git reset --hard hash」和「git checkout hash」有區別嗎?

有可能是一個或沒有人會打擾增加一個--hard選項來做一些基本的checkout可以做的事情。

也許有區別是你會看到歷史的方式?

+1

我介紹了這個在更新到我的回答對你以前的問題之一 - 看看ASCII藝術上方附近,特別是在它說:「Digression:...」(儘可能多我喜歡更多的代表在這裏重新回答它) – Cascabel 2010-03-29 22:02:40

+0

我認爲你可以在這裏發佈你的答案,並從中獲得代表。如果有人搜索這個特定的知識,他不會找到其他職位。這一個目標是一個非常具體的主題,它應該擁有獨立的頁面。順便說一句,看來你是我的Git導師:-) harigato,senseï! – 2010-03-29 22:10:40

+1

但是我得到它,區別在於重置移動分支而不是結帳。 – 2010-03-29 22:12:05

回答

52

這個答案大多是從我對前一個問題的回答引用的:git reset in plain english

這兩者非常不同。它們導致索引和工作樹的狀態相同,但生成的歷史和當前分支不相同。

假設你的歷史看起來像這樣,與當前已簽出master分支:

- A - B - C (HEAD, master) 

和運行git reset --hard B。你會得到這樣的:

- A - B (HEAD, master)  # - C is still here, but there's no 
          # branch pointing to it anymore 

如果使用--mixed--soft過你會真正得到這種效果 - 唯一的區別是發生了什麼你的工作樹和索引。在--hard的情況下,工作樹和索引匹配B

現在,假設您將運行git checkout B。你會得到這個:

- A - B (HEAD) - C (master) 

你已經結束了分離HEAD狀態。 HEAD,工作樹,索引全部匹配B,與硬重置相同,但主分支留在C。如果您在這一點上新的提交D,你會得到這一點,這可能不是你想要的東西:

- A - B - C (master) 
     \ 
     D (HEAD) 

因此,您使用結賬時,好了,檢查出承諾。你可以擺弄它,做你喜歡的事,但是你已經把你的分支留下了。如果您希望分支也移動,則使用重置。

+5

+1。這個線程(http://marc.info/?l=git&m=120955970704567&w=2)也增加了一個副作用:如果你在一個合併中(例如,當合並衝突,或者在'git合併 - ),'git reset --hard'忘記了合併的 ,但是'git checkout -f'沒有;因此,在後者創建一個合併提交後,一個'git commit'通常不是你想要的。 – VonC 2010-03-29 22:18:41

+0

@VonC:和往常一樣,你的優秀附加點! – Cascabel 2010-03-29 22:25:21

14

如果Git提供的文檔不能幫助您,請查看Mark Lodato的A Visual Git Reference

特別是如果你是比較git checkout <non-branch>git reset --hard <non-branch>(熱鏈接):

git checkout master~3 http://marklodato.github.com/visual-git-guide/checkout-detached.svg.png

git reset --hard master~3 http://marklodato.github.com/visual-git-guide/reset-commit.svg.png

注意,在git reset --hard master~3你留下修改的DAG的一部分的情況 - 一些提交沒有被任何分支引用。那些受保護的(默認)30天,由reflog;他們最終將被修剪(刪除)。

6

git-reset hash將分支引用設置爲給定的散列,並且可以選擇將其檢出,並使用--hard

git-checkout hash將工作樹設置爲給定散列;除非散列是一個分支名稱,否則最終會有一個分離的頭部。

最終,有三件事情git的交易:

    working tree (your code) 
------------------------------------------------------------------------- 
        index/staging-area 
------------------------------------------------------------------------- 
     repository (bunch of commits, trees, branch names, etc) 

git-checkout默認情況下只更新索引和工作樹,可以選擇更新的檔案庫裏的東西(與-b選項)

git-reset默認情況下只是更新存儲庫和索引,以及可選的工作樹(使用--hard選項)

您可以考慮存儲庫像這樣:

HEAD -> master 

refs: 
    master -> sha_of_commit_X 
    dev -> sha_of_commit_Y 

objects: (addressed by sha1) 

    sha_of_commit_X, sha_of_commit_Y, sha_of_commit_Z, sha_of_commit_A .... 

git-reset操縱分支引用指向的內容。

假設你的歷史是這樣的:

  T--S--R--Q [master][dev] 
     /
    A--B--C--D--E--F--G [topic1] 
        \ 
        Z--Y--X--W [topic2][topic3] 

請記住,分支機構只是自動在提交預支名。

所以,你有如下分支:

master -> Q 
dev -> Q 
topic1 -> G 
topic2 -> W 
topic3 -> W 

和當前分支topic2,即,頭指向標題2。

HEAD -> topic2 

然後,git reset X將重置名稱topic2指向X;這意味着,如果你犯了一個提交的分支標題2 P,事情會是這樣的:

  T--S--R--Q [master][dev] 
     /
    A--B--C--D--E--F--G [topic1] 
        \ 
        Z--Y--X--W [topic3] 
          \ 
          P [topic2] 
相關問題