这一讲是关于最流行的版本控制(version control system)工具git的介绍。
概述
第一个问题,什么是版本控制系统?版本控制系统常常用来管理源代码(或其他文本格式的文件,二进制文件不推荐)。版本控制系统能够记录文件的历次修改(增删改),并能够记录与之相关的元信息,如修改人,修改原因等。同时也是团队协作的利器。
我们很多人学习git,可能都是采用的自顶向下的学习方法,也就是先接触了git的各种命令。老实说,git的命令行工具入门还是有些门槛的。在这个lecture中,将自底向上地介绍git的基本工作原理。当对git的data model有所了解后,那些命令可能也会变得更加好理解。
git data model
git的data model是很优雅的。
snapshot
在git中,一个文件叫做blob(也就是a bunch of bytes),一个文件夹叫做tree。tree下面可以递归地挂tree或者blob。
1 | <root> (tree) |
最顶上(top-level)那棵树就是一个snapshot。
建模历史
用户的更改就是一个个snapshot的更新。snapshot的历史变化就是项目的更新过程。怎么描述这个过程?一种简单的方法是线性表,也就是把历史snapshot按照时间顺序依次排列连接。但这种方法比较单一,git实际采用的是有向无环图DAG。snapshot就是DAG中的每个节点,叫做commit。在下图中,每个节点前面的箭头都指向它的parent。注意,在第三个节点后,历史出现了分叉。在实际中,这可能对应于两个不同的feature开发。git的DAG描述使得这种多个功能并行开发成为可能。
1 | o <-- o <-- o <-- o |
使用下面的伪代码描述:
1 | // a file is a bunch of bytes |
object
上面的blob
,tree
和commit
都是object
。所有的object都有一个SHA-1 hash的字符串来标记。
1 | type object = blob | tree | commit |
例如,上面给出的那个snapshot,可以使用git cat-file -p $id
的方式来看到:
1 | # git cat-file -p 698281bc680d1995c5f4caaf3359721a5a58d48d |
refrence
refrence是指向commit的指针,和object的区别是,它是给人读的,而且可以移动。比如master,一般指向主分支的最近的一次commit。
1 | # refrence使用一个人类可读好记的string和object的SHA-1 hash串关联 |
除了上述master,git中还使用HEAD
表示当前所在的snapshot。
仓库
git的仓库就是objects和references的集合。使用git命令就是在DAG中更改object,并更新reference。
Git 常用命令
先介绍一个很好的git教程和参考资料:pro git
入门命令
1 | git help <command>: get help for a git command |
分支管理
1 | git branch: shows branches |
和远程仓库交互
1 | git remote: list remotes |
后悔药
1 | git commit --amend: edit a commit’s contents/message |
高阶用法
1 | git config: Git is highly customizable |
参考资料
- pro git,强推,前1-5章必看
- git for cs scientists,上述git data model的可视化解释
- oh shit git,一些git常见误操作的补救方法
- learning git,一个交互式学习git操作的网站