Git 學習(四)操做修改和版本穿梭 Git 學習(三)本地倉庫操做——git add & commit

Git 學習(四)操做修改和版本穿梭

   

  以前的章節,已介紹了本地Git庫建立、暫存區增、刪、改,以及提交版本庫;可回顧下命令操做: git add 和 git commit。html

  光有以前章節的操做,Git 顯然不能知足版本控制的需求。所謂的版本控制,可理解爲文件夾的時間機,即從建立該文件夾伊始,全部文件提交操做都將被記錄版本庫,且能夠隨意穿梭版本(回退至昨日的版本,或甚至N年前)。git

  本文就此具體說明Git是如何管理修改、撤銷修改以及在各個版本間穿梭的。工具

 

  管理修改

    爲何Git比其餘版本控制系統設計得優秀,由於Git跟蹤並管理的是修改,而非文件。爲達成這一目的,暫存區存在的意義就在於此。post

    此外,先依據 .git/index (暫存區文件)中記錄的時間戳、長度等信息判斷工做區文件是否改變。若是工做區的文件時間戳改變,說明文件的內容可能被改變了,須要要打開文件,讀取文件內容,和更改前的原始文件相比較,判斷文件內容是否被更改。若是文件內容沒有改變,則將該文件新的時間戳記錄到 .git/index 文件中。由於判斷文件是否更改,使用時間戳、文件長度等信息進行比較要比經過文件內容比較要快的多,因此 Git 這樣的實現方式可讓工做區狀態掃描更快速的執行,這也是 Git 高效的因素之一。學習

    git/index 實際上就是一個包含文件索引的目錄樹,像是一個虛擬的工做區。在這個虛擬工做區的目錄樹中,記錄了文件名、文件的狀態信息(時間戳、文件長度等),文件的內容並不存儲其中,而是保存在 Git 對象庫(.git/objects)中,文件索引創建了文件和對象庫中對象實體之間的對應。下面這個圖展現了工做區、版本庫中的暫存區和版本庫之間的關係。字體

工做區、版本庫、暫存區 操做原理圖url

在這個圖中,咱們能夠看到部分 Git 命令是如何影響工做區和暫存區(stage/index)的:spa

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

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

  圖中的 objects 標識的區域爲 Git 的對象庫,實際位於 ".git/objects" 目錄下

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

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

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

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

  當執行 "git checkout -- <file>" 命令時,會將文件在工做區的修改撤銷

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

上文內容實際上是第三章: Git 學習(三)本地倉庫操做——git add & commit 工做區與版本庫的補充說明,原理圖中說起的部分命令還未介紹,可先大體瀏覽,徹底看完下文後再理解上圖(該圖很重要)。

須要注意:工做區其實與Git庫是分離的,咱們在工做區進行的修改,若是不add到暫存區,commit提交併不會提交版本(再次重申,commit 提交修改僅針對暫存區)。

這邊所說的修改,包括文件自己的修改(刪行、加行、改內容等),而建立新文件或刪除,也算一個修改。

 

  修改撤銷

    這邊,介紹下暫存區撤銷修改的命令:

      git checkout -- <file1> <file2> ...   將文件在工做區的修改所有撤銷,可多個,空格分隔       

git checkout -- file命令中的 "--" 很重要,沒有"--",就變成了切換分支的命令,切換分支命令將在之後章節介紹。

    舉幾個具體示例來講明以上命令的用法,初始化空git庫,若你先建立了 1.txt 並將其 git add,你在工做區修改了 1.txt 文件,但發現修改錯了,須要撤銷修改至當時 git add 的狀況

        git add 時 1.txt 內容爲 111(即暫存區),工做區修改成 wrong

        git status  可見以下提示

       

       git checkout -- 1.txt  後,再次打開 1.txt,發現其中的內容被撤銷修改了,即內容爲 111;

 

      若工做區刪除了 1.txt,但如今又想撤銷刪除,也可操做 git checkout -- 1.txt ,此時查看工做區,可發現 1.txt 被恢復了。

      

 

  版本穿梭

    僅僅針對工做區的修改撤銷是遠遠不夠的,須要在全部版本庫中任意切換;版本是針對 commit 操做而言的,每次 commit 成功後,都會自動生成版本號。

      git log   顯示當前分支提交版本庫的日誌

      

       git log  該命令很經常使用,可顯示提交日誌信息(當前版本庫,可加參數,help查詢具體);上圖可見茶色字體顯示了一大串相似 的是commit id(版本號),和SVN不同,Git的commit id不是1,2,3……遞增的數字,而是一個SHA1計算出來的一個很是大的數字,用十六進制表示。

      每提交一個新版本,實際上Git就會把它們自動串成一條時間線。若是使用可視化工具查看Git歷史,就能夠更清楚地看到提交歷史的時間線:

      

 

      git reset --hard <revision>  重置至某一版本(強制,暫存區和工做區均重置)

        必須知道當前版本是哪一個版本,在Git中,用HEAD表示當前版本,也就是最新的提交,上一個版本就是HEAD^,上上一個版本就是HEAD^^ ...
        如上,咱們要把當前版本回退到最新版本,就可使用命令行  git reset --hard ,若使用命令行  git reset --hard HEAD^,則回滾爲上一版本,此時  git log  僅顯示了當前版本及其以前的信息

         

        命令可輸入版本號,前幾位便可(一般前7位);顯然,若回滾了昨天的版本後,又反悔了的這種狀況仍是時有發生的,這時,就須要輸版本號了;然則,版本號忘了怎麼辦。。這時,須要另外一個命令幫助:

      git reflog  顯示操做的日誌

        該命令可顯示操做日誌,且顯示了對應的版本號及信息,可查詢到以前的版本號並再次回滾, 如  git reset --hard 6de39b3  。

 

      Git的版本回退速度很是快,由於Git在內部有個指向當前版本的HEAD指針,當你回退版本的時候,Git僅僅是把HEAD指向改變

      

      改成指向 2

      

      而後順便把工做區、暫存區文件更新了。

相關文章
相關標籤/搜索