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

      

      而后顺便把工做区、暂存区文件更新了。

相关文章
相关标签/搜索