簡體   English   中英

撤消git命令-git checkout-

[英]Undo git command - git checkout --

有一種方法可以撤消以下git命令:

git checkout -- .

我試圖刪除已添加到repo目錄中但未暫存或未提交的文件。 該命令似乎沒有執行此操作,而是更改了一些其他文件。

更新:

未跟蹤的文件和未暫存的文件之間有區別。 在這種情況下,我想找到一種丟棄未跟蹤和未暫存文件的方法。 當我運行git checkout -- . ,我以為它會刪除未跟蹤的文件,但據我所知,它只會刪除未暫存的文件。

git checkout -- path 索引/暫存區工作樹的git checkout -- path副本

如果您命名的path是目錄,則Git將從該目錄開始並包括所有子目錄,將其知道的所有文件(在索引/暫存區域中找到)復制到工作樹中。

但是,要利用此答案,您需要了解每個文件的三個活動副本。

每個文件(最多)三個副本

請記住,在Git中,每個文件始終有多達三個版本處於活動狀態。 例如,假設您在存儲庫中已提交名為README.txta.ext文件。 三個副本 README.txt ,以及三份 a.ext在任何給定的時間,提供給您。 三份副本中的兩份采用特殊的僅Git格式。

如果我們使用git show用來訪問僅Git格式文件的語法,則可以通過以下方式描述這三個副本:

    HEAD             index        work-tree
---------------   -----------     ----------
HEAD:README.txt   :README.txt     README.txt
HEAD:a.ext        :a.ext          a.ext

如果現在創建一個新的未跟蹤文件b.dat ,則具有以下內容:

    HEAD             index        work-tree
---------------   -----------     ----------
HEAD:README.txt   :README.txt     README.txt
HEAD:a.ext        :a.ext          a.ext
                                  b.dat

在索引/暫存區域中尚無b.dat副本。 即使在HEAD和index中它們相同,其他兩個文件在邏輯上也兩個副本。 (當它們相同時,Git會自動共享基礎副本,因此不需要額外的空間。)

工作樹副本是普通文件

工作樹中存儲的任何文件的任何副本都只是一個普通文件。 您可以使用計算機執行的任何操作。 Git不在乎您如何處理此類文件。 如果您詢問Git有什么不同,Git 告訴您工作樹副本與索引副本不同。

git add path副本工作樹git add path 暫存區

假設此時,您可以使用任意喜歡的編輯器來修改README.txt ,該編輯器將編輯工作樹副本(除非它非常了解Git,否則它根本無法使用或觸摸索引副本)。 現在,工作樹副本不同於索引副本。 索引副本采用特殊的僅Git格式,可以進行下一次提交。

現在,您將需要運行git add README.txt ,以將更新的工作樹文件復制到索引中。 完成此操作后,舊版本的README.txt仍處於HEAD提交中, 並且仍采用特殊的僅Git格式,但是現在HEAD:README.txt:README.txt有所不同,而:README.txt是與README.txt相同。

每個文件的HEAD提交副本都是只讀的; 索引副本不是

任何提交中的任何內容都無法更改。 因此,您提交的README.txt副本和您提交的a.ext副本將永遠安全地保存在存儲庫中1 索引/暫存區中的副本可能與HEAD提交上的副本相同或不同, 可以隨時覆蓋。 它開始時一樣的人在HEAD,2,git add 工作樹副本, 索引中。


1如果放棄或刪除提交(通常通過git resetgit rebase -i進行刪除),則可能導致Git丟失凍結副本:凍結副本僅持續到包含該副本的提交為止。 但是,大多數Git都是基於添加新提交而不刪除舊提交的想法構建的。

2如果當前分支上有未提交的更改而簽出另一個分支,則可以克服 “簽出或提交后HEAD和索引匹配”的正常情況。 這個答案沒有足夠的空間來詳細說明這些細節。


git commit所有索引副本凍結到一個新提交中

git commit所做的是以當時索引中具有的格式獲取當時索引中的每個文件,並將其凍結為只讀的提交副本。 此提交的文件集成為新的HEAD提交。 一旦git commit運行完畢並返回提示,便有了一個新的提交,並且HEAD提交和索引匹配了-因為Git 索引中進行了新的提交!

未跟蹤的文件

Git非常簡單地定義了一個未跟蹤的文件 :它是不在索引中的文件。 就這樣—就是所有的一切—但卻有很強的后果:如果b.dat不在索引中,則git commit不會將其放入新提交中。 而且, git checkout -- 找不到 b.dat ,因為它不在索引中,所以它不能覆蓋工作樹副本。

請注意,僅僅是因為某些文件存在於存儲庫中的某些提交中,並不意味着就對該文件進行了跟蹤! 該文件被跟蹤,當且僅當該文件是在索引現在 如果您對確實包含該文件的提交運行git checkout那么 -那時-Git將把文件從提交中復制到索引中,再復制到工作樹中。 當時的文件將被跟蹤。 如果再明確從索引中刪除文件, 在某一時刻的文件將不再被跟蹤。 因此,您必須始終牢記或測試索引中是否存在某些特定文件的副本,以了解是否已跟蹤該文件。

git checkout commit -- path 提交索引和工作樹的git checkout commit -- path副本

在這里,使用git reset ,通過將多個不同的東西塞到一個命令中,Git變得過於復雜。 當您將git checkout 路徑一起使用,但沒有提交或樹說明符時,Git從索引復制到工作樹。 當您使用git checkout與兩條路徑提交,或樹,Git會復制到索引工作樹兩種

git reset -- path 提交索引的git reset -- path復制,不考慮工作樹

git reset這種特殊形式,與路徑一起使用,從提交復制到索引/登台區域。 請記住,索引已經包含所有跟蹤文件的副本,因此這只會用其他副本覆蓋這些副本。 默認情況下, git reset用於獲取文件的提交是HEAD提交-因此此副本從活動的HEAD副本復制到索引中。

任何文件的工作樹副本都將保留。 該文件存在於HEAD提交中的事實意味着該文件可能已被跟蹤:取消跟蹤該文件的唯一方法是簽出該提交,然后顯式刪除了索引副本。 在這種情況下, git reset -- path將文件放回到索引中,以便再次對其進行跟蹤。

但是請注意,您可以使用git reset commit -- path從某些特定的提交復制文件。 如果該文件不在 HEAD提交中,則在進行git reset操作之前,該文件可能會被取消跟蹤(不在索引中),但之后會被跟蹤(在索引中)。 這完全取決於您已經對索引進行了哪些更改。

摘要

運行git status 兩個比較:

  • 第一個比較是HEAD vs索引。 無論有什么不同,這里都會進行提交

    HEAD中的文件也可能在索引中(因此將跟蹤所有這些文件)。 如果索引中的副本與HEAD的副本不同,則Git調用准備提交的副本。 如果在索引中的副本是一樣什么在HEAD ,文件本身仍然是跟蹤和上演,這只是git status不會刻意去它。

    這里的關鍵思想是,即使每個提交都是所有文件的完整快照,我們一個提交的了解也往往是:與以前的提交相比,此提交有何不同? 因此, git status告訴我們,如果我們采用當前暫存區域(建議的新提交),然后將其實際轉換為新提交,會有什么不同。

  • 第二個比較是索引與工作樹。 無論有什么不同,這里都不會提交

    跟蹤索引中的文件。 對於那些與工作樹中的內容相匹配的內容, git status只是不用理會它們。 對於那些不同的內容, git status提及它們,而不是提交 對於不在該指數在所有,但都是在工作樹中的文件,Git的抱怨道關於他們是未經跟蹤

    再一次,這里的總體思路是,我們關心與之前的提交相比,每次提交實際上有什么不同。 如果我們已取消暫存或什至未跟蹤的文件與暫存副本不同(或缺少暫存副本),則可以使用git add將它們復制到暫存區域。 如果我們有一個與暫存的a.extHEAD:a.ext完全相同的工作樹a.ext ,我們可能根本不在乎,所以我們根本就不會看到它。

    要關閉Git絕對應該提交的未跟蹤文件,可以在.gitignore指令中列出那些未跟蹤的文件(按名稱或glob模式,例如*.o*.pyc )。 這樣可以防止Git自動在en-masse git add . git add --all ,並保持git status不變。 但是請注意,如果某個文件已經在索引中(無論它已經到達那里了),則在.gitignore列出該文件的名稱或模式將無效

復制文件的主要操作是:

  • git add path :從工作樹復制到索引
  • git checkout -- path :從索引復制到工作樹
  • git checkout commit -- path :從commit復制到索引和工作樹
  • git reset [ commit ] -- path :從commit (默認HEAD )復制到索引

刪除文件的主要操作是:

  • git add path :如果path在索引中但是從工作樹中丟失,則從索引中刪除
  • git rm --cached path :從索引中刪除,但不從工作樹中刪除
  • git rm path :從索引和工作樹中刪除
  • git reset [ commit ] -- path :如果未在commit包含path ,則從索引中刪除(默認HEAD

除了這些,還有一些你可以觸發特殊情況下git commit --only pathsgit commit --include paths ,但這些基本上等同於做git add對這些通路第一。 始終牢記索引,並注意git status 總結了索引的差異 ,而不是列出索引的內容,因此,如果您有30,000個大型文件項目,則只會看到很少的有趣文件,而不會看到所有30,000個文件。

暫無
暫無

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

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