本文面向初次接触版本控制系统的Git用户,旨在介绍一些关于版本控制和Git的简单概念。
文中并不涉及过多的Git实际操作,文末推荐更多的Git学习资源。
导言
Git是目前最先进的版本控制系统,拥有最多的用户数量并管理着数量庞大的实际软件项目。风靡全球的Github更是让Git版本控制系统名声大震。本文以“版本控制系统”为切入点,介绍相关概念和简单的Git用法。
什么是版本控制系统?
如果对“版本控制”没有概念,那真是没法用Git。
所以我们来看一个例子:假设大四毕业生小张在写毕业论文,写好初稿后经常删改,甚至还会在第二天把前一天删掉的东西找回来。如果他动点脑子,就不会只在一个文档中改来改去,而会在文件夹中有:
毕业论文_初稿.doc
毕业论文_修改1.doc
毕业论文_修改2.doc
毕业论文_修改3.doc
毕业论文_完整版1.doc
毕业论文_完整版2.doc
毕业论文_完整版3.doc
毕业论文_最终版1.doc
毕业论文_最终版2.doc
……
看起来是不是很郁闷啊?小张当然也郁闷了,因为自己总是改不好,所以他把自己的论文发给女朋友(是学霸),求帮忙;与此同时他自己也在继续修改。第二天就有了:
毕业论文_最终版3.doc
毕业论文_女友版1.doc
他女友毕竟是学霸,当然给他的论文做了比较大的修改,此时小张虽然看到了希望,但还要纠结着做一件事情:把上面两个版本的论文合并成:
毕业论文_死也不改版.doc
等合并好,已是凌晨三点半。小张无比怨念:这样子真是没法和女友开心的玩耍了呢!
怎么办?
小张想,如果能有个什么东西来帮忙控制一下这该死的版本,那真是谢天谢地了!就像这样:
版本 | 修改人 | 说明 | 日期 |
---|---|---|---|
初稿 | 小张 | 这是初稿 | Day1 |
修改1 | 小张 | 修改目录 | Day2 |
修改2 | 小张 | 合并段落 | Day3 |
…… | …… | …… | …… |
最终版2 | 小张 | xxx | Day7 |
死也不改版 | 女友 | balabala | Day8 |
这样就不用手动控制那么多版本啦!
所以,所谓“版本控制系统”,就是来解决这类问题的。
Git又是什么?
没错,Git就是一个版本控制软件。在进行软件开发时,一个团队的人靠使用Git,就能轻松管理好项目版本,做好项目的追踪和辅助进度控制。确切的讲,Git是一款分布式版本控制系统。这个“分布式”,要和“集中式”放在一起理解。
所谓“集中式版本控制”,就好比这一个团队中,版本库都集中在一台服务器上,每个开发者都要从服务器上获取最新的版本库后才能进行开发,开发完了再把新的版本提交回去。
而“分布式版本控制”,则是这个团队中每个人的电脑上都会有一份完整的版本库,这样,你工作的时候,就不需要联网了,因为版本库就在你自己的电脑上。既然每个人电脑上都有一个完整的版本库,那多个人如何协作呢?比方说你在自己电脑上改了文件A,你的同事也在他的电脑上改了文件A,这时,你们俩之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。
和集中式版本控制系统相比,分布式版本控制系统的安全性要高很多,因为每个人电脑里都有完整的版本库,某一个人的电脑坏掉了不要紧,随便从其他人那里复制一个就可以了。而集中式版本控制系统的中央服务器要是出了问题,所有人都没法干活了。
在实际使用分布式版本控制系统的时候,其实很少在两人之间的电脑上推送版本库的修改,因为可能你们俩不在一个局域网内,两台电脑互相访问不了,也可能今天你的同事病了,他的电脑压根没有开机。因此,分布式版本控制系统通常也有一台充当“中央服务器”的电脑,但这个服务器的作用仅仅是用来方便“交换”大家的修改,没有它大家也一样干活,只是交换修改不方便而已。
版本库是咋回事?
版本,不是文件的版本么?这个版本库是什么意思?
如果能意识到控制的是文件的版本,那就离理解版本库只差一步了(最关键的一步)。
程序要记录项目的版本号,最简单的方法就是把版本相关的信息放在某文件里,持续写入文件便视为版本更新。所以,当我们在一个目录中运行命令:
$ git init
# Git初始化的命令,用于新建版本库
这个目录中就会默认产生一个新目录:
.git/
没错,这就是我们刚刚新建的版本库,它将默认记录当前目录(直接包含.git
的这个目录,下文中叫做“项目目录”)中任何文件的改动。如果把这个版本库删除了,这里面记录的文件版本就都没有了,项目目录中的文件当前是什么样子,那就一直是什么样子,没法恢复到以前的版本了。如果想让Git忽视项目目录中的什么文件(比如程序缓存等),可以在.gitignore
中写清楚那些文件。
那么,Git怎么用?
在实际应用中,Git有非常多的用法,而本文是面向Git完全初学者,所以我们要从最基本的开始做。
比如,在刚才建好的版本库中,A新建了README文件,并在里面写了东西。写好后他想给项目做个版本,就需要这样:
$ git add README
$ git commit -m "add README"
第一个命令是告诉Git要追踪什么文件,第二个命令是进行提交,并对此次提交做个简答说明。当然,今后他再对README做什么修改,都可以这样做。Git会自动为此次提交生成一个16进制的版本号。
如果此时他查看本地的版本库,就会发现最新的一次提交是在刚才,提交说明为:add README
。
然后,他要把项目的版本库更新到Github上,当然这时候项目本身已经在Github上建立好了。他只需要:
$ git push origin master
这行命令应该这样理解:A已经在本地把项目最新的版本做好了,他要发到Github上,以便团队里其他人都能收到这个新的版本,于是他运行git push
;push的目的地是origin
,这其实是个名字,意义为该项目在Github上的地址;推送的是本地的master
分支。
这个时候,Github上项目的版本号与A本地的最新版本号一致。
分支是版本控制里面的一个概念:在项目做大了之后,如果要在原基础上进行扩展开发,最好新建一个分支,以免影响原项目的正常维护,新的分支开发结束后再与原来的项目分支合并;而在一个项目刚开始的时候,大家一般会在同一个分支下进行开发.这是一种相对安全便捷的开发方式。
此时,小组里成员B对项目其他文件做了一些更改,同样也在本地做了一次提交,然后也想推到Github上面。他运行了git push origin master
命令,结果发现提交被拒绝。这要做如何解释?
仔细想想,最开始的时候,A和B是在同一个版本号上做不同的更改,这就会分别衍生出两个不同的版本号。A先把自己的版本推到Github上,此时Github上的版本库与B本地版本库相比,差异很大,主要在于B这里没有A的版本记录,如果B这时把自己的版本强制同步到Github上,就会把A的版本覆盖掉,这就出问题了。
所以B进行了如下操作:
$ git pull
这样子,B先把Github上的版本库和自己的版本库做一个合并,这个合并的意义在于:B通过Github,把A刚才添加的版本加了进来,此时B本地的版本库是整个项目最新的,包括项目之前的版本、刚刚A添加的版本和B自己添加的版本。
这之后,B再次运行git push origin master
,成功地把自己的版本推到了Github上。如果A想要推送新的版本,也要像B之前这样折腾一番才行。
还能再给力点么?
当然可以!
这里有两个在线代码托管平台:
还有一些优秀的Git在线资料:
最后还有一本不错的中文书籍:
不过,本文就要到此为止了,因为再往下写就会涉及更多更深的Git操作实践,而这些内容在上面给出的资料中已经整理好。
最后
本文的目的在于解决身边乃至更多开发者同时入门版本控制和Git时候遇到的困惑,希望能对各位初学者起到积极的作用。
如果您有更好的意见或建议,欢迎与我讨论:)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。