Git的工做區、暫存區和版本庫之間的關係及其互操做

工做區,暫存區和版本庫之間的關係git

工做區:咱們會想固然的認爲,當前倉庫所在目錄就是咱們的工做區,其實這是不徹底正確的。在當前倉庫中,新增,更改,刪除文件這些動做,都發生在工做區裏面。服務器

 

暫存區:英文叫stage, 或index。在版本庫.git)目錄下,有一個index文件。它實際上就是一個包含文件索引的目錄樹,像是一個虛擬的工做區。在這個虛擬工做區的目錄樹中,記錄了文件名、文件的狀態信息(時間戳、文件長度等),文件的內容並不存儲其中,而是保存在Git對象庫(.git/objects)中,文件索引創建了文件和對象庫中對象實體之間的對應。若是當前倉庫,有文件更新,而且使用git對象

 add 命令,那麼這些更新就會出如今暫存區中。blog

 

版本庫:當前倉庫下,若是沒有任何的提交,那麼版本庫就是對應上次提交後的內容。下面這個圖展現了工做區、版本庫中的暫存區和版本庫之間的關係。索引

 

 

圖中左側爲工做區,右側爲版本庫。在版本庫中標記爲 "index" 的區域是暫存區(stage, index),標記爲 "master" 的是 master 分支所表明的目錄樹。ci

 

  圖中咱們能夠看出此時 "HEAD" 實際是指向 master 分支的一個「遊標」。因此圖示的命令中出現 HEAD 的地方能夠用 master 來替換。it

 

  圖中的 objects 標識的區域爲 Git 的對象庫,實際位於 ".git/objects" 目錄下,裏面包含了建立的各類對象及內容。io

 

  當對工做區修改(或新增)的文件執行 "git add" 命令時,暫存區的目錄樹被更新,同時工做區修改(或新增)的文件內容被寫入到對象庫中的一個新的對象中,而該對象的ID被記錄在暫存區的文件索引中。ast

 

  當執行提交操做(git commit)時,暫存區的目錄樹寫到版本庫(對象庫)中,master 分支會作相應的更新。即 master 指向的目錄樹就是提交時暫存區的目錄樹。基礎

 

  當執行 "git reset HEAD" 命令時,暫存區的目錄樹會被重寫,被 master 分支指向的目錄樹所替換,可是工做區不受影響。

 

  當執行 "git rm --cached <file>" 命令時,會直接從暫存區刪除文件,工做區則不作出改變。

 

  當執行 "git checkout ." 或者 "git checkout -- <file>" 命令時,會用暫存區所有或指定的文件替換工做區的文件。這個操做很危險,會清除工做區中未添加到暫存區的改動。

 

  當執行 "git checkout HEAD ." 或者 "git checkout HEAD <file>" 命令時,會用 HEAD 指向的 master 分支中的所有或者部分文件替換暫存區和以及工做區中的文件。這個命令也是極具危險性的,由於不但會清除工做區中未提交的改動,也會清除暫存區中未提交的改動。

 

使用git diff查看各個區之間的差別

git diff 和 git diff --cached容易混淆

 

  git diff 比較的是工做區和暫存區的差異

 

  git diff --cached 比較的是暫存區和版本庫的差異

 

  git diff HEAD 能夠查看工做區和版本庫的差異

 

  每次commit後,git diff --cached沒有內容,是由於暫存區的內容已經更新到版本庫中,所以暫存區和版本庫中的內容無差異

git reset和git revert的區別

reset是重置,默認是git reset --mixed <commit> 可讓版本庫重置到某個commit狀態,該commit以後的commit不會保留,並重置暫存區,可是不改變工做區。即這個時候,上次提交的內容在工做區中還會存在。

  若是使用git reset --hard <commit> 將版本庫,暫存區和工做區的內容所有重置爲某個commit的狀態。以前的commit不會保留。

  revert比reset更加溫柔一點,回滾到某次commit且該commit以後的提交記錄都會保留,而且會在此基礎上新建一個提交。對於已經push到服務器上的內容做回滾,推薦使用revert。

 

 

下面是一個實際問題:


git checkout -- <path> doesn't do a hard reset; it replaces the working tree contents with the staged contents. git checkout HEAD -- <path> does a hard reset for a path, replacing both the index and the working tree with the version from the HEAD commit. 

 

一些總結:

A "hard reset" for a path is just done with git checkout HEAD -- <path>. A soft reset for a path doesn't make sense. A mixed reset for a path is what git reset -- <path> does.

相關文章
相關標籤/搜索