原本在学校跟随导师做项目的时候,就一直在使用版本管理,主要是用来记录项目的修改,项目成员之间的沟通和交流。使用的服务端是Visual SVN,客户端是TortoiseSVN,常用的TortoiseSVN指令也仅限于SVN Update和SVN Commit,前者用来从服务器更新,以期望查看其他同学的修改,后者用来将自己的修改提交到服务器,使得团队共享修改。由于项目组中的成员比较少,主要的代码修改也只有我一人完成,因此TortoiseSVN也就沦为了记录我修改本地代码过程的工具。其实这与我平时写工作日志(word格式)、代码中添加注释(注释中一般会出现修改原因、修改者、修改时间、备注)的习惯有一些冗余。
随后进入职场,接触的项目越来越大、开发者越来越多,就慢慢开始了解TortoiseSVN的其它功能。例如查看文件修改日志Show log、回滚已提交的修改操作Revert、创建分支Branch/Tag、创建补丁Create patch等。在逐渐熟悉和使用的情况下,逐渐感觉到TortoiseSVN似乎还缺少一点什么功能?比如下述场景就经常发生:我从项目SVN服务器拷贝自己负责的代码到我的本本,然后按照项目计划开始修改自己的模块(此时就像在本地开发调试一样),但是突然临时接到上级指示,有一个紧急的Bug要处理。此时我只能先创建补丁文件(Create patch),然后将目前的修改回滚到初始状态(即我从SVN服务器拷贝时的版本),如是我才能开始修改紧急的bug。等待修补完成后,再将先前的patch文件应用回来。这里面我会同时做好相应的工作记录(word文档),这里面就会记录我初始修改模块时的相关步骤和细节,记录bug修补的过程,然后接着记录模块的修改。如此,结合TortoiseSVN的提交日志和我的word工作文档,我才能精确的定位我开发过程中的任意时刻——方便后续思路的整理和延续,如下图所示:如果每次TortoiseSVN提交的时间粒度是按照黄色箭头所示,那么中间的红色修改我只能在我的word工作日志中查看,但是word中毕竟记录的是思路,具体的代码文件我只能手动拷贝到word日志中记录的相应位置,或者创建patch文件保存到制定位置,如果TortoiseSVN提交的时间粒度是途中箭头所示,那么这与word日志的工作几乎重复,可以达到随意定位修改的目的,但是需要注意的是,在团队开发中,如此频繁的TortoiseSVN提交时绝对不可能的,一是SVN服务器要求完整的功能修改完成后才能提交,而是如此频繁的提交会增加服务器负担,也会使得自己不完整的代码模块影响整个项目的功能。
看到这里,你是不是觉得好复杂,好麻烦,但是对于码农来说,良好的记录和注释是必须的,这样你才能更好的对自己的代码负责。这种开发状态我已经坚持了多年,也习以为常了,直到某一天我接触了Git后,我才恍然发现,原来还有一种所谓的分布式版本管理工具,可以记录我的本地修改。真是令我喜大普奔。
下面介绍一下怎么利用Git来管理本地的代码修改。
关于两者的分析和讨论早已遍布各大论坛、贴吧,这里我不评价两者孰优孰劣。仅从自己实际的代码开发工作,从提高我本人代码开发效率的角度来说一下我对两者的看法。正如背景中所述,SVN的使用已有多年,简单的来说就是有一个服务器会存储你对代码的修改,这里的修改必须是你确定提交(Commit)到服务器的。对于两次提交的间隔粒度完全取决于开发者本人,如果仅仅是利用SVN来管理自己的代码开发记录,你完全可以随意提交以期望来记录自己完整的开发流程(这种方式在团队合作中是坚决不允许的)。SVN的结构分为版本库和工作副本,版本库就是放在服务端的“数据库”用来记录你每次的提交,记录的内容包括所有版本库控制范围内的文件的改动;工作副本就是你自己本机中的代码工程,它是服务器中代码工程的一个拷贝,SVN将版本库和工作副本存放在不同的位置。具体的示意图如下(自己思路的直接体现,可能不一定完全符合SVN的工作过程,但是大意是正确的,便于大家理解):
从上图可以看出,SVN版本管理的基本流程,服务端保存的是你每次对工程进行的修改,当然第一次提交时记录的就是你的初始工程文件。那么从上图SVN服务端的目录结构中我们并未直接看到我们提交的工程文件,而利用TortoiseSVN (本地服务器)和VisualSVN(远端服务器)的Repo-browse却可以看到我们具体的项目文件,如下图。那么我们提交的文件又存到哪里了呢?直观猜测的话应该是db目录下的某些文件,因为随着提交次数的增加,该文件的大小也在变化。搜索一下相关资料,找到了如下的回答:
“svn有两种存储方式:BDB和FSFS,目前用的最多的是FSFS方式,这种方式的话,一般是存储在\db\revs文件夹下,里面有一堆以版本号命名的文件,如:0、1、2、3、4......,那个就是我们的工程文件。svn先把0版本的状态压缩成1个文件,然后每次版本更新时就针对变动的部分做一个压缩文件,每次都是增加一个增量包,最后在服务器上能看到文件名为从0开始到最终版本的一系列文件”
“SVN服务器端不是简单将上传的文件一个一个存放起来的,SVN服务器端默认采用的FSFS格式是将每次commit的内容增量方式存放的,每个增量包存成1个文件,这个增量包中包括了这次commit的全部数据。也就是说你不可能在服务器端存放该版本库的文件夹下找到你上传的某个文件”。
至此我们就明白了SVN服务端的结构。至于客户端就没什么难的了。就是通过网络协议将服务端的版本库下载到本地,存储在.svn目录下,除此以外的就是自己的工程文件了(如果你是从远端SVN服务器下载的别人的工程,那么就是别人的工程文件)。.svn中记录的是你从SVN服务器下载时刻时服务器工程文件的状态,再下一次提交时刻,会与SVN服务器通讯来查看服务器和你本地两端的修改状况。
由此我们可以看出要想对本地的修改进行记录,必须要与SVN服务器进行通讯,无法只是单纯的保存本地的修改。这也是我寻求Git的主要目的。百度百科对Git的描述是:“Git是一个开源的分布式版本控制系统,用以有效、高速的处理从很小到非常大的项目版本管理。分布式和集中式的最大区别在于开发者可以本地提交。每个开发者机器上都有一个服务器的数据库。”——反正就是一句话,Git可以完成上述我想要的本地修改记录。
第一步,Git的版本库和工作副本在同一目录下,叫做.git。安装完Git后,可以直接在任意目录下单击右键,选择Git Init Here,建立Git版本库,即.git文件夹。(谨记:这是我们在本地建立的版本库,压根儿没有服务器毛关系啊,^_^。)
第二步,直接将我们需要管理的本地工程拷贝到.git同目录下。随后我们想正常开发一样打开工程进行操作即可,直到我想保存一下修改状态时,我们就可以转到第三步。
第三步,在工程文件夹中右键,选择Git Gui,会弹出管理窗口,这里会显示我们所做的修改,在红色框中列出的是我们做过修改的文件,橙色框中可以看到所做的修改。绿色框中显示的是修改的缓冲区,通过在红色框中选择指定文件进入到绿色的缓冲区后,我们可以单击黄色按钮“提交”,至此本次我们对本地文件的修改记录就已经提交了。
第四步,在工程文件夹右键,选择Git History,我们既可以看到本地的此次修改记录。
至此我们就很容易的实现了对本地代码修改的记录,而这整个过程中,根本没出现服务器。这是与SVN最大的区别。
今天就记录到这里,明天会对背景中的场景的进行详细的介绍,给出Git的解决方案。
(未完待续……)
时间:2014-09-06