Advanced CVS

做了几个月的实际项目,感觉还是只用到CVS的皮毛,CVS中的高级功能比如create tag、create branch和merge等都未使用过。Dreamhead发过来一本”pragmatic version control-using CVS”,顺便do some practice and research on the advanced functions of CVS。

1、Tags、Branches and Tagging的概念理解
Tags分为Regular tag和Branch tag两种。
Regular tag其实就是我们一般理解中的tag,而Branch tag即是我们理解中的branch。
HEAD也是一个特殊的分支,the main branch,只是我们把它默认当作main trunk。

建立分支的必要性,举个简单的例子当我们的项目对外release1.0版本后,比如我们对整个project建立version为“Release_1_0”,但是这个版本肯定有bug存在,我们就这样提交给用户使用,相信不会等多久bug report就会feedback回来。所以我们得一边做下一个版本Release_2_0的开发一边fix bug,而我们fix bug时基于的版本只能使release1.0,这时我们就要考虑难道新版本的开发和fix bug的工作都要在main trunk 上么,这样可行么?回答是“也许可行,但是不用过多久你就会发现这样会造成太多的冲突,开发人员的抱怨声也越来越多”。Branch可以帮助我们解决这个难题。我们在建立version Release_1_0的同时建立一个branch,比如叫做“Release_1_0_Branch”,并同时建立一个regular tag ”Root_of_Releas_1_0_Branch”,这个regular tag的用途是为了以后branch 合并到main trunk时提供一个参考点。之后开发新版本的人员就基于main trunk工作,而fix bug的人员就基于Release_1_0_Branch工作。一旦在Release_1_0_Branch上将Release_1_0的bug修复了,我们就可以将Release_1_0_Branch合并到main trunk中来一次性remove the bugs。上面举的这个例子只是branch较简单的一个用法。有效的利用branch会给你的项目的开发带来很多便捷的。

下面的英文段落是从某书中摘录的关于version和branch的说明。
You can use CVS to maintain different branches of a project. Doing so is often
necessary if you release a version of your project to the public, such as version 1.0.
As you begin to work on adding new features for version 2.0, the code is not stable
enough for release; so, if any serious bugs are discovered in version 1.0, they must
be made to the original 1.0 code. CVS allows you to create a separate branch,
starting with the original 1.0 code, so you can maintain this code separately from
the new development continuing with the main branch, HEAD.
//…
Versions differ from branches. A version is a snapshot of a branch at a given
point in time—in other words, it’s a particular set of file revisions.
//….
Adding a version label to a project associates the revision number of each particular
file with a single project-level label.You should consider tagging a project with a version label at all significant development milestones, such as a beta or an official release, or before any drastic
change is undertaken.

2、Merge
理解了branch的概念后,那我们如何将一个Branch合并(Merge)到main trunk or another branch呢?下面我们使用Eclipse作为工具来说明如何将branch合并到其他branch中(main trunk is also a branch , a special branch)。

在你在CVS中创建branch后一段时间,你可能要将你在branch中的changes合并到其他branch中。要想将你的branch中的changes合并到其他branch中,你首先要知道“the name of your branch”and “the version from which your branch was created”。

知道上面的两样后,我们就可以实施我们的merge了。我们以branch merge到HEAD为例。具体步骤如下:

* 目标version加载
首先将目标version 加载到你的工作区,在这个例子里我们将HEAD version加载进来,具体方法是在你工作区(可能是“Navigator view”)中,Right click your project name, choose Replace With > Another Branch or Version from the context menu. Then select the HEAD to replace with your current version in your workplace。

* 选择branch
Select the project and choose Team > Merge.
在随后出现的对话框中,你首先选择“the version from which the branch was created.”,然后在下一步中选择你的Branch。

* Synchronize view中的操作
在第二步结束后,Synchronize view中将显示“all the differences between the branch and your workspace version(that is the HEAD version)”,你必须在Synchronize view中通过菜单中提供的“Update, Override and Update, or Mark as Merged”手工决定合并到你工作区的change。

* Commit the changes
在所有期望的changes都被merge到你的工作区后,你就可以“commit”the changes to the repository了。

注:Merge actions:
Update – Running this action will bring the changes into the file in the workspace. Any conflicts that are not auto-mergable will be skipped.

Override and Update – This action is enabled on files with conflicting changes. Running this action will discard any local changes you have and replace the file with the remote contents.

Mark as Merged – This action will remove the selected changes from the view. The changes will only reappear if the remote state of the resource changes and the CVS Merge Synchronization is refreshed.

Effective Java阅读笔记-item24、25、34

Dreamhead把他用大把银子买来的“Effective Java”借给我阅读,我真是很感动亚,我只能用行动来感谢Dreamhead了。^_^

24、需要时使用保护性拷贝
在学习这个item之前我们看看下面这段“危险的”代码(改编自书中例子):

Considering the following code:
//Period.java
import java.util.Date;
public final class Period {
    private final Date start;
    private final Date end;
    public Period(Date start , Date end){
        //do some checking , end should be later than start
        this.start = start;
        this.end   = end;
    }
    public Date start(){
        return this.start;
    }
    public Date end(){
        return this.end;
    }
    //remainder omitted…
    public static void main(String[] args) {
        Date start = new Date(2004 , 11 , 28);
        Date end   = new Date(2004 , 11 , 30);
        Period p = new Period(start , end);
        
        System.out.println("Normal period:");
        System.out.println(p.start());
        System.out.println(p.end());

        //danger code part1
        System.out.println("Unnormal period part1:");
        end.setMonth(4);
        System.out.println(p.start());
        System.out.println(p.end());

        //danger code part2
        System.out.println("Unnormal period part2:");
        p.end().setMonth(5);
        System.out.println(p.start());
        System.out.println(p.end());
    }
}

//output:
Normal period:
Wed Dec 28 00:00:00 CST 3904
Fri Dec 30 00:00:00 CST 3904
Unnormal period part1:
Wed Dec 28 00:00:00 CST 3904
Mon May 30 00:00:00 CST 3904
Unnormal period part2:
Wed Dec 28 00:00:00 CST 3904
Thu Jun 30 00:00:00 CST 3904

Period类声称提供一段不可改变的时间段,不过从上面的输出结果来看我们可以轻易的修改这个时间段。为了使上面的Period类真正成为非可变类,我们需要进行“defensive copy”。

Danger code part1提示我们“对构造函数的每个可变参数进行保护性拷贝”;
Danger code part2提示我们“对类中public方法返回的可变内部域进行保护性拷贝”;

修改如下:
public Period(Date start , Date end){
        //do some checking , end should be later than start
        this.start =new Date( start.getTime());
        this.end = new Date(end.getTime());
}
public Date start(){
    return (Date)this.start.clone();
}
public Date end(){
    return (Date)this.end.clone();
}
修改后再运行,结果如下:
Output:
Wed Dec 28 00:00:00 CST 3904
Fri Dec 30 00:00:00 CST 3904
Unnormal period part1:
Wed Dec 28 00:00:00 CST 3904
Fri Dec 30 00:00:00 CST 3904
Unnormal period part2:
Wed Dec 28 00:00:00 CST 3904
Fri Dec 30 00:00:00 CST 3904

切记:在把类的内部组件的引用返回给客户之前,你应该返回一个保护性拷贝,如内部数组。

还有一点就是如果有可能你尽量使用immutable object作为你的内部组件,这样你就可以不必关心“defensive copy”的问题了。

25、小心设计方法的原型
在这个item中记住几个原则即可(这几个原则对我这个菜鸟来说用处还是蛮大的):
- 小心选择方法名字(可参考那本java developers almanac的索引来看看java中方法都是如何命名的)
- 对于参数类型,优先选用接口而不是类
- 小心使用function object , 原因不是主流的代码风格,难于理解。

34、通过接口引用对象
Item25中提到了“对于参数类型,优先选用接口”,更一般的讲我们应该用接口来引用对象。
书中的例子:
List subscribers = new Vector(); //good – use interface as type!
Vector subscribers = new Vector(); //bad-use class as type!

如果没有合适的接口,使用类来引用对象也是完全适合的。
其中有一种情况是当我们没有合适的接口时,我们尽量使用基类(往往是abstract class)来引用实现类(子类)的对象。

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言精进之路1 Go语言精进之路2 Go语言编程指南
商务合作请联系bigwhite.cn AT aliyun.com

欢迎使用邮件订阅我的博客

输入邮箱订阅本站,只要有新文章发布,就会第一时间发送邮件通知你哦!

这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn
DigitalOcean Referral Badge

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats