版本控制6(译文)(连载)

译:只是路过
 

Chapter 6: History

第六章:历史

This is part of an online book called Source Control HOWTO, a best practices guide on source control, version control, and configuration management.

这是一篇名为如何做源码控制的在线书籍的一部分,一本关于源码控制、版本控制、配置管理的最佳实践手册。

Confronting your past

对抗你的过去

You may now be tired of hearing me say it, but I will say it again:  Your repository contains every version of everything which has ever been checked in to the repository.  This is a Good Thing.  We sleep better at night because we know that our efforts are always additive, never subtractive.  Nothing is ever lost.  As the team regularly checks in more stuff, the complete historical record is preserved, just in case we ever need it.

你可能都不想再听了,但我还是要说:你的库包含了你签入的所有的文件的版本。这是一个好事情。就像我们可以睡得更香,因为我们知道我们的努力是在被做加法而不是在递减。没有东西丢失。因为团队常规的签入了更多的材料,完整地历史记录被保留了下来,以防万一我们哪天会用到。

But this feature is also a Bad Thing.  It turns out that keeping absolutely everything isn't all that useful if you can't find anything later. 

但是这个特性又是一个坏事情。它表现出如果你之后不能找到任何东西,完全的保留任何事情就变得并不是那么有用。

My woodshop is a painfully vivid illustration of this problem.  I have a habit of never throwing anything away.  When I build a piece of furniture, I save every scrap of wood, telling myself that I might need it someday.  I keep every screw, nail, bolt or nut, just in case I ever need it.  But I don't organize these things very well.  So when the time comes that I need something, I usually can't find it.  I'm not necessarily proud of this confession, but my workshop stands as an expression of who I am.  Those who love me sometimes find my habits to be endearing.

我的森林就是说明这个问题痛苦又鲜明的示例。我有个习惯,不扔弃任何东西。当我打造一个家具,我会保留所有的碎片,我总告诉自己可能总有天会用到他们。我还保留我可能会用到的螺丝、钉子、门栓、螺帽等,仅仅为了某天可能用到它们。但是我没有把这些东西很好的整理。所以当我需要用什么东西的时候,我通常还是找不到。我没有必要为这种坦白骄傲,但是我的立场表达了我是怎样的人。爱我的那些人们发现我的习惯是很可爱的。

But there is nothing endearing about a development team that can't find something when they need it.  A good SCM tool must do more than just keep every version of everything.  It must also provide ways of searching and viewing and sorting and organizing and finding all that stuff.

但是对一个开发团队而言在需要的时候找不到东西就不可爱了。一个好的配置管理工具必须做出更多事情来保持所有文件的任何版本。它需要提供搜索和查看、分类、组织、查找所有资料的方式。

In the rest of this chapter, I will discuss several mechanisms that SCM tools provide to help make the historical data more useful.

在余下的章节,我将讨论机制配置管理工具提供的机制来帮助使历史的数据更有用。

Labels

标签

Perhaps the most important feature for dealing with old versions is the notion of a "label".  In CVS, this feature is called a "tag".  By either name, the concept is the same -- labels offer the ability to associate a name with a specific version of something in the repository.  A label assigns a meaningful symbolic name to a snapshot of your code so you can later find that snapshot more easily.

可能处理旧版本的最重要的特性是“标签”的概念。在CVS里面,这个特性被称为“标记”。对于其他的名称,概念都是相同的--标签提供了在库里面为特定版本指定名字的能力。一个标签指派了一个有象征性意义的名字给代码的快照,你可以之后方便的找到这个快照。

This is not altogether different from the descriptive and memorable names we use for variables and constants in our code.  Which of the following two lines of code is easier to understand?

描述和记忆名字不是完全不同于的我们在代码中使用变量和常量。以下的代码哪一行更容易理解呢?

if (errorcode == ERR_FILE_NOT_FOUND)
if (e == -43)

 

Similarly, which of the following is a more intuitive description of a specific version of your code?

同样的。哪一个更直观描述你的代码的特别版本。

LAST_VERSION_BEFORE_COREY_FOULED_EVERYTHING_UP

378

 

We create (or "apply") a label by specifying a few things:

我们通过指定一点事情来创建(或“应用”)一个标签:

1.      The string for the name of the label.  This should be something descriptive that you can either remember or recognize later.   Don't be afraid to put enough information in the name of the label.  Note that CVS has strict rules for the syntax of a tag name (must start with a letter, no spaces, almost no punctation allowed).  I still follow that tradition even though Vault is more liberal.

2.      The folder to which the label will be applied.  (You can apply a label or tag to a single file if you want, but why?  Like most source control operations, labels are most useful when applied recursively to a whole folder.)

3.      Which versions of everything should be included in the snapshot.  Often this is implicitly understood to be the latest version, but your SCM tool will almost certainly allow you to label something in the past.  If it won't, take it out back and shoot it.

4.      A comment explaining the label.  This is optional, and not all SCM tools support it, (CVS doesn't), but a comment can be handy when you want to explain more than might be appropriate to say in the name of the label.  This is particularly handy if your team has strict rules for the syntax of label (V1.3.2.1426.prod) which prevent you from putting in other information you need.  

1.        标签的名字字串。这应该是用来描述你可以以后记住和识别的东西。不要担心在标签名字中放入充足的信息。注意,CVS对标签的语法有严格的规则(必须以字母开始,不能有空格,甚至不允许有点)。我仍然保留了那个传统,尽管Vault更自由些。

2.        标签应用到那个目录.(你可以为一个你必要的文件应用一个标签或标记,但是为什么呢?就像很多源码控制操作,标签递归应用到一整个目录更有用的多。)

3.        文件的哪个版本需要包含在快照中。通常隐含的理解是最近的版本,但是配置管理工具也几乎都允许你为过去的版本定义标签。如果不可以,扔它出去并枪击它。

4.        标签的注释。这是可选的,不是所有的工具都支持,(CVS就不支持),但是当你打算更多的在标签名字中恰当的描述的时候,注释就很容易被获得了。如果你的团队对标签有一个严格的规则(V1.3.2.1426.prod),阻止放入其他你需要的信息的显著有效的。

For example, in the following screen dump from Vault, I am labeling version 155 of the folder $/src/sgd/libsgdcore:

例如:下面是Vault的一个截图,我为目录$/src/sgd/libsgdcore版本155进行了标签。

It is worth clarifying here that labels play a slightly different role in some SCM tools.  In Subversion or Vault, folders have version numbers.  Using the example from my screen dump above, the folder $/src/sgd/libsgdcore is at version 155.  Each of the various files inside that folder has its own version number, but every time one of those files changes, the version number of the folder is increased by one as well.  So the version number of a folder is a little bit like a label because it maps to a specific snapshot of the contents of the folder.

有必要澄清的是标签在配置管理工具里扮演了一个有点不同的角色。在SubversionVault里面,目录都有版本号。我上面的截图里面的例子,目录$/src/sgd/libsgdcore就是在版本155。在那个目录中的每个不同的文件都有自己的版本号,但是当每次那些文件中的一个发生变化时,目录的版本号就会同那一个文件一样增加。所以,目录的版本号就有点类似一个标签了,因为它为目录中的内容绘制了特定的快照。

However, CVS doesn't work this way.  There is no folder version number which can be mapped to a specific snapshot of the contents of that folder.  For this reason, tags are all the more important in CVS, since there is no other way to easily mark specific versions of multiple items as a snapshot.

然而,CVS不是这样的工作方式。为目录中的内容绘制的特定的快照没有目录版本号。基于这个原因,标记对CVS更为重要,因为它没有其他的方式简单的标示多文件的时候特定的版本为一个快照。

When to use a label

什么时候使用标签

Labels are cheap.  They don't consume a lot of resources.  Your SCM tool won't slow down if you use lots of them.  Having more labels does not increase your responsibilities.  So you can use them as often as you like.  The following situations are examples of when you might want to use a label:

标签是便宜的。他们不需要耗费很多资源,你的配置管理工具不会因为使用它而速度减慢。拥有更多的标签不会增加你的责任。当你可以想使用他们就可以使用。下面的情况就是你想用标签的例子。

When you make a release

当你做了一个发布

A release is the most obvious time to apply a label.  When you release a version of your application to customers, it can be very important to later know exactly which version of the code was released.

一个发布是应用一个标签的相当明显的时机。当你为你的客户发布你的应用程序的一个版本,它对之后准确的知道发布的哪个版本相当重要。

When something is about to change

当什么文件将要变更的时候

Sometimes it is necessary to make a change which is widespread or fundamental.  Before destabilizing your code, you may want to apply a label so you can easily find the version just before things started getting messed up.

有时做一个广泛的或基础的变更是必需的。在你构建你的代码之前,你可能想要应用一个标签,那你可以恰好简单的找到这个变得糟糕的版本的前一个版本。

When you do an automated build

当你做一个自动构建的时候

Some automated build systems apply a label every time a build is done.  The usual approach is to first apply the label and then do a "get by label" operation to retrieve the code to be used for the build.  Using one of these tools can result in an awful lot of labels, but I still like the idea.  It eliminates the guesswork of trying to figure out exactly which code was in the build.

有的自动构建系统每构建一次就应用一个标签。通常的方式是先应用一个标签然后做一个“通过标签获取”操作来获取用于构建的代码。使用这些工具当中的一个都会生成可怕数量的标签,但是我仍然喜欢这个创意。这消除了推断用于构建的代码的臆测工作。

When you move some changes from one place to another

当你将变更从一个地方移动到另一个地方

Labels are handy ways to mark the sync points between two branches or two copies of the same tree.  For example, suppose your company has two groups with separate source control systems.  Group A has a library called SuperDuperNeatoUtilityLib.  Group B uses this library as well, but they keep their own copy in the their own source control repository.  Every so often, they login into Group A's repository and see if there are any bug fixes they want to migrate into their own copy.  By applying a label to Group A's repository, they can more easily remember the latest point at which their two versions were in sync.

标签是在两个分支或同一棵树的相同拷贝之间标记同步点的便利的方法。例如,假设你的公司有两个组用分离的源码控制系统。A组有一个库叫做SuperDuperNeatoUtilityLibB组最好也使用这个库,但是他们在他们自己代码库中维护了一个他们自己的拷贝。常常,他们登录到A组的库,看是不是有他们想移植到他们自己的拷贝中的关于错误的修复。通过在A组应用一个标签,他们可以更简单的记得他们在两个版本间同步前最近的那个点。

 

Best Practice: Use labels often

最佳实践:经常使用标签
Labels are very lightweight. Don't hesitate to use them as often as you want.

标签是相当轻量级的。每当你需要的时候不要讨厌去使用他们。

Once you have a label, the question is what you can do with it.  The truth is that some labels never get used.  That's okay.  Like I said, they're cheap. 

一旦你有了一个标签,这个问题就是你可以对它做什么。真相是有一些标签从来没有被使用过。好的,我爱说,他们是便宜的。

But many labels do get used.  The "get by label" operation is the most common way that a label comes in handy.  By specifying a label as the version you want to retrieve, you can get a copy of every file exactly as it was when the label was created.

但是还是很多标签被使用。“通过标签获取”操作是标签变得垂手可得的最普通的方式。通过为你想获得的版本指定一个标签,你就能够在标签创建的时刻准确取得每个文件的拷贝。

It's also very handy to diff against a label.  For example, in the following screendump from Vault, I am asking to see all the differences between the contents of my working folder and the contents of the label named "Build 3.0.0.2752".  (This label was applied by our automated build system when it made build 2752.)

反向的比较一个标签也很容易做到。例如,在下面Vault的截图中,我被要求看所有我的工作目录的内容和名为"Build 3.0.0.2752"的标签的内容之间的差别。(这个标签是被自动构建系统在2752次构建的时候应用的。)

Admonishments on the evils of "Label Promotion"

“标签升级”上的迫害进行警告

Sometimes after you apply a label you realize that you want to make a small change.  As an example, consider the following scenario:  One week ago, you finalized the code for the 4.0 release of your product.  You applied a label to the tree, and your team has proceeded with development on a few post-4.0 tasks.   

有时候,你刚刚应用了一个标签你就想做一个小的变更。一个例子,考虑下面的场景:一个星期之前,你把你产品的4.0发布终于定下来了。你应用了一个标签到树上,然后你的团队在4.0之后继续开发。

But now Bob (one of your QA guys) comes crawling into your office.  His clothes are torn and his face is covered with soot.  While gasping for air he informs you that he has found a potential showstopper bug in the 4.0 release candidate.  Apparently if you are running your app on the Elbonian version of Windows NT 3.5 with the time zone set to Pacific Standard Time and you enter a page margin size of 57 inches while printing a 42 page document on a Sunday morning before 9am, the whole machine locks up.  In fact, if you don't quickly kill the app, the computer will soon burst into flame. 

但是,现在BOB(你团队的质量保证的那个家伙)迈进你的办公室。他的衣服破破烂烂的,脸上还有灰。一边喘气一边告诉你他发现了一个4.0发布办里潜在的重大缺陷。很显然,如果你正在运行你的应用程序,是基于WindowsNT3.5的阿尔波尼亚版本,时间区是设置的太平洋标准时间,然后你录入一页页边空白57英寸的文档,一边打印一个42页的文档,在星期天早上9点前,整个机器被锁死了。事实上,如果你不快速的干掉这个程序,计算机就会很快死掉。

As Bob finishes explaining the situation, a developer walks in and announces that he has already found the fix for this bug, and it affects only one line of code in FOO.CPP.  Should he make the fix and generate a new release candidate?

BOB完成了对这些情况的解释,一个开发人员走进来宣布他已经找到了这个缺陷的修复办法,它只影响了代码FOO.CPP中的一行。他需要进行这个修复并且生成一个新的候选发布版吗?

After scolding Bob for not being more diligent in finding this bug sooner, you begrudgingly decide that the severity of this bug does indeed make it a showstopper for the 4.0 release.  But how to proceed?  The label for the 4.0 build has already been applied.  You want a new release candidate which contains exactly the contents of the 4.0 label plus this one-line change.  None of the other stuff which has been checkin in during the past week should be included.

在责备完BOB没有努力的早些找出这个缺陷之后,你小心的决定这个缺陷的严重程度需要中断4.0的发布。但是怎样进行?4.0构建的标签已经被应用了。你希望一个新的待发布的包含了4.0的内容又插入了这一行的变更。其他的员工在上周签入的内容不需要包括进去。

I'm sure it was this very situation which prompted Microsoft to implement a feature in SourceSafe 6.0 called "label promotion".  The idea is that a minor change to a label can be made after it was originally created.  Returning to our example, let's suppose that the 4.0 label contained version 6 of FOO.CPP.  So now we would make the one-line change and check it in, resulting in version 7 of that file.  Then we "promote" version 7 of the file to be included in the 4.0 label, instead of version 6.

我确信这个是提醒微软在SourceSafe 6.0中执行称为“标签升级”的特性的真实案例。这个主意是对标签一个小变更,标签在被初始创建之后还可以生成。回到我们的例子,我们假设4.0标签包含了FOO.CPP的版本6。那我们就要做一个一行的变更并且签入到库中,生成了文件的版本7。那我们“提升”文件的版本74.0标签,取代版本6

Best Practice: Avoid using label promotion
最佳实践:避免使用标签升级
Your repository should contain an accurate reflection of what really happened.  Don't use label promotion. If you must, do at least try to feel guilty about it.

你的库应该包含一个关于真正发生了什么的映像。不要使用标签升级。如果你必需那样,至少要带点负罪感的去做。

Personally I think "label promotion" is a terrible name for this feature.  In fact, I think label promotion is a terrible feature.  I am doctrinally opposed to any SCM feature which allows the user to alter the historical record.  The history of the repository should be a complete record of what really happened.  If we use label promotion in this situation, there will be no record of the fact that the original 4.0 release candidate actually contained version 6 of that file.  In situations where label promotion seems necessary, a fanatical purist like me would just create a new branch, which is a topic I will discuss in the next chapter.

私下里我认为“标签升级”是这个特性的一个可怕的名字。事实上,我认为标签升级是一个可怕的特性。我学术性的反对任何的配置管理的特性允许用户变更历史记录。库的历史应该完整记录什么真正发生过的。如果我们在这种情况下使用标签升级,他们将不会记录4.0发布版真正包含过版本6的事实。在标签升级看来很重要的情况,一个狂热的纯粹主义者希望我创建一个新的分支,我会在下一章讨论这个主题。

However, even though I dislike this feature for philosophical reasons, customers really want it.  Here at SourceGear, I tell people that "the customer is not always right, but the customer is always the customer".  So in order to remain true to our goal of making Vault a painless transition from SourceSafe, we implemented label promotion.  But that doesn't mean I have to be happy about it.

然而,尽管基于学术的原因我不喜欢这个特性,用户却需要它。在SourceGear,我告诉人们“用户不总是对的,但是用户始终是用户”。为了保留我们的真实目的,为Vault生成了一个从SourceSafe的无痛的转换,我们执行标签升级。但是那不意味着我必须喜欢它。

History

历史

Another important feature is the ability to view and browse historical versions of the repository.  In its simplest form, this can be just a list of changes with the following information about each change:

其他重要的特性是查看和浏览库的历史版本的能力。作为非常简单的形式,其可以列出关于每个变更的变更信息。

  • What was changed
  • When the change was made
  • Who did it
  • Why (the comment entered at checkin time)
  • 什么发生了变化
  • 什么时候做变更
  • 谁来做变更
  • 为什么(签入的时间录入的内容)

But without a way of filtering and sorting this information, using history is like trying to take a drink from a fire hose.  Fortunately, most SCM tools provide plenty of flexibility in helping you see the data you need.

但是没有一个方式来过滤和分类这个信息,使用历史就像试图抱薪救火。幸运的是,许多配置管理工具在帮助你查看你需要的数据时提供了许多弹性。

In CVS, history is obtained using the 'cvs log' command.  In the Vault GUI client, we use the History Explorer.  In either case, the first way to filter history is to decide where to invoke the command.  Requesting the full history from the root folder of a repository is like the aforementioned fire hose.  Instead, invoke the command on a subfolder or even on a file.  In this way, you will only see the changes which have been made to the item you selected.

CVS里面,历史通过使用“cvs log”命令获得。在Vault客户端的图形用户界面,我们使用历史浏览器。其他情况下,第一个过滤历史的方式是决定在哪里调用这个命令。请求获取从一个库的根目录的全部历史就像上面说到的抱薪救火。取而代之的,在一个目录或者每个文件处调用这个命令。在这种方式下,你将会只是看到你选择的项已经进行过的变更。

Most SCM tools provide other ways of filtering history information as well:

很多配置管理工具提供了其他的方式过滤历史信息:

  • Show only changes made during a specific range of dates
  • Show only changes made by a specific user
  • Show only changes made to files of a certain extension
  • Show only changes where the checkin comment contains specific words
  • 显示指定日期范围发生的变更
  • 显示指定用户进行的变更
  • 显示某一个特定扩展名的类型的文件发生的变更
  • 显示签入的注释内容包含了指定的文字的变更

The following screendump from Vault shows all the changes I made to one of the Vault libraries during October 2004:

下面这个Vault的截图就显示了所有我在200410月之间在库中做的变更。

Best Practice: Do as I say, not as I do
最佳实践:照我说的做,而不是照我做的做
It is while using the history features of an SCM tool that we notice what a lousy job our developers do on their checkin comments. Please, make your checkin comments as complete as possible. The screen dump above contains an example of checkin comments written by a slacker who was in too much of a hurry.

在使用一个配置管理工具的历史特性的时候,我们发现我们的开发人员在他们签入注释中做了很恶心的工作。拜托啦,尽可能的注释完整你的注释。上面的这个截图就包含了一个签入注释的例子,一个懒鬼匆忙的写下了它。

Sometimes the history features of your SCM tool are used merely to figure out what happened in the past, but often we need to dig even deeper. Perhaps we want to retrieve ("get") an old version? Perhaps we want to diff against an old version, or diff two old versions against each other? We may want to apply a label to a version that happened in the past. We may even want to use an old version as the starting point for a new branch. Good SCM tools make all of these things easy to do.

有的时候,配置管理工具的历史特性只是用于描绘出过去发生了什么,但是通常我们需要挖出更深的原因。可能我们想获得(“get”命令)一个旧版本?可能我们想同一个旧版本进行差异比对,或者在两个旧版本间进行差异比对。我们可能甚至希望用一个旧版本作为一个新分支的起始点。好的源码控制工具可以轻松的做这些事情。

A word about changesets and history

一个关于变更集合和历史的词

For tools like Subversion and Vault which support atomic transactions and changesets, history can be slightly different.  Because changesets are a grouping of individual changes, history is no longer just a flat list of individuals changes, but rather, can now be viewed as a hierarchy which is two levels deep.

SubversionVault这两个工具,在支持原子事务、变更、历史上都有些微的不同。因为变更集合是一组分离的变更,而历史不再是一系列分离的变更,但是却可以被作为有两级深度的层级来查看。

To ease the transition for SourceSafe users, Vault allows history to be viewed either way.  You can ask Vault's History Explorer to display individual changes.  Or, you can ask to see a list of changesets, each of which can be expanded to see the individual changes contained inside it.  Personally, I prefer the changeset-oriented view.  I like the mindset of thinking about the history of my repository in terms of groups of related changes.

为了使SourceSafe的用户轻易的转变,Vault允许了查看历史的任何方式。你可以要求Vault的历史查看器显示分离的变更。或者,你可以要求查看变更的列表,可以被扩展开来查看里面包含的分离的变更。私下里,我喜欢以变更集合为导向的查看方式。我有喜欢我的库的历史是依据相近的变化成组排序的倾向。

Blame

过失

Vault has a feature which can produce an HTML view of a file with each line annotated with information about the last person who changed that line.  We call this feature "Blame".  For example, the following screen dump shows the Blame output for the source code to the Vault command line client:

Vault有一个特性,可以生成一个HTML格式的文件,显示上一个变更了这行的人所做的注释。我们称这个特性为“过失”。例如,下面的截图显示了Vault命令行客户端上源码的过失的输出:

This poor function has had all kinds of people stomping through it.  I was the last person to change line 828, which I apparently did in revision 106 of the file.  However, line 829 was last modified by Jeff, and line 830 belongs to Dan.

这可怜的功能让所有的人都践踏过它。我就是变更过第228行的上一个人,我很显然是在这个文件的版本106进行的变更。当然,第829行是Jeff修改的,830行是Dan

Best Practice: Don't actually use the blame feature to be harsh with people about their mistakes.
最佳实践:不要真的用过失特性来使人们的过失那么醒目
Even though this Best Practice box is more about team management than source control, I don't feel like I'm straying too far off topic to offer the following tidbit:
尽管最佳实践框是比源码控制更多的针对团队管理的,我没有感觉到提出下面的提示偏离主题太远:
Tim Krauskopf, an early mentor of mine, said many wise things to me, including the following piece of management advice which I have never forgotten:
Tim Krauskopf
,我早前的一个好友,告诉了我很多睿智的事情,包括下面的我从未忘记的管理建议:
"Spend more time on credit than on blame, and don't spend very much time on either one."

“拿出更多的时间去相信而不是责备,然后不要花太多时间在任何一个上面”。

By now the reason for the silly-sounding name of this feature should be obvious.  If I find a bug on line 832, the Blame feature makes it easy for me to see that it must be Dan's fault!

但是现在,这个特性的名字听来愚蠢的原因是显然的。如果我在182行找到了一个缺陷,过失特性对我而言就会简单的看成是Dan的失误。

Note that we here at SourceGear take absolutely no credit or blame for the name of this command.  We took our inspiration for this feature from the blame feature found in the CVS world, popularized by the Bonsai tool from the Mozilla project.  The following screen dump shows this CVS Blame feature in action using the Bonsai installation on www.abisource.com.  I was delighted to discover that the AbiWord layout engine actually still contains some of my code:

注意:在SourceGear,我们显然没有给出信任或过失这个命令。我们通过在CVS世界里寻找到的过失特性获得了灵感,在Mozilla的项目中的Bonsai工具进行普及。下面截图就显示了CVS的过失特性,

www.abisource.com网站对Bonsai安装就可以体现。我欣喜地发现AbiWord显示的引擎真的包含了我的代码:

Whether you like the name or not, the Blame feature can be awfully handy sometimes.

不管是你是否喜欢这个名字,过失特性有时能非常便利。

Looking ahead

前瞻

In the next chapter, we'll start talking about branches.

 下一章节,我们将开始讨论分支。

 

原文地址:https://www.cnblogs.com/margiex/p/314112.html