版本控制系统 - version control system - git

几乎每个开发者每天都在用版本控制系统,那么为什么我们要用它呢?
为什么需要版本控制系统(VCS)
最基本最重要的原因当然是版本回复reversion。随着开发,代码不断地在演化。如果你在写代码的时候发现一秒钟前错误的删除了一行代码,你会很快的用ctrl+z来撤销修改,从而回复你错删的代码。但是如果你经过一个小时的努力,改了很多的代码文件,你发现这个修改是不可行的,需要倒退回去,你改怎么办?有人有比较好的习惯,当认为目前有里程碑意义的时候就把代码全备份,如果后面发现想倒退回来的时候就删除修改后的,重新启用之前备份的。这样可以解决一些问题,但是这是手工的,很麻烦。只要是麻烦的事情都会容易让你懒于去做。如果有可以工具,让你很方便的退回到以前的某个时候的代码状态,是不是很好?这就是版本控制系统要解决的问题。
还有一个重要的原因就是变更跟踪。如果你手工备份,是不是也得写一个readme文件,说明为什么要修改。如果是多人协同开发,你还想知道是谁修改的。如果有一个工具可以帮你自动维护这些信息,让你很容易达到目的,何乐而不为呢?
还有一个重要的原因就是bug跟踪。如果你在一个稳定的版本上做了修改,发布以后发现有bug了。你首先想到的肯定是你修改导致的,如果你能快速的找到你的修改点,是不是很容易定位错误。还有另一种情况,在发现bug的时候你的代码又前进了很多,你要想重现bug是不是要利用之前的哪一个版本来测试?

综合这些问题,我们需要一个版本控制系统来:
1. 维护代码的演化历史
2. 记录历史变化的原因和说明
3. 如果是多人开发,就会发生多人修改同一个文件的可能,还得保证彼此不会覆盖他人的代码,甚至能智能地合同。

版本控制系统 - 基本概念
1. Atomic operations - 原子操作
当你向VCS提交一些变更的时候,要么全部提交成功,要么全部提交失败。这样可以保证系统的一致性。试想如果只是成功提交了一部分,很可能导致整个系统因为缺失部分没有提交上来的文件而出错。并不是所有的VCS都有这个功能,CVS就没有。SVN和Git就有。

2. File locking - 文件加锁
如果你在修改一个文件,你希望别人不要同时修改,不然就会冲突。所以你需要在这个文件上加锁,告诉别人我在修改,你先别动。等你修改好了,你提交了,释放了锁,别人才能接着修改。但这样会导致一些问题,如果你一直加锁,别人也想修改,不然就做不下去,那么别人就得等待。这样就会影响效率。如果你全球性的开发就更是问题,特别是你睡觉前忘了解锁,别人就一天不能干活了。如果不加锁就得解决合并的问题,也就是帮你们把多个人的修改合并到一起。

3. Version merging - 版本合并
如果允许多人同时修改一个文件,比如svn和git,就得解决合并问题。如果多个人都在修改一个文件,第一个人提交的时候当然没有问题。第二个人提交的时候系统就要求他手工合并,这对于一般的文本文件来说相对容易,尤其是如果你们修改的不是同一行,一秒钟就合并好了。如果修改了同一行,你得当心,不要再合并的时候破坏了别人的修改从而导致系统一致性受到破坏。如果是图片等二进制文件的合并就更加困难。这个也能体现vcs的功能的强大。还有协同开发模式的优劣。

4. Baselines, labels and tags - 基线和标签
工作中的提交是频繁的,琐碎的。但是当你认为当前的版本是一个里程碑行的稳定版本的时候,或者是一次release的时候你就需要价格标签,说明他的重要性,以便今后快速的退回到这里。

5. Truncks & Branches - 主干与分支
分支可以看做是一条代码演化路径,也是开发路径。"branch head"就是指该branch的最新commit。下图中的Branch A和B就是分别指向了着两个branch的头。master指向了主干上的head。
         o--o--o <-- Branch A
        /
 o--o--o <-- master
        \
         o--o--o <-- Branch B


基本上很多人一起开发的时候大家都是共同基于一份代码库,修改的也是一份。这就是主干Truncks。但是如果这种事情发生了:你发布的系统出了问题bug,需要测试修改bug。同事主干上正在进行大规模的架构重构和升级,这两方面的工作有冲突,必须只能做一件。这时候你可以从主干里面拉出一个分支,让维护人员去修改bug,从而发布,这些修改不会提交到主干。在主干上主力人员还可以继续修改,互不影响。

6. Distributed revision control - 分布式代码控制
传统的vcs,代码库是集中式的,所有人都从一个地方下载代码,并提交到这里。git是一种分布式的代码库管理方式。分布式的代码库是基于点对点的复制和交换,这样更快。

分布式版本控制系统 - Git
1. 下载安装msysgit, 在Windows上运行的git开源项目
2. 打开git-cmd.bat, 创建一个目录,建立一个版本库git-repository\depot
D:\git-repository>cd depot
D:\git-repository\depot>git init

3. 如果你的项目已经开始,就把项目copy到depot,然后添加:
D:\git-repository\depot>git add .
D:\git-repository\depot>git commit

你会被要求输入comments,不然就不会被提交。Comments很重要,它反映了版本变更的历史描述。可以用git show来查看Comments历史。它会显示谁最后修改了代码,改了什么,为什么修改。而且每个comment还有一个40位的十六进制数字id("object name" or the "SHA-1 id")。除了第一个comment以外,后面的comment还有父comment,这样可以一直追溯到第一个comment。通过gitk命令,可以在一个GUI上看到清晰的comment继承结构。
你commit的时候git会开一个vim让你输入comments,我们一般希望comments最好一句话就能表达清楚。这样你就可以通过加入 -m 的参数来直接在commit的时候输入:
git commit -m 'Your comments'

你可以在repository下面的.git/config文件里面添加下面的code来告诉git你是谁:
[user]
        name = Your Name Comes Here
        email = [email protected]

这样git就能在你commit的时候带上你的信息。


4. Clone, 如果自己在本地工作,你就可以clone本地的repository, 在你的workspace执行:
D:\workspace\git clone D:\git-repository\depot

引用

Git支持5种协议:本地目录,SSH服务,GIT服务,Rsync,HTTP。


5. Checkout, 你可以通过 "git check .",来下载最新的代码
6. log, 你可以通过git log来查看commit历史
7. tag, 你可以通过git tag来创建tag
git tag stable-1 1b2e1d63ff

stable-1是tag名字,1b2e1d63ff是对应的commit的id的前几位。
通过下面的code就可以查看所有的tag:
git tag


8. commit, 在commit之前你要通过add来告诉git你要commit的内容,git会通过“the index”来cache这些变化。在commit之前你可以通过"git diff --cached"来预览你的要commit的修改。然后你可以通过"git commit"来提交你的变化。
   当然,如果你预览以后,想undo某个文件的修改,可以用“git rm path/to/file”。这其实也是从index中移除这个变化。
   那么,在你使用add把你的修改加入到index之前,你也可以用“git diff”来比较你要加入到index里面的变更。
   也即是git在你的working code和repository之间提供了一个cache层,你要先add到这个cache里面,然后再提交,也只有这样,才能做到原子级别的提交啊。也就是把你的变更先cache起来,然后一次原子性地提交出去。
   最后,如果你嫌麻烦,而且对自己的修改又很有信心,而且不需要打包原子性提交,你可以通过"git commit -a"来省略add这一步,直接把你的变化提交出去。但我觉得这样不推荐。
  
9. ignore,项目中总是有一些文件不需要共享,不需要vcs管理的,比如classpath,每个开发者都可以有自己的一份。不用和别人一致。那你就可以在.git/ignore里面加上你要跳过的那些文件:

.bundle
db/*.sqlite3
log/*.log
tmp/


10. status, 你可以查看当前的状态,看看你在哪个分支上,看看有没有要提交的:
git status


Git 概念总结
1. repository
因为没有一个集中式的repository,那么每一个人都有自己的一个repository。

2. branch
和一般的分支没有什么区别,每个分支都是一个开发演化路径,也就是由一系列的commit构成的。每个commit都对应这个项目的一个snapshot。可以通过“git branch”来查看当前的分支。

3. head
既然分支是由一系列的commit构成的,那么最近的一个commit对应的那个snapshot就是这个分支的head。

4. master
master就是主干分支。

5. clone
既然每个人都有一个,当你想在一个已有的repository上继续工作的话,你就可以clone一个。刚刚clone的repository就源repository的master的head。

6. remote-tracking branches
虽然clone的时候只是copy了master的head,但是也有对源repository上其他的分支的track。那就是remote-tracking branches。你可以通过“git branch -r”来查看。

猜你喜欢

转载自jackycheng2007.iteye.com/blog/983805