接下来我们要详细深入的去探索一下Git的提交历史以及原理。
git log命令
git log可以查看提交历史。

git log --patch -1
--patch 可以显示每次提交之间的diff,
-n 可以指定显示最近几个commit。
这个是命令很有用,可以看最近两次commit之间的代码差异,进行code review是比较方便的。
git log --stat
可以显示每次commit的统计信息,包括修改了几个文件,有多少行插入,多少行删除。
git log --oneline
显示简短的hash,每个commit显示一行
git log --oneline --graph
这是最有用的,可以看到整个commit树结构,包括如何合并的,就显示每个commit的SHA-1和提交说明,同时SHA-1显示短值。
--oneline:显示一行,不要显示多行那么多东西,一行里,就显示commit的标识符,SHA-1 hash值,40位的;提交备注;显示分支和HEAD指向哪个commit
--graph:显示图形化的commit历史,这个大家后面学习到分支那里就知道了,如果有分支的话,commit历史会形成一棵树的形状,这个时候用--graph可以看清楚这颗commit树长什么样子,很有用。

注意看一下,log中最近一次提交 HEAD -> master 是什么意思?
分支简单了解:后面章节着重讲解
版本控制系统中都有一个概念,叫做分支。使用分支意味着你可以从开发主线上分离开来,然后在不影响主线的同时继续工作。即同样的一份代码拷贝多次,每次拷贝的代码刚开始都是一样的,然后不同的人可以基于几个拷贝的项目去开发;然后开发完之后,再将拷贝的代码合并在一起,这就是分支的过程。
git里面每次git init之后,默认初始就创建一个分支,叫做master分支。
我们每次写代码,然后git commit提交,都会形成一次新的commit,然后默认就是在master分支对应的代码拷贝上,进行代码修改和提交的
每次提交之后,master分支就会对应着最新的一次提交
HEAD,指针,指向了我们当前所处的分支,因为当前我们默认就处于master分支上,所以HEAD指针就是指向master的。
图解git原理
上面的文字太抽象,我们来画图理解一下:

上图为文件1和文件2存放git中的过程状态:
文件1、文件2新建后add到暂存区,再提交到仓库。
文件1修改后add到暂存区,在提交到仓库。
我们来分析一下在仓库中文件1和文件2的变化过程:
文件1和文件2新建

1、在新建的文件1commit到仓库后,会在仓库中形成一个blob的数据结果,文件1和文件2的V1版本都以blob的形式存储到了仓库中。
2、同时还有一个tree object,它会存在两个指针分别指向两个blob。tree object其实就是一个指针,用于指向仓库的blob文件的。
3、commit object就是对应的commit的信息。如:

4、master本地分支其实是一个指针,指向的是最新一次commit。
5、HEAD也是一个指针,他来区分当前是哪一个分支。
文件1修改

1、文件1修改后commit到仓库里面,此时又回新创建一下修改了的文件1的V2版本的blob。
2、创建一个新的tree来指向 文件1 V2 blob 和 文件2 V1 blob。
注意:
文件没有变化,Git 不会再次保存,而只对上次保存的快照作一链接。
git会根据文件进行计算hash身份验证,如果hash相同则表示没有修改过。
3、会有一个新的commit object信息,指向的tree object是新创建的tree object;
也会有指向上一次commit的指针,指向hash:1234567的commit。object。
4、此时的master指针就指向了最新的一条commit object。
5、HEAD由于分支没变所以依然指向master本地分支。
commit object原理总结:
实际上每次我们执行一次commit,git都会存储一个commit object,这个commit object中会包含一个指针,指向这次提交文件的快照。这个commit object同时也包含作者的姓名和邮箱,提交说明,以及对上一次commit object的指针。
将一个文件版本放入暂存区的时候,就会计算一个校验和,然后提交的时候会将文件内容以blob的方式放入版本库中,同时在暂存区放入这个文件版本的校验和。接着git会创建一个commit object,其中会包含元数据,以及一个指针指向版本库中的文件快照。
也就是说,每次执行一次提交,都会在版本库中包含这么几个东西:一个blob,每个文件都会有一个blob来存储这个文件的本次提交的快照;一个tree,这个tree会包含对本次提交的所有文件的blob的指针;一个commit object,指向了tree的指针,作者,等信息。
接着如果再次执行一个提交,那么下一个提交同样会包含那些东西:每个文件一个blob,一个tree指向所有blob,一个commit object指向那个tree,同时这个commit object会有一个指针,指向上一个commit object。
最后多次提交,就会得到一颗完整的commit树。
git reset命令
git reset --hard HEAD^,就可以回退到上一个版本
HEAD^,代表的是commit(add methods for classes)的上一个commit(add two files)
git reset --hard HEAD^,就是将仓库、暂存区、工作区,全部恢复到上一个commit(add two files)对应的状态
git reset --hard HEAD^^,可以回退到上两个版本
git reset --hard HEAD~5,退回到HEAD之前的倒数第5个commit的状态
git reset --hard d324644,指定一个commit的hash值,回退到很老的版本
如果我们要回来怎么办?
git reflog命令

上图应该很明确的说明了git log
与 git reflog
的区别啦。
git reflog
可以回到过去回到未来。
git log
只能回到过去。
知道了回到未来的版本号,就可以继续使用git reset
命令回到未来版本啦!




