簡體   English   中英

git checkout HEAD -- 之間有區別嗎? 和 git reset --hard HEAD?

[英]Is there a difference between git checkout HEAD -- . and git reset --hard HEAD?

我已經查看了這個 stackoverflow 鏈接,但我認為我所要求的之間的細微差別是結帳 cmd 中HEAD的使用,因為他們的建議似乎不起作用:

git reset --hard HEAD 和 git checkout 之間有區別嗎?

git checkout HEAD -- . 也清理我的集結區。 此外,關於添加到暫存區的已刪除文件的第二個答案似乎是通過git checkout HEAD -- .回來的git checkout HEAD -- .

有沒有一種情況會得到不同的結果?

是的,除了. 如果您不在存儲庫的頂層。 我不會說以下是唯一的區別; 僅舉一個例子就足以看出它們是不同的。

用於說明差異的設置

首先創建一個至少有一次提交的新存儲庫(這里我做了兩次,這是我的習慣):

$ mkdir treset
$ cd treset
$ git init
Initialized empty Git repository in ...
$ echo 'for testing reset vs checkout' > README
$ git add README
$ git commit -m 'initial commit'
[master (root-commit) 058b755] initial commit
 1 file changed, 1 insertion(+)
 create mode 100644 README
$ echo contents for file a > file-a
$ echo contents for file b > file-b
git commit -m 'add files'
[master f505609] add files
 2 files changed, 2 insertions(+)
 create mode 100644 file-a
 create mode 100644 file-b

此時, HEAD和索引匹配——都包含來自提交f505609的內容——並且工作樹也包含與該提交匹配的(正常格式)文件。 現在讓我們添加一個文件,並將其復制到索引中:

$ echo 'uncommitted file' > foo
$ git add foo

從技術上講, git add foo在存儲庫中創建了blob 對象a9e2570d6af8c05b57e2cefecaebeedfabc98bf2 ,然后將該哈希 ID 放入索引中:

$ git ls-files --stage
100644 e16f62b2e75cf86a6f54adcfddcfd77140f238b9 0       README
100644 881d9334f4593efc7bab0dd536348abf47efed5c 0       file-a
100644 fa438bc26ce6b7a8f574bad9e63b83c912a824b9 0       file-b
100644 a9e2570d6af8c05b57e2cefecaebeedfabc98bf2 0       foo

(此Blob對象的哈希ID是用於文件已知的內容預見,由於foo ,這是其他三個文件也是如此,但他們實際上是承諾,所以這些斑點的對象是永久的。一個為foo可以GCed ,如果我們從未真正提交它而是從索引中刪除條目。)

使用git checkout HEAD

如果我們使用git checkout HEAD ,我們會指示 Git 從HEAD復制到索引中,然后將它們擴展為正常的工作樹文件。 HEAD包含三個文件( READMEfile-afile-b ),因此這樣做並使用它們已有的內容更新三個工作樹文件 - 因此沒有可觀察到的影響。 1

$ git checkout HEAD -- .; ls
file-a  file-b  foo README

請注意,文件foo保留在索引(再次運行git ls-files以查看)和工作樹中。


1除非,也就是說,我們通過可用的任何操作系統級工具檢查文件修改時間或執行的系統調用等內容。 在這種情況下,我們可以判斷 Git 是否真的覆蓋了工作樹文件。 在我的系統,它實際上並沒有,因為索引散列相匹配的HEAD哈希和stat中相匹配的索引緩存的數據stat從工作樹中的文件數據,所以沒有理會。 原則上Git 將HEAD復制到索引,然后將索引復制到工作樹,如果需要基於哈希和/或統計數據,Git 實際上會在這里觸及工作樹文件。


使用git reset --hard

如果我們告訴 Git 重置索引以匹配當前提交,並重置工作樹以匹配索引的更改,則操作是不同的。 這一次,Git 檢查索引並看到文件foo存在,而它在提交中不存在。 所以 Git索引中刪除文件foo ,並相應地更新工作樹:

$ git reset --hard HEAD; ls
HEAD is now at f505609 add files
file-a  file-b  README

文件foo已從工作樹中消失。

如果我們使用git reset --mixed HEAD ,Git 會從索引中刪除foo ,但不會從工作樹中刪除。 (這種重置的默認操作——還有許多其他類型——是--mixed 。)

使用git restore

使用新的 Git 2.23+ git restore命令,我們可以分別控制索引和工作樹。 首先,我們必須將foo放回索引和工作樹中:

$ echo 'uncommitted file' > foo
$ git add foo

我們現在可以選擇是否將HEAD復制到索引,以及是否類似地管理工作樹。 它的文檔也更加明確:

如果路徑已被跟蹤但在還原源中不存在,則將刪除該路徑以匹配源。

路徑被“跟蹤”的意思是路徑在索引中。 在這種情況下, foo現在在索引中(由於git add )所以它被跟蹤。 如果我們從HEAD恢復索引, foo將從索引中刪除,就像git reset --hardgit reset --mixed 所以讓我們嘗試VonC 的命令,但使用. (當前目錄和所有子目錄) 2作為路徑名,這里:

$ git restore --source HEAD --staged --worktree .
$ ls
file-a  file-b  README

所以你可以看到這與git reset --hard具有相同的效果。 git reset不同, git restore只有一項工作——盡管它有兩部分——所以我們不必擔心其他操作模式。

(這就是同時添加git switchgit restore原因:它們大多做與git checkoutgit reset已經可以做的相同的事情,但它們只有一項工作,即使它有幾個部分。相比之下, git checkout有大約三到大約七種不同的工作,這取決於您的計數方式,而git reset有大約三到大約五種。3 )


2這個特定的存儲庫只有一個頂級目錄,所以我們不必擔心您已經在工作樹中創建了一個cd subdir子目錄。 但是,如果你有, . 將意味着將其應用於subdir/* files ,以便 checkout 和 reset 會更加不同。

3對於git checkout ,請考慮:

  • 切換分支
  • 從索引提取到工作樹(僅限於git checkout-index
  • 從特定提交中提取到索引,然后提取到工作樹
  • 重現合並沖突( git checkout -m帶有文件名)
  • 合並時切換分支( git checkout -m但帶有分支名稱)

雖然這只是五個,但我們可以git checkout --oursgit checkout --theirs ,有些人可能希望將它們與通常的“從索引中提取”風格分開計算。 當您添加創建分支git checkout -b )並強制重置分支git checkout -B )時,我們可以獲得更多。 唉, git switch也有創建和強制重置選項!

當然,有些人可能會像git checkout那樣將其中的一部分或全部合並到一個操作中。 這就是為什么我說“取決於你如何計數”。

對於git reset ,請考慮:

  • 無需移動HEAD即可重置索引和/或工作樹
  • 使用移動HEAD重置索引和/或工作樹
  • 重置一個或多個特定路徑(無法移動HEAD
  • 中止合並或櫻桃挑選或還原(無法移動HEAD
  • 使用git reset -p有選擇地修補(無法移動HEAD

所有這些都集中在一個命令git reset

為避免混淆,您應該使用新的實驗命令git restore (Gti 2.23+,2019 年 8 月)。

正如我在“什么是git restore命令? git restoregit reset之間有什么不同? ”中所解釋的那樣,您可以使用git restore指定要git restore

  • 指數
  • 和/或工作樹。

這比在git checkout依賴 HEAD 或沒有 HEAD 更明確。

要使用git restore進行reset --hard

git restore --source=HEAD --staged --worktree hello.c

或者更實用但可讀性較差的簡短形式:

git restore -s@ -SW hello.c

暫無
暫無

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

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