簡體   English   中英

git reset --hard 似乎沒有重置未提交的更改

[英]git reset --hard does not seem to be reseting uncommited changes

我是 Git 的新手,我做了一些不需要的更改,如下所示:

捕獲

現在我不需要任何這些,所以我嘗試了這個:

git reset --hard

但它仍然顯示它們!

那么我如何重置它並回到我沒有創建任何這些不需要的文件的地方?

一個未跟蹤的文件:

  • 沒有從當前提交中出來(請參閱下面的可能異常,在詳細描述中);
  • 不在提議的下一次提交中;
  • 躺在圍繞你的工作樹

因此,該文件現在不在 Git 中,明天也不在 Git 中,因此任何Git操作都不會觸及它。

如果您不希望這些文件出現在下一次提交中,則無需執行其他任何操作。

龍:這是怎么回事

Git 與files無關。 Git 是關於commits 的

那些剛接觸 Git 的人通常認為這是關於文件的,但事實並非如此。 提交確實包含文件,但 Git 是關於提交的。 他們可能還認為 Git 是關於分支的,但這也不是真的:分支名稱確實可以幫助您(和 Git)找到提交,但 Git 仍然是關於提交的。

由於 Git關於提交的,因此您需要了解它們。 以下是您現在需要知道的:

  • 每個提交都有一個編號。 這些不是簡單的計數:我們沒有提交#1,然后是#2,然后是#3,依此類推。 取而代之的是,每次提交都會得到一些非常大、又大又難看的數字,看似隨機,例如5a73c6bdc717127c2da99f57bc630c4efd8aed02

    此編號對於此特定提交是唯一的。 任何地方的每次提交,無論是誰、何時、何地等,都必須獲得自己唯一的編號。 這就是為什么這個數字必須如此之大。 該數字實際上是加密哈希函數的輸出。

  • 每個提交存儲兩件事:

    • 每個提交存儲每個文件的完整快照。 這是提交的主要數據部分。 提交中的文件是一種特殊的、壓縮的、僅限 Git 和去重的文件:它們根本不是普通文件(並且 Git 可以存儲某些系統(例如 Windows)無法提取的文件,這給Windows 用戶)。 這充當永久存檔,就像提交中所有文件的 tar 或 zip 文件。
    • 並且,每個提交都存儲一些元數據:關於提交本身的一些信息,例如誰提交以及何時提交。 這個元數據讓 Git 將新提交與舊提交聯系起來,這就是 Git 完成大量工作的方式。

由於加密編號方案,任何提交的任何部分都不能更改 一旦你做了一個提交,它就會永遠凍結。 (如果你錯誤地犯了一個錯誤的提交,你可以停止使用它。它會存在很長時間,以防你想要它回來,但最終 Git 會發現你不僅沒有使用它,而且——在合適的條件下——其他人也永遠無法找到和使用它,因此 Git 可以完全刪除它。但這是一個更棘手的問題,我們不會在這里擔心。)

但是如果提交是只讀的(確實是),並且提交中的文件以只有 Git 本身可以讀取(並且確實如此)並且實際上沒有任何內容可以寫入的格式存儲,我們將如何獲得任何實際工作完畢? Git 在這里與所有版本控制系統都有相同的答案,它們都有這種問題。 你不說是Git的文件。 相反,您在 GitGit 中取出副本上工作。

Git的提取您的需求,文件的這些可用的,可行的副本,當你檢查出有犯git checkoutgit switch 可用文件進入工作區,Git 稱之為工作樹工作樹 這非常簡單明了:您的工作樹是您完成工作的地方。 它有您可以查看使用的文件。 但是這些文件不在 Git 中

進行新的提交

其他(非 Git)版本控制系統以相同的方式開始:您提取提交,並獲得有用的文件。 然后您根據需要編輯文件,當您准備好時,您可以運行,例如hg commit (對於 Mercurial,一個不同的版本控制系統)。 這個非 Git VCS 計算出您對文件做了什么並進行了新的提交,然后一切就緒。

Git 讓事情變得更加困難。 Git 設置了一個單獨的東西,而不是在您運行git commit時讀取您的工作樹。 這東西有三個名字,也許是因為第一個名字很糟糕。 這三個名字分別是:

  • 索引:這個名字並不意味着什么,它有一些好的和壞的方面; 我自己傾向於使用這個;
  • 暫存區:這個名字反映了你如何使用這個東西,也許是最好的名字;
  • 緩存:這個名字不太好,Git 現在大多避免使用它,但它在git rm --cached類的標志中徘徊。

這個東西——索引或暫存區——保存你提議的下一次提交 當你第一次檢出一些提交時,Git 用你提交的所有文件的副本(或“副本”,因為它們已經被去重:索引“副本”是 Git 的內部格式)填充它剛退房。 這些文件也會進入你的工作樹(作為真實的普通文件,而不是奇怪的 Git 化的重復數據刪除魔法)。

當您修改某個文件的工作樹副本時,只會更改該文件的工作樹副本。 Git文件在任何地方都沒有改變。 提議的下一次提交仍保留文件的先前版本,即 Git 從當前提交中提取的文件。

如果您希望 Git 提交更新的副本,而不是您從先前提交中取出的舊副本,您必須告訴 Git 更新其索引/暫存區。 您可以使用git add執行此操作,例如, git add file.ext 這告訴 Git 讀取file.ext工作樹版本,將其壓縮為 Git 的內部格式,根據需要安排重復數據刪除,並為下一次提交做好准備。 文件的下一次提交就緒副本進入索引/暫存區,現在您已經更新了建議的下一次提交

這一切意味着,在任何時候,每個文件都有三個副本(盡管其中一些是 Git 化的,因此進行了重復數據刪除):

  HEAD         index      work-tree
---------    ---------    ---------
README.md    README.md    README.md
main.py      main.py      main.py

例如,如果當前提交中有三個文件。 HEAD副本是只讀的(並且去重); 索引副本是可替換的(但也可以去重復); 並且工作樹副本是可用的普通文件,不會進行重復數據刪除,但可以讓您完成工作。

運行git commitindex 中的副本進行新的提交。 所以這就是這些副本存在的原因:為下一次提交做好准備。

未跟蹤的文件

您的工作樹只是您計算機上的一個普通目錄(或文件夾,如果您喜歡該術語)。 因為它一個普通文件夾,您可以在此處創建新文件,或刪除現有文件。 Git 不會知道或關心您是否這樣做了:提議的下一次提交隱藏在 Git 的索引(或暫存區)中。 它沒有新文件:

  HEAD         index      work-tree
---------    ---------    ---------
README.md    README.md    README.md
main.py      main.py      main.py
                          new.txt

現在在您的工作樹中但現在不在Git 索引中的任何新創建的文件都是untracked files 這就是未跟蹤文件在 Git 中的定義方式:未跟蹤文件是指確實存在於您的工作樹中但不存在於 Git 索引中的文件。

如果您對這些未跟蹤的文件之一運行git add ,Git 將讀取它,將其壓縮為內部格式,檢查重復項等,並將新文件添加到 Git 的 index ,使其暫存以進行提交。 現在該文件確實存在於 Git 的索引中(以及您的工作樹中),因此它不再是未跟蹤的文件 通過更改 Git 索引中的文件集,您已經更改了未跟蹤的文件:

  HEAD         index      work-tree
---------    ---------    ---------
README.md    README.md    README.md
main.py      main.py      main.py
             new.txt      new.txt

同樣,您可以使用git rm --cached從 Git 的索引中刪除文件,但將其保留在您的工作樹中。 這會導致跟蹤的文件變為未跟蹤。 (這是我之前提到的特殊例外:如果文件在您檢出的提交中,但隨后您刪除索引副本,則它現在未被跟蹤。)

同樣,所有這些更新都發生在 Git 的索引中,您看不到. 沒有明顯的地方可以在 Git 的索引中查找文件。 1但是,如果 Git 對此完全保持沉默,那么 Git 將比現在更難使用。 所以git status報告未跟蹤的文件。

運行git status實際上做了很多事情:

  • 首先,它讓 Git 打印出你當前的分支名稱,以及其他一些有用的信息。

  • 接下來,它讓 Git 將當前提交(即HEAD )與索引進行比較。 對於所有匹配的文件, git status什么都不說 對於任何不同的文件, git status表示此文件已暫存以進行 commit 這意味着文件的索引副本是不同的

  • 然后git status讓 Git 將索引文件與工作樹文件進行比較。 對於所有匹配的文件, git status什么也沒說 對於任何不同的文件, git status表示此文件未暫存為 commit 這意味着文件的工作樹副本是不同的 2

盡管如此, git status忽略任何未跟蹤的文件 它確實收集了他們的名字:當 Git 運行第二次比較時,任何未跟蹤的文件都會顯示出來,並且 Git 現在擁有未跟蹤文件的完整列表。

現在git status將顯示未跟蹤的文件,但現在.gitignore文件會啟動,如果你有的話。


1可以運行git ls-files --stage來轉儲 Git 索引中的內容。 但這並不適用於日常工作,也不是完成工作的好方法。

2請注意,所有三個副本都可以不同 例如,查看一些具有README.md現有提交。 在文件中添加一行並運行git add README.md 然后在文件中添加第二行。 現在三個副本都不同了。 試試git status 該文件既“為提交而暫存”,又“未暫存以進行提交”。 這只是意味着 HEAD-vs-index 顯示添加的第一行,而 index-vs-working-tree 顯示添加的第二行。

如果您現在運行git commit ,Git 會提交每個文件的索引副本。 所以提交中的README.md文件只添加了一行。 如果您現在運行git add README.md ,Git 會用添加的一行替換索引副本,並使用包含兩行添加的新索引副本。


可以“忽略”未跟蹤的文件

如果某些文件未經跟蹤, git status通常會列出它在這一節中,你在你的輸出不喜歡像節目文件app/Popup.php 在此處列出此文件的目的是提醒您尚未添加該文件,並且在您添加之前它不會出現在下一次提交中。

但是,如果該文件不應該出現在下一次提交中,甚至不應該出現在任何提交中呢? 好吧,該問題的一個答案是您現在可以刪除該文件:

rm app/Popup.php

現在它不再在您的工作樹中。 (請注意,此刪除不Git的完成,甚至GIT中,這是你對自己就是這樣做的東西。)由於這個文件是從來沒有Git,它現在消失了,至少盡可能的Git去。 Git 無法幫你找回它。 Git 中從來沒有過!

但是:也許您不想刪除它。 也許你想同時告訴 Git 兩件事:

  • 嘿 Git,不要再抱怨app/Popup.php
  • 嘿 Git,不要將app/Popup.php添加到您的索引中! 不應該犯!

要做到.gitignore ,您可以在.gitignore文件中列出該文件:

echo app/Popup.php >> .gitignore

或者:

echo /Popup.php >> app/.gitignore

(這些將在此處產生相同的效果)。

.gitignore文件中列出一個文件,或者像*.o*.pyc這樣的 glob 模式,告訴 Git:停止抱怨這個文件/與這個模式匹配的文件,當它們未被跟蹤時 所以這使得git status更有用:它只警告你現在應該跟蹤的文件。

它還會阻止git add添加文件。 您可以強制git add添加文件,但默認情況下, git add現在不會將文件添加到 Git 的索引中。

如果文件已經在 Git 的索引中,這些都沒有任何影響。 所以.gitignore並不是真正要忽略的文件列表。 這真的是.git-don't-complain-about-these-files-if-they-are-untracked-and-do-not-add-them-to-the-staging-area-unless-I-force-it-because-they-are-supposed-to-stay-untracked-okay? , 或類似的東西。 但是將它作為文件名會很瘋狂,所以 Git 只是將其稱為.gitignore

底線

未跟蹤的文件不會出現在您的下一次提交中 說“我該怎么處理這些我在下一次提交中不想要的文件”是沒有意義的:它們已經不會出現在您的下一次提交中。 詢問如何通過不列出文件來使git status更有用,這很有用。 不過,這真的非常簡單:您只需要習慣 Git 的奇怪之處,即始終為每個文件創建三個副本,並且名稱.gitignore具有誤導性:這些文件根本沒有被忽略,它們只是默默地未被跟蹤只要它們實際上未被跟蹤(如果不使用類似調試的git ls-files就很難判斷)。

正如git status告訴你的那樣,這些文件是untracked 這意味着它們超出了 Git 的權限。 因此git reset --hard對他們沒有任何作用。

告訴 Git 刪除未跟蹤文件的命令是git clean 它有多種選擇; 例如,它不會在沒有這樣做的情況下遞歸到文件夾中,所以也許你想要git clean -d

(這是一個危險的命令——在錯誤的時間說它基本上可以擦除你的整個硬盤——所以我強烈建議你說git clean -d -n做一次試運行,看看會先實際發生什么。)

暫無
暫無

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

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