標籤:

一個奇怪的git問題,求大家幫忙分析一下?

比如我現在在工作區新建一個文件叫test.html,然後git status:

git檢測到這個新添加的文件,提示通過add加入暫存區。

下面執行:

git reset --hard

貌似沒有執行什麼,再看git status:

還是剛添加文件時的git status提示,新添加的test.html沒有被刪除。

現在執行:

git add dist/test.html

在查看git status狀態:

新添加的test.html放入暫存區,下面執行:

git reset --hard

再看git status,工作區和暫存區全部乾淨了,新添加的test.html也沒有了。

總結下兩次操作的區別:

同樣是新建了一個test.html文件

  1. 第一種是直接git reset --hard,新建test.html文件在工作區被保留
  2. 第二種是先add這個新建test.html文件,被添加到暫存區,然後git reset --hard,工作區的test.html文件也被刪除了。

如果git reset --hard是拿上次提交的記錄來覆蓋工作區和暫存區的話,那麼第一種情況時,test.html就應該被刪除。如果是git reset --hard不對沒有被追蹤的文件進行處理的話,第二種情況下,test.html在工作區不會被刪除。

自己已經暈了,等git來解答,我覺著這很可能是git的一個bug。


首先這不是Git的Bug

請先熟悉這幅圖:

git add 實際上已經把文件提交到了Staged區域

git status命令實際上已經明確提示了:

如果想把Staged區域的文件撤銷,需要使用git reset HEAD &命令

而git reset --hard HEAD命令,引用GitBook里的話:

這條命令會把你工作目錄中所有未提交的內容清空(當然這不包括未置於版控制下的文件 untracked files).

以上


如清風所言,第一,請先熟悉這幾張圖。

第二,關於git add的本質。

git add命令在git里是一個典型的多功能命令,在不同場景下有不同的功能:

1.開始跟蹤新文件,直接添加到暫存區

2.把已跟蹤,修改後的文件添入暫存區

3.合併時把有衝突的文件標記為已解決狀態

擴展:這也正是git commit -a和分別執行git add/git commit的區別。(比如新添加的圖片,由於還處於未跟蹤狀態,git commit -a並不會把圖片也commit)。

第三,關於git reset --hard 的本質。

本質:暫存區的該文件會被master分支的該文件所替換,回到最近一次git commit的狀態。工作區不變。

第四,就題主的疑問

「第一種是直接git reset --hard,新建test.html文件在工作區被保留」

憑空新建的test.html屬於untracked(未跟蹤)文件,沒有git add,一直還是處於工作區且未跟蹤狀態。根據git reset --hard的本質(暫存區的該文件會被master分支的該文件所替換,回到最近一次git commit的狀態。工作區不變。),test.html不會受到影響。

「第二種是先add這個新建test.html文件,被添加到暫存區,然後git reset --hard,工作區的test.html文件也被刪除了。」

憑空新建的test.html屬於untracked(未跟蹤)文件,執行完git add後,添加到了暫存區,根據git reset --hard的本質(暫存區的該文件會被master分支的該文件所替換,回到最近一次git commit的狀態。工作區不變。),test.html被成功「刪除」。


這不是bug

第一種情況你的檔案是 untracked

即然是 untracked,那麼 git 就不會去管你的檔案,要刪要存你自己看著辦。

第二種情況你把檔案交給 git 做管理(git add),所以執行 git reset 之後 git 幫你回覆到先前的狀態(沒有檔案)


首先,這不是 git 的 bug。

`git add` 操作是把文件加到 git 的 `index` 中,這個時候 git 會為其創建一個 blob 對象,保存到 `.git/objects` 目錄下,通過 `git ls-files` 可以看到 git 為該文件做好與物理文件的映射。

`git reset --hard` 操作的是 git 對象資料庫與其 `index`,它影響不了任何未加入版本控制的文件。如果你要刪除這些文件,可以用 `git clean -f`,這個命令不操作任何 git 對象和 `index`,它僅僅是把 `untracked files` 列出來,然後執行系統命令 `rm -f` 而已。

從下面的截圖,你可以看得更清楚:


1 Treat git as a data structure

2 If test.html is not in the data structure, all the command have no effect.

3 If test.html is in the data structure, all the command will work.

So this command (git reset --hard) only work after git add test.html

Again, please read the official documents.


如果git reset --hard是拿上次提交的記錄來覆蓋工作區和暫存區的話,那麼第一種情況時,test.html就應該被刪除。

你這個推斷是錯誤的,


謝邀

這並不是git的bug

因為題主沒有正確的理解git stage

可以仔細看看他全部的文檔(我已經看了很多遍)

Git - Recording Changes to the Repository

希望題主學習順利

並可以從中掌握更多git的相關知識


推薦閱讀:

在使用git的過程中 為什麼要是使用命令行?
.Net控制Git.exe進程交互遇到的問題?
為什麼我在git上提交代碼都會重複提交別人更新的代碼?

TAG:Git |