文档结构  
翻译进度:已翻译     翻译赏金:0 元 (?)    ¥ 我要打赏

我对于源代码管理总是有种既爱又恨的感觉。

在我的软件开发生涯中,我很快就了解到,无论是爱还是恨,必须得明白你对源代码管理的态度,这是作为一个编程者相当重要的一部分。

当时我正在HP跟另外一个开发者一起参与一个小的项目。

我们在编写一个程序用于自动化测试HP打印机,这个程序叫做AntEater。

一个美丽的清晨,我准备开始高高兴兴写代码,而且考虑到我需要先获取最新的源代码才开始工作。

我一直在为一个新功能编写一个文件,而我的同事Brian则刚刚提交了一些变更。

第 1 段(可获 1.51 积分)

我可不想在过时的代码基础上工作,于是就把最新的代码从服务器上拉了下来。

我构建了应用,然后运行了一下,以确保所有都正常工作。

应用启动起来了,但是奇怪的事情却发生了。

硬盘灯在不断的闪烁。

我可以听到机械硬盘正在努力工作的呼呼声。 

它应该是在做什么事情,但是是什么呢?

没过多久,一个错误对话框弹出来了,接着就是可怕的蓝屏,昭示着死亡的降临。

我的PC自动重启了,然后就收到了写着“系统磁盘未发生错误”的欢迎消息。

第 2 段(可获 1.23 积分)

呃,好吧。这通常意味着你的硬盘可能报废了。

我联系了IT部门。

我们检查了下我的系统,证实了我的系统确实出问题了。也许硬盘已经损坏了。

他们重新组装了我的机器,第二天我就有了一个全新的Windows系统。

我花了一整天时间来重装并重新配置我的开发环境。

终于,一切事情都重回正轨了。接着我就下载了我的应用的最新的源代码,也就是包含了我自己所提交的变动的分支上的源码,然后运行了这个应用。

又一次,我的硬盘灯开始不停地闪烁起来。

第 3 段(可获 1.24 积分)

我试图中止,但是已为时太晚了。

几秒钟后,系统重启并出现了熟悉的消息:“非系统磁盘错误”。

搞什么鬼?

到底发生了什么?

我可以说相当生气。

终于发生在我身上。

我走到Brian的桌子旁,观察他所提交的代码变更。

他在一个C++的头文件里修改了一个变量,将其初始值改为了“C:\temp”。

他这么做是为了使他所写的一个函数能够起作用,这个函数使得应用可以在启动的时候从临时文件里进行扫描,并删除它们。

我在同一个C++头文件里也做了一个修改,但我还没来得及合并我的修改。

第 4 段(可获 1.5 积分)

因此,当我将他的最新代码拉去下来的时候,我没有得到他的那个将那个变量值设为“C:\temp”的最新的头文件,但是我却得到了那段用于扫描“临时文件位置(tempFileLocation)”并删除其中所有东西的代码。

既然我的变量没有被初始化,因此它被默认设置成了“C:\”—也就是我的电脑的根目录。

因此,每次当我启动这个程序时,它就会递归的删除我电脑里的所有文件。

源代码控制可以这么有趣。

什么是源代码控制?

源代码控制,或者有时候被称为版本控制,是用于跟踪不同版本的文件和软件项目的源代码,以及协调多个开发人员可能同时操作同一个文件集的工作的方式。

第 5 段(可获 1.63 积分)

源代码管理以及源代码管理系统有很多不同的版本和实现,但是它们都有一个共同的目标,就是帮助你最好的管理你的软件开发项目的源代码。

为什么它如此重要?

回想我当初刚开始成为一个软件开发者工作的时候,有大量的团队都没使用源代码管理。

我同时工作在多个项目上,一个数百万美元的系统的源代码被存放在一个共享网络文件夹或者是软盘上, 就这样来回传递。

由于依赖这种版本的源代码管理手段—有时被称作人工传递—而当某个人不小心删除掉那个磁盘或者共享文件夹里的内容时,因此而导致公司破产的案例鬼知道有多少。

第 6 段(可获 1.49 积分)

源代码控制是如此重要的一个主要原因是因为它能够减轻这个问题。

一个使用了源代码控制系统的团队会更少可能的“丢失”他们的代码的。

源代码控制给你提供了一个地方用于你提交你的代码,并保证它是安全的,这样它就不会被随意的删除掉,并且它允许你跟踪代码变更,这样如果你不小心删除了一部分代码或者犯了比较大的错误时,你还可以返回并修复掉它。

你是否曾经将一份文档存在你的电脑上时,为了保存多个版本而复制保存了多份,而每份文档在标题上使用不同的日期加以标注,这样如果你需要回退到某个版本的时候就可以很方便的这么做了?

第 7 段(可获 1.49 积分)

这其实是源代码控制完全可以帮助你做到的事情。

但是源代码控制并不仅仅是保证你不丢失源代码这一件事。

你只需要定期备份文件就可以避免这个问题。

源代码控制还能帮助你协调多个同时工作在代码库里同一个文件集上的开发者的工作。

如果没有源代码控制帮忙管理开发者所做的不同的修改的话,就会很容易导致开发者们互相覆盖其他人的变更,或者被迫只能等待其他人对同一个文件的编辑完成之后,他才能继续编辑。

第 8 段(可获 1.33 积分)

一个好的源代码控制系统可以允许你们同时在同一个文件上进行工作,然后可以将变更合并到一起。

源代码控制同时也解决了在同一个软件应用的源代码库的多个版本上同时工作的问题。

假设你有一个应用已经发布给了客户而它有一些bug需要解决,但同时你又开始开发一些新的功能为下一个版本做准备,而这些新功能还没有准备好。

如果能够让代码有多个版本会不会很棒呢?

第 9 段(可获 1.33 积分)

例如,其中一个版本是你当前已发布的版本,你在上面做一些bug的修复,而另外一个版本则可以是你进行新功能开发的版本。

如果你可以将进行bug修复的版本的代码应用到你的包含新功能的版本上,那会不会很棒?

源代码控制给你提供了实现这个功能的能力。

源代码控制基础

关于源代码控制有很多需要了解的—而你当然也不可能仅仅读了相关内容就变成了专家—但是你可以学习一些基本知识。

在下一部分,我将会给大家简要介绍一下源代码控制的基础知识,然后再介绍一些最常用的源代码控制的技术,这样你就可以至少理解源代码控制大体上是如何工作的。

第 10 段(可获 1.75 积分)

存储库

关于源代码控制系统的最关键的概念之一就是关于存储库的思想—它基本上就是指所有源代码存储的地方。

当你在使用源代码进行工作时,你将会从存储库获取代码,在其上进行工作,然后提交你的修改。

其他开发人员也可能同时在做同样的事情。

存储库是所有代码最终汇聚到一起的地方,也是代码在技术意义上“存活”的地方。

不同的源代码控制系统对于存储库是什么会有不同的定义,而且还有可能有本地的存储库,但是对于任何代码库,最终只有一个中央的位置或存储库作为系统的记录。

第 11 段(可获 1.48 积分)

检出代码

当你想获取一份可以修改的本地代码版本时,你就会需要从存储库检出代码。

早期的源代码控制系统实际上会让你检出代码并将文件锁定,因此只有你可以修改它们。

现在的大多数源代码控制系统在你“检出”代码时,会将代码的一份本地副本拉取到你自己的电脑里或者本地的存储库里。

这份检出的代码是你的本地副本,并且你所作的修改只是针对你本机或者本地存储库的代码。

只有当你“检入”或者将你的代码合并入中央存储库时,其他开发人员才能看到你所做的变动。

第 12 段(可获 1.54 积分)

通常情况下,当你使用源代码控制系统进行工作时,你会检出代码库的一份本地副本,实现新功能,或者做一些其他的变动,然后当你完成的时候,你就会将代码提交回去,并处理任何可能与其他开发人员同时工作在同一段代码时产生的冲突。

修订(Revisions)

源代码控制系统有一个概念叫修订,是指一个文件被源代码控制所包含的之前的版本。

例如,如果我们有个文件名叫foo.bar,是我初次创建的,而你在之后做了修改,再接着在之后的某个时间我又修改了一次,那么在源代码控制的存储库里就会包含三个不同版本的foo.bar。

第 13 段(可获 1.58 积分)

这一点为什么很重要呢?

嗯,有很多原因。

首先,假定我将foo.bar搞怀了,而你想要将它恢复至我修改之前存在的那个版本。

既然文件在源代码控制系统内,你就可以很容易回滚到之前的版本或者检出那次修订 ,然后就当我的修改从来没存在过一样。

你也可以针对一个文件查看其修订历史并对比随时间的变化,从而可以看出一个文件是如何进化的 ,即通过查看每一个修订时所发生的变化以及是由谁所做的修改。

(我比较喜欢称之为相互指责。)

第 14 段(可获 1.33 积分)

分支

源代码控制最容易被误解的一个领域是分支—或者可以说是如何正确使用分支

不过,这个概念却是相当简单的。

大多数源代码控制系统允许你在当前存在的代码库里创建一个分支,是为了创建一个新的代码基准库,从而跟它的父代码库独立开来发展。

等等,什么?我原以为你说这很简单,约翰。

好吧,试着将你的代码想成一棵树。

你已经得到了树干,而且在某种程度上你有可能有多个分支是从这个树干分出来的。

这在现实生活中看起来是什么样的?

假定你正在一个软件的一个版本上工作,而你已经准备好将那个版本提交给客户,并将它命名为版本1,但是… 你想继续为版本2进行新功能的开发。

第 15 段(可获 1.79 积分)

问题是—即使你编程水平相当高—你知道在你即将交付给客户的版本1中也会出现一些bug需要修复。

然而,你并不想在给他们进行版本1的修复时也把版本2加入的的新功能也提供给他们。(你也许正计划为之后升级到版本2时再收点钱。)

那么,你该怎么做呢?

简单。你对你的代码进行分支管理就好了。

一旦你准备好交付版本1时,你需要创建一个新的分支,而不是将位于主干的东西进行交付。你可以将此分支命名为 “版本1”。

然后你就可以在版本1的分支上进行bug修复,而在主干上面实现新功能。

第 16 段(可获 1.61 积分)

只有一个问题…

如果你想要把这些bug修复加入到主干上怎么办?

合并

解决你的问题的办法是合并。

什么是合并?你可能会问了。

它正像它表面上的意思那样。

你需要将一个代码线的变更合并到另外一个上面。

在我们上面给出的小小的软件例子中,我们仅仅使用了源代码控制系统里的一个合并的功能就将我们的版本1分支上的变更合并到了主干上。

合并分支的功能使得我们能将在版本1上所做的修改取出来,在我们从主干上创建分支之后,可以将它们再合并进主干里。

第 17 段(可获 1.44 积分)

合并只能单向进行,因此我可以将版本1分支上的所有变更合并到主干上,但是那些我们正在主干上开发的新功能并不会进入版本1的分支。

一切就如我们所想的那样。

世界上一切都很美好和安宁,直到我们真正试图进行合并时,我们才发现我们有了…

冲突

艹!MD! 这是什么狗X!

(很奇怪的是, 我在这本书里写出这些脏话完全没有问题,但是在一个句子里连续抛出以F-炸弹开始的三个“强势的”单词就有失大雅了)

第 18 段(可获 1.36 积分)

这些是开发人员在将几个简单的变更合并到主干时经常会发出的单词。

通常这会发生在每个周五下午的五点钟,当你只是想做个快速的合并然后溜之大吉时。

你启动了合并,穿上你的外套,给你的朋友发了消息,告诉他们你将会跟他们一起共度放松嗨皮吃吃喝喝的夜晚,然后快速瞥了一下屏幕,上面说:

“冲突(内容):在simplefile.java文件里发生合并冲突

自动合并失败;请修复冲突并提交结果。”

第 19 段(可获 1.38 积分)

或者有几个其他这样的垃圾。

三个小时过去了,你还在盯着文件里一堆 “<<<<<” 和 “>>>>>”一样的符号,试图将所有的都弄明白。

我不会说慌;合并分支真的是… 一个贱人。

大部分情况下,一个好的源代码控制系统会试图将文件里某一部分的简单变更自动合并到另外一个文件里,而且一切都很神奇。

但是… 时不时的,你在一个分支上的一个文件里做了一处修改,同时另外一个白痴傻蛋开发者也对同一个文件的同一行也做了一个改动—因为他是个白痴—因此就需要人工干预了。

第 20 段(可获 1.4 积分)

计算机是没办法知道其中一个修改是否应该覆盖另一个,或者如果两个变更都应该被包含在里面呢,又或者有其他方式来解决冲突呢,所以这一切完全取决于你。

你的周五晚上已经被毁了。

解决合并冲突以及错综复杂的合并可以讲出另外一整本书来,因此我在这里就不深入研究里面的细节了。

目前为止我们所知道的已经可以足够帮助我们理解合并的基本工作原理了,而当冲突出现时不得不手动解决时,请记住不要在周五晚上将要下班离去之前去做“快速的简单合并”。

第 21 段(可获 1.44 积分)

技术

源代码控制有一段相当长而且有些有趣的历史,这些我们就不在这里讨论了,因为关于有趣的部分我撒了个谎:)。

可以说源代码控制系统是从最开始通过USB设备进行传送,进化到有策略的将源代码的整个文件夹复制并重命名为V1,然后再到我们今天所拥有的相当复杂的系统。

在源代码控制的战场上发生过很多次战争,最终有两大派别获得了胜利:集中式的源代码控制和分布式的源代码控制。

集中式的比较老些。它没有那么多“金光闪闪的东西”,但是它相对来说比较容易理解并且还能够完成工作。

第 22 段(可获 1.39 积分)

CVS和Subversion是集中式源代码控制的两个例子。

分布式的是比较新的。在大部分人眼里它可能更能吸引人眼球,而且更加复杂些,但是更多的人在使用它。

Git和Mercurial是分布式源代码控制的两个例子。

集中式源代码控制

在集中式的源代码控制中,你只有一个存储库,存放在一个中央服务器上,所有的开发者需要首先获取他要工作的代码文件的副本,然后将所做的修改提交上去。

每一个开发人员都通过一个源代码控制客户端来从中央存储库检出和提交代码。

第 23 段(可获 1.36 积分)

所有版本的历史和文件的修订版本都存储在中央存储库。

使用集中式源代码控制的典型工作流程是这样的:

  1. 从中央存储过更新我在工作的代码的本地副本。
  2. 进行修改。
  3. 提交变更到中央存储库(并处理可能出现的任何冲突)。

分布式的源代码控制(DVCS)

使用分布式源代码控制的最大的不同是每个开发者都会在他们自己的机器上拥有整个存储库的完整副本。

一些非常酷的潮人喜欢说这意味着:“并没有中央存储库,伙计。就像我们都有该软件的自己的版本,没有哪个版本比其他版本更好的。”

第 24 段(可获 1.56 积分)

这完全是错误的。

没错,理论上讲,这是可能的,但是如果没有某种系统的记录,你该怎样交付代码并在不同的开发人员之间协调项目呢?

这是不会发生的。

如果你认为它会,那你真应该建立你自己的乌托邦或邪教,又或者其他什么东西。

是的,现实情况是每一个开发者都会在自己本地有一份存储库的完整拷贝,但是你仍然会利用存储库的某种中央版本来作为系统记录或者项目的主存储库。

第 25 段(可获 1.28 积分)

当你在一个分布式源代码控制系统上工作时,你这就是在本地工作,所有一切都跟使用一个集中存储系统工作一样,只是这是在本地而已。

本质上,这意味着你无需将大量文件通过网络进行传输,而且你还可以离线工作一段时间。

然而,最终你会得到其他人所作的修改,而你也可以将你自己所完成的的漂亮且珍贵的代码变更发送给整个世界让他们去欣赏。

你可以通过拉取和推送来完成这些。

有了DVCS,你可以将变更拉取到你本地的存储库,而且你可以将你所做的变更推送到主存储库或者其他任何你想要推送的存储库上—包括你的赶时髦的,且分散的,并认为“每个仓库都是平等的”的朋友。

第 26 段(可获 1.56 积分)

最常用的源代码控制系统的快速介绍

如果你是在未来的某个时间阅读本书,这个列表可能会变化。

总有新的源代码控制的新星出现而炙手可热。

但是,目前来说,即在写本书的时代,我认为我会给你简要介绍一下你可能在野外看到的最常用的源代码控制系统。

注意:只是简短的介绍。

CVS

不,它并不是一个药店。它是源代码控制。

它以CVS或者并发版本系统为名而为人所知。 (我从来没有叫过它的全名;实际上我是查字典才查出来的。)

它是什么?

嗯,我知道当我说这些时有些人会生气,但是以我的观点来看,它是Subversion的前辈。

第 27 段(可获 1.65 积分)

CVS是一个集中式的源代码控制系统,而且它相当的健壮。

它非常的强大,但是有一点慢。

大部分曾经使用CVS的组织最终都会转换使用Subversion,但是CVS仍然在处理一些东西时有一点异样,而有些人还是更喜欢这些异样的东西。

比如,打标签和分支以及回滚提交在CVS里都很不一样。

CVS狂热者会告诉你CVS做的正确,而Subversion做错了。

我并不真的关心这些,因此我只是点头,因为我不喜欢被人用叉子刺。

Subversion

第 28 段(可获 1.25 积分)

偏见预警(以下只是偏见,仅供参考)

Subversion可能是我最熟悉的源代码控制系统。

我曾经以纯粹图形化的方式关于如何使用它给人讲过课程,我也写过关于如何使用它进行分支管理和合并策略的博客文章, 并且我曾使用这项技术为相当大的开发团队管理过SVN服务器,存储库和源代码控制系统策略。

那这意味着我是一个超级SVN迷而认为其他任何东西都很烂呢?

不,并不是这样。

就集中式源代码控制系统来说,我认为Subversion是最好的,但是它肯定也有一些缺点的。

第 29 段(可获 1.21 积分)

然而,总体来说,它能使工作完成,并且非常简单易用,因此我喜欢它。

Git

Git基本上已经变成源代码控制的同义词了。

今天你去问一个不满25的开发人员什么是源代码控制,他或她 很有可能说,“什么,你是说Git吗?”

他/她会这么说是有理由的。

Git是… 嗯… 相当的棒。

真的,它就是这么棒。

就源代码控制软件来说,Git能够完成你能想到的几乎任何事情.

它极其的强大。

它的基础相当简单。

而且它快速,高效且通用。

Git甚至还有一个相当大的公司来支持开源并为Git项目提供托管服务,它叫GitHub

第 30 段(可获 1.4 积分)

如果你还不知道,绝对值得你去了解一下。

Mercurial

Mercurial有点像是Git的邪恶孪生兄弟。

有人说Git像麦吉弗,而Mercurial像詹姆斯•邦德。

我并不确切清楚他们到底说的是什么—或者他们在抽什么烟—但是我大概明白了。

Mercurial被描述得比Git更优雅和文雅

相同的基础思想—他们都是分布式的源代码控制。

相同的基本功能和特性。

但是,以我的经验来看,Mercurial只是相对来说有一点更容易使用和理解而已,而Git则有一点晦涩难懂,但是有很多方式可以将东西结合起来。

第 31 段(可获 1.45 积分)

因此,我已经从本质上通过对比Git描述了Mercurial。

嗯,也只能这样了。

如果你同时使用两者,你就会知道为什么了。

这有点像那种毫无意义的宗教战争类型一样的东西。

还有其他的吗?

没了,真的没了。

主流的源代码管理系统也就是这四种了,其中Git占用很大(相当大)的市场份额。

是的,有些人会比较另类使用其他的东西而且用着也会很开心,但是那是相当稀少的。

好了,现在你已经能够学会源代码管理的基本知识了。

记得要及早提交并时常提交。

而且,请使用有意义的提交信息。

第 32 段(可获 1.41 积分)

文章评论