易栈网-膘叔

浏览模式: 标准 | 列表 | 图文
老王:单例模式是邪恶的么

老王:单例模式是邪恶的么

老王的看法,不过,事实上就是这样,现在很多开发人员还是很少在运行时候把对象作为参数传给某个方法或者class

原文:http://hi.baidu.com/thinkinginlamp/blog/item/ea586b63472627680c33fa38.html

正文:

写在前面的话:PHP每次运行重建环境,这样的运行方式本身就决定了PHP没有传统意义上的单例。

单例模式(singleton)也被叫做单件模式。使用它的目的是为了确保某个类只有一个实例。因为它的实现方式很简单,所以多数模式书籍都把单例模式作 为入门模式来介绍,可以说对很多模式爱好者来说,单例模式是他们最熟悉的设计模式。可惜这间接造成了单例模式使用的泛滥,以至于到了无所不在的地步,比如 说,ZendFramework里连前端控制器都是单例的。那么,单例模式是邪恶的么?

下面看一个实际编程时很多人愿意采用的单例模式例子:

注意:正常的单例模式应该设置一个私有化的__construct,但是出于下文的需要,我省略的它,至于限制__clone的行为,因为我嫌它占地方, 所以也没写,这两点你自己注意一下就好了,和文本讨论的问题关系不大。完整的例子可以参考:http://www.php.net/manual/en /language.oop5.patterns.php。

class Database
{
private static $instance;

public static function getInstance()
{
if (!isset(self::$instance)) {
$class = __CLASS__;
self::$instance = new $class;
}

return self::$instance;
}
}


如此的单例模式通常是这样调用的:

class Article
{
private $dasebase;

public function __construct()
{
$this->database = Database::getInstance();
}
}

$article = new Article();


下面我们就来讨论一下这样使用单例模式好还是不好。

文章在构造函数内通过单例模式的方式得到数据库实例,这看起来很正常,但是对于文章这样的领域概念来说,数据库实例属于纯粹的技术实现手段,明显属于外来 物,应该尽可能隔离才对,这样才符合单一原则,在测试驱动开发的领域,这被称作MOCK,但是在上例中,由于我们是在构造函数里通过单例模式静态方法调用 得到的数据库对象,这就造成了没有办法从外部替换掉这个数据库对象。

为了克服这样的问题,按照如下的方式获取数据实例更好一些:

class Article
{
private $dasebase;

public function __construct($database)
{
$this->database = $database;
}
}

$database = Database::getInstance();
$article = new Article($database);


一旦我们把数据库实例化的过程放到了外面,便可以随意替换掉其具体的实现方式,这很棒,特别是在测试的时候很有用,因为数据库环境是一个很大的不安定因 素,替换掉它有助于让测试用例更高效的运行。你甚至可以把程序搞得再智能化一点,一切外部对象依赖都通过容器注入的方式挂接。

此时再看看上面代码里的$database = Database::getInstance($database);突然又感觉有点莫名其妙,因为实在看不到在这里使用单例模式有什么额外的好处,直接按照最平常的实例化方式并没有什么不妥:

$database = new Database();
$article = new Article($database);

外部数据库对象通过构造函数的方式注入到文章里,保存在$this->database属性中,至于文章级联的评论 ($article->comments)也需要数据库实例这样的情况,可以在实例化评论的时候把文章的$this->database属性 通过评论构造函数注入的方式传递过去,当然,还有其它的方法,总而言之,你不再需要一个单例模式的数据库实例。

再回到单例模式的本意上:为了确保某个类只有一个实例。比如说公司只有一个CEO(如果有一个公司有多个CEO,那么这个公司必然会犯很多逻辑错误)。但 是反思现在很多人对单例模式的使用,往往并没有按照单例模式的本意来使用,拿上面的数据库例子来说,如果文章有一个数据库实例,评论有另一个数据库实例。 这有什么逻辑问题么?答案是没有。既然不必确保数据库只有一个实例,那么在这里使用单例模式的动机本身就值得推敲。当然,有人会说文章和评论使用不同的数 据库实例本身就低效。但如果仅仅是出于效率的考虑来使用单例模式,那么本质上不符合单例模式的定义,更何况即便不使用单例模式,我们也可以像文中的例子一 样通过注入的方式来解决所谓的低效问题。

写在后面的话:单例模式本身并不邪恶,邪恶的是在错误的环境下使用单例模式。不要为了单例而单例。

如何提高网站的访问速度 - 从30秒到3秒的改变

如何提高网站的访问速度 - 从30秒到3秒的改变

又一篇不是我写的东西,不错,对于WEB开发人员来说还是有参考意义的。所以我就贴了回来,也可以做个参考吧。。

原文:摘自:http://xinsync.xju.edu.cn/index.php/archives/4504

2006年10月份,我开始对web开发产生了兴趣,并决定自己也尝试开发一个网站。在此之前,我做过3年的java application的开发,对web开发应该算一无所知。在比较了java,php,ror,和python后,我选择了基于python的web框 架 - django 。到目前为止,我还认为这是一个明智的决定。Django高效的开发效率让我仅仅用一个月的业余时间,就基本完成了网站的开发。这是一个网络书签的网站, 我加上了一些有意思的特性,让网站显得有些与众不同。

我购买了域名和Dreamhost 的主机空间。Dreamhost支持django,并且第一年的费用只有180元人民币。2006年11月份,http: //www.hpbookmarks.com 上线了。网友们发来了善意的评论,“很有创意”,“点意思”,“一些feature很不错”。同时,还有一个非常一致的意见就是,“访问速度太慢了”。其 实,当时的情况不只是访问速度慢,而且是相当不稳定。很多时候是几个小时网站无法访问。当时,我并没有在意,因为我有两个自以为“合理”的解释。第一,我 用的是国外最便宜的虚拟主机,国内访问慢是很正常的。第二,django的还处于0.95的状态,效率和稳定性方面有问题也正常。

但是,我慢慢发现上面的解释不过是自己骗自己的借口。很多用dreamhost的网站,访问起来也很快。而且django也已经被成功应用在许多 大型的网站。我开始认真考虑提高网站速度的问题了。毕竟,速度慢的网站很可能在第一次就失去的用户,他们可以永远不会再来了。终于,我进行了下面一步一步 的优化工作,并且取得了一个看起来还不错的结果。

第一步,用Ajax提高用户体验

由于我的网站上链接字体的大小是根据点击次数决定,所以每次点击都要提交到服务器端并记录次数,再在客户端打开网站链接。这在localhost 测试的时候没有发现问题,但是部署到服务器上,会感到明显的等待。解决办法就是用Ajax。用户点击网站链接后就直接打开,再通过Ajax将点击的事件提 交到服务器端记录。这样用户感觉不到任何延时。

第二步,将逻辑移到客户端的javascript中

在开始的时候,“网站标签高亮”和“手气不错”的功能都是提交到服务器端操作,然后返回结果的。后来,我发现其实很多逻辑是可以移到客户端,由 javascript来实现的。Javascript非常强大,可以完成很多复杂的逻辑。将逻辑移到客户端的javascript中,可以很有效的减少和 服务器通讯的次数,获得更好的访问速度。

第三步,解决进程的

由于采用的是fastCGI的方式,我配置了django.fcgi。可是,我发现系统进程中,有大量的django.fcgi进程被标记为 < defunct>(失去功能)。这些进程会导致服务器有时无法正常访问。我开始尝试用命令来kill掉这些进程,但是很快发现这无法从根本上解决问 题。后来,我看到一个老外在blog上提到一个解决方案,将django.fcgi改名为dispatch.fcgi。原来,dispatch.fcgi 是一个dreamhost的系统进程,它的健壮性是可以得到保障的。果然,我将django.fcgi改名为 dispatch.fcgi后,的现象再没有出现。

第四步,优化SQL语句

SQL语句的执行通常也是一个很花费时间的操作。经过检查,我发现我的一条SQL语句,是一个嵌套三层的子表查询。而这条SQL还必须是一个 Raw SQL,即不能采用django的OR Maping。这意味着不能被cache缓存,每次都是真刀真枪的执行。更失败的是,经过我的分析,这条SQL完全可以不执行。这是一次设计上的失误,标
准的over design(过渡设计)。当时,我是想通过数据库得到一个最精确的统计值。后来发现,这个值完全可以用一个近似的常量代替。优化SQL,尤其是避免不必要的SQL执行,带来的效果是非常明显的。

第五步,尽量减少页面大小

随着添加网站越来越多,有一天我发现django生成的首页已经达到了80k。我很清楚这是一个非常不能被接受的数字。我开始检查页面,很快发现 了线索。 第一,因为偷懒,页面中很多layout是用空格( )实现的。第二,因为为了增加代码可读行,调试方便,每行生成的页面都增加换行符 (\n)。第三,最糟糕的是,大量的用了
inline css。就是将css style直接嵌入标记块中。于是,我立即动手,用css的align解决layout,去掉\n,将inline css抽象到独立的css文件中。这样下来,在不更改任何内容的情况下,80k变成了57k。(补充:由于网站链接大部分是打开新窗口,所以用了大量的 target=_blank。在ylsdd的提示下,在html的head里增加了,又节约了4k。)

第六步,用gzip进行页面压缩

当我兴高采烈的把页面优化结果贴到了smth bbs上,却被直接泼了盆凉水。原来百分之二十几的优化结果,实在太一般了。ylsdd给我了一个很重要的线索,deflate。原来apache的 deflate模块可以把文件进行gzip压缩,压缩后的文件传到浏览器后再被解压。主流的浏览器都支持这种gzip的解压操作。于是,我在apache 的配置文
件中加入了Add OutputFilter DEFAULT html css js的语句。经过测试,css,js这些文本文件的压缩后都只有原来尺寸的25%。这里,和大家分享一个网站http: //www.port80software.com/products/httpzip/compresscheck 它的作用是检测你的网站是否被压缩,以及压缩比率等。

第七步,回归静态页面

新的问题又来了。原来deflate只支持静态文件的压缩。而我的首页是django动态生成的,deflate模块没有进行压缩。我突然想到, 网站的首页为什么不能是静态页面呢?于是,我增加了一个runtime的api,这个api提供的是和原来一样由django动态生成的页面。我又写了一 个 python的程序,通过urllib2模块下载这个动态生成的页面,并保存为index.html。我将网站的root映射到index.html这个 静态页面。最后,通过linux crontab定义一个行为,每五分钟执行一下这个python程序,生成新的index.html。值得一提的是,由于网络原因,python程序不一 定每次都能准确完整的下载动态生成的页面。所以我们必须再进行一个校验算法。当页面大小要超过一定数字,页面中出现某个校验字符串的情况下,才保存 index.html。这样,每次用户提交的访问,不是由服务器端动态生成页面,极大的节省了服务器端的开销。而静态页面又可以有效的被deflate压 缩。最后结果,首页被压缩为13k,为原来的22%。唯一的区别就是,新提交和推荐的网站不能立即出现在首页。但是我认为,这应该是可以被接受的。

至此,网站的优化工作基本完成。网站的访问速度从原来30秒以上,缩短到3秒左右,应该说算是一个飞跃。虽然,3秒的速度也不是非常快,但是,考虑到虚拟主机等客观原因,这个结果我还是满意的。原来感觉我的网站很慢的朋友们,也可以再试试。

以上的优化方案出自我的个人经验,并不一定适合所有网站。但是,它告诉我们一个事实。影响网站访问速度的不仅仅是服务器配置,网络带宽。也许,你 糟糕的设计,低效率的方案也是致命的因素。应当注意的是,优化工作也不能匆匆上手。一定要仔细研究,具体情况具体分析,得到统计数据,找到真正的问题所 在,再开始优化。相信自己,提高网站的访问速度并不是不可能。毕竟,Nothing is Impossible。祝大家成功。

PHP细节之&&和and

PHP细节之&&和and

本文来自冰山上的播客:http://xinsync.xju.edu.cn/index.php/archives/4476
还是值得记录一下,虽然效果一样,但正因为优先级的不同,导致结果可能会和预料中的值有偏差,虽然实际应用中不太用得到但,看看还是好的
原文:

PHP中&&和and都是逻辑运算符,且功能也是完全一样的。如果你不了解它俩的区别,你可能会留下很不容易发现的BUG。仔细看下面的代码片段(注释是执行结果):

<?php
$true = TRUE;
$false = FALSE;
$rt1 = $true && $false;//$rt1:FALSE
$rt2 = $true and $false;//$rt2:TRUE

var_dump($rt1);//FALSE
var_dump($rt2);//TRUE
var_dump($true && $false);//FALSE
var_dump($true and $false);//FALSE

这里最让人感到奇怪的就是为什么$rt1成了FALSE,而$rt2却是TRUE。其实这是PHP优先级在作怪。从文档中我们看到,赋值符号”=”的优先级低于逻辑与符号”&&”,但高于逻辑与符号”and”(也就是&& > = > and)。也就是说:

$rt1 = $true && $false;
$rt2 = $true and $false;

在PHP看来其实是:

$rt1 = ($true && $false);
($rt2 = $true) and $false;

这样就容易解释为什么会有那样的结果了。那现在你知道下面两句的结果了吗?

var_dump($rt1 = $true && $false);
var_dump($rt2 = $true and $false);

参考资料:
PHP Operator Precedence
PHP Logical Operators

我想买车了

说实话,我真的想买车了。
上班,没车,天天挤公交又特别累。晚上回家吧,还是乘地铁。那叫一个累啊。。。
如果有了车,那上下班可以轻松很多了。所以,我就想买辆车,这样,平时或许也会方便很多
可是,相对的,问题也有一些啊:
你想想,去远的地方吧。没车真不方便 。
去近的地方吧。开车又不值得。
只是,没有车库,不方便停车。出门吧,又到处找不到一个好的停车位。

不过,想想,还是忍了。。。
这些都不是什么大问题啊。实在不行,咱还可以忍忍不开的嘛。

嗯,决定了,买,分期付款,没啥买不起的。不就是贷点款嘛。。。


各位,帮忙想个建议啥的,你说,我是买国产的永久、凤凰好还是买国外的GIANT之类的呢?这些车的优劣谁能给个评测?现在的车网、论坛啥的,这类评测都很少见啊。

享用 Balsamiq Mockups

享用 Balsamiq Mockups

前段时间在博客园上看到有介绍这款软件,试用了一下,发觉还是不错的。该软件是基于Adobe AIR框架的一个富客户端,当然了,你也可以直接在官方网站上进行试用。

官方网站的网址为:http://www.balsamiq.com/products/mockups/desktop

试用是很简单的,可以直接从菜单栏上把BUTTON进行拖放,在页面中拖放控件时,还会有XY轴的水平线进行各个控件的相对定位,可以让你控件能够整齐的显示在页面上。

手绘风格的网页原型还是很容易被用户所能接受。字体也很漂亮,对于中文的支持则需要在菜单的View下选择Use System Fonts来解决。宋体的感觉不是特别好。

在程序的右上角还有一个全屏功能,该功能激活后,会在页面上有一个很大的光标箭头,你可以用鼠标控制该箭头来对你所做的页面进行演示。

花了十分钟把我的博客的页面做了一次原型(当然是根据我现在的博客做的,稍改了一下布局,我自己也觉得这样会比较好一点吧?文章页内的)

bac8deceee43c44a23497f5e6b3344a2

价格为$79的软件在没有注册前是不能保存、导出的,我做的图还是用系统的Print来进行截屏的(忘了装截屏软件了)。动不动跳出的提示注册框还是让你很郁闷的。不过相对于这款软件来说,还是值得被弹两下的。

由于作者表示进行推广可以赠送license,于是我在自己的博客上也想试试,看看能不能获取序列号,毕竟这款软件确实是值得试用。

谷鸽鸟看——打造全球最大的山寨信息网

关于“谷鸽鸟看”计划

2009年4月1日, 总部位于美国加州山寨城(Mountain Village)的谷歌公司正式推出“谷鸽鸟看”计划。 该计划旨在利用装备了 CADIE 芯片和软体, 并被赋予了超智能信息处理能力的“谷鸽”, 动态采集、整理和分享山寨信息,打造全球最大的山寨信息网。 简言之,“谷鸽鸟看”计划的使命是:

鸟看全球信息,使人人皆可山寨并从中受益!

什么是“谷鸽鸟看”技术?

谷鸽

谷歌为专门训练的 31415926 只谷鸽装备了以 CADIE 计算技术为支撑的四大高科技系统:

  • 智能导航帽:在鸽子头脑清醒的时候提供 0.01 米精度全球定位导航信息, 并在鸽子头昏脑胀的时候使用绿色纳米微波为鸽子进行泰式头部按摩。
  • 信息处理肚兜:纯棉工艺,不仅仅为了保暖, 同时也是 CADIE 谷鸽版芯片和软体的运行平台。
  • 无线充电脚环:当谷鸽飞临专用太阳能充电站时, 脚环在五分钟内以无线方式为谷鸽充满 16 小时工作电力。
  • 呼叫应答器:支持 2G/3G 网络协议,响应用户召唤, 真正实现“思想有多远,山寨就有多远”的山寨主义理想。

类似谷歌街景(Street View) 采集技术,谷歌倾心打造的超智能谷鸽被赋予外出采集山寨信息的重要使命。 这一方面可以大幅提高谷歌地球(Google Earth) 和谷歌地图(Google Maps)的图像分辨率, 另一方面也可以弥补网页搜索中山寨信息含量明显偏低的缺憾, 实现搜索山寨化,山寨信息化,信息无废话。

天涯何处不山寨,就看谁的动作快! 利用飞得高、看得远、耳朵灵、眼睛贼等特点, 谷鸽将重点采集以下山寨信息:

  • 最具有震撼力的山寨新闻:例如,湖南某烟花厂最新研制成功无污染、无燃烧、无烟尘, 适于在所有完工或未完工高层建筑安全燃放的绿色版山寨烟花的新闻。
  • 最有潜质的山寨明星:包括,上不了春晚一级的舞台,但有潜力成为网络人气偶像的型男、靓女; 不懂得炒作,但却充满娱乐气质的宅男、宅女;没有出众外表,但有满腹心事的痴男、怨女……
  • 最适合山寨恋人约会的时间地点:例如,2月14日晚,多情谷下、断肠崖边的爱情烧饼屋。
  • 最有创意的山寨发明、创造:例如, 能够从谷鸽音乐搜索中迅速找到可调解家庭矛盾、平息地区争端的“和平音乐编织机”。
  • 最有魅力的山寨流行语:类似2008年出现的“叉腰肌”、“囧”、 “谷鸽”等充满山寨活力的流行网络新词。

由“谷鸽鸟看”技术采集的所有山寨信息将被 CADIE 集中处理并发布在谷鸽山寨搜索引擎上。 新一代山寨搜索引擎将能够覆盖全球每个角落、每一时刻、每一种类型的山寨信息。 网友可以使用谷歌地图提供的谷鸽飞行路线图功能查看谷鸽的飞行路线。

谷鸽飞行路线图

返回页首

如何召唤谷鸽?

除谷鸽自动外出寻找山寨信息外,用户也可以主动召唤谷鸽采集身边的山寨信息。召唤方法如下:

  • 走到户外或楼顶超过20平方米的空地
  • 用支持上网功能的手机打开谷歌移动版http://g.cn/
  • 对着手机屏幕上出现的麦克风图标,使用鸽子的方法,“咕——咕——咕——”大叫三声
  • 耐心等待……

不出意外的话,谷鸽会在三十分钟内出现在您的身边。 根据不完全统计,排除软件 Bug 和芯片抽风等影响因素, 谷鸽响应召唤者的平均时间间隔是 21.04 分钟,响应成功率为 99.5865%。

返回页首

如何保护隐私?

谷歌承诺,谷鸽只飞越公共区域,并只能像普通鸽子一样感知鸟类可感知的事物 (想像一下你自己被装上翅膀,在天上飞翔时所能看到和听到的一切)。如果你不想谷鸽打扰你, 可以从以下网址下载“谷鸽别烦我”的折纸挂件图样,自行制作后, 站在窗前,一旦看到谷鸽,就高高挥舞“谷鸽别烦我”的折纸。祝你好运!

“谷鸽别烦我”折纸挂件图样

返回页首

什么是“绿色谷鸽”计划?

谷歌计划在全国范围修建 271828 座由 CADIE 技术提供支持的太阳能充电站。 “谷鸽太阳能充电站”同时支持无线和有线两种充电模式, 不但可以为佩戴“无线充电脚环”的谷鸽提供可持续能源, 还可以为其他可充电电器设备提供服务。 未来,经过谷鸽计划的充分检验后,这批充电站将投入民用, 为手机、电动汽车、油电混合动力汽车、电动自行车等民用设备提供充电服务。

目前,谷歌正在与英国科学家积极合作,研发第二代能源供应设备——“鸽能发电”。 这将是一种完全依靠谷鸽翅膀振动获得电力,并完全自给自足的供电模式。

未来,绿色、清洁、无污染的“鸽能发电”技术, 及其推广版本如“狗能发电”、“马能发电”、 “麻雀能发电”等等,有望部分取代高污染、高能耗的火力发电技术, 成为全球绿色能源体系的重要组成部分。


Only a joke,愚人节,谷歌的玩笑还是挺有创意,详细请看:http://www.google.cn/intl/zh-CN/google_pigeon/index.html

Xenocode Browser Sandbox

Xenocode Browser Sandbox

Run any browser from the web

看了这个副标题是不是觉得很HIGH呀,试用了一下确实可以。身为一名WEB开发人员,这样的工具实在是居家旅行之必备工具啊。

看看人家的说明,多嚣张啊:

The Xenocode Browser Sandbox allows all popular Windows browsers to be run simultaneously, directly from the web. Web designers, system administrators, and other users can now evaluate Internet Explorer 8, 7, and 6, Mozilla Firefox, Apple Safari, Opera, and Google Chrome directly from the web in a risk-free manner. Unlike traditional software applications, Xenocode WebApps do not require any software to be installed and allow multiple application versions to run side-by-side on any version of Windows.

支持这么多的浏览器,你“建国门建国门(请参考小笑话:见过没)”。

再了解一下这家公司:

Understanding Xenocode Technology

Xenocode is a powerful virtualization technology that separates applications from the underlying operating system. Unlike traditional hardware virtualization solutions that duplicate an entire host operating system, Xenocode's lightweight application virtualization technology emulates only core operating system features required for application execution. Xenocode requires no setup, configuration, clients, or device drivers, insulates applications against conflicts, and runs existing applications seamlessly on Windows Vista and locked-down desktops.

Xenocode virtual applications can be deployed on the web, intranets, portable storage devices, and existing desktop management infrastructure, including Active Directory, Microsoft SMS, LANDesk Management Suite, and BMC Configuration Management. Xenocode technology has been licensed by Novell and is available as part of Novell ZENworks Application Virtualization.

The Xenocode Virtual Application Studio authoring environment allows software developers and systems administrators to easily convert existing applications into virtual machine packages. The Xenocode WebApp service allows Xenocode applications to be run directly from the web via a simple control that embeds directly into web sites, blogs, and other online content.

介绍了这么多,如果不贴网址,恐怕我会被人砍死吧?

来吧。这里就是:http://www.xenocode.com/browsers/

前提,您的机器上需要安装.net framework,相信大多数人应该都会有安装吧。best regards for you....

PS:有朋友说地址失效了,嗯,确实,其实,是他们换域名啦,到这里看看吧:http://spoon.net/browsers/

SVN提交更新的一个准则

SVN提交更新的一个准则

同样,是一篇摘录,笔记。勿怪。。。
原文:http://www.cnblogs.com/chenlong828/archive/2008/09/22/1296193.html
作者:dreamland

查阅了一下网络和博客园,发现还没有一个明确地指导源码管理提交准则的相关文章,因此斗胆整理了一部分自己平时开发管理的心得,加上查阅了部分英文资料写了一个不算很完善的SVN提交准则。

负责而谨慎地提交自己的代码

SVN更新的原则是要随时更新,随时提交。当完成了一个小功能,能够通过编译并且并且自己测试之后,谨慎地提交。

如果提交过程中产生了冲突,则需要同之前的开发人员联系,两个人一起协商解决冲突,解决冲突之后,需要两人一起测试保证解决冲突之后,程序不会影响其他功能。

如果提交过程中产生了更新,则也是需要重新编译并且完成自己的一些必要测试,再进行提交。

保持原子性的提交

每次提交的间歇尽可能地短,以一个小时,两个小时的开发工作为宜。如在更改UI界面的时候,可以每完成一个UI界面的修改或者设计,就提交一次。在开发功能模块的时候,可以每完成一个小细节功能的测试,就提交一次,在修改bug的时候,每修改掉一个bug并且确认修改了这个bug,也就提交一次。我们提倡多提交,也就能多为代码添加上保险。

不要提交自动生成的文件

Visual Studio在生成过程中会产生很多自动文件,如.suo等配置文件,Debug,Release,Obj等编译文件,以及其他的一些自动生成,同编译代码无关的文件,这些文件在提交的时候不应该签入,如果不小心签入了,需要使用Delete命令从仓库中删除。

不要提交不能通过编译的代码

代码在提交之前,首先要确认自己能够在本地编译。如果在代码中使用了第三方类库,要考虑到项目组成员中有些成员可能没有安装相应的第三方类库或者没有放入GAC(针对.Net Framework)中,项目经理在准备项目工作区域的时候,需要考虑到这样的情况,确保开发小组成员在签出代码之后能够在统一的环境中进行编译。

不要提交自己不明白的代码

代码在提交入SVN之后,你的代码将被项目成员所分享。如果提交了你不明白的代码,你看不懂,别人也看不懂,如果在以后出现了问题将会成为项目质量的隐患。因此在引入任何第三方代码之前,确保你对这个代码有一个很清晰的了解。

提前宣布自己的工作计划

在自己准备开始进行某项功能的修改之前,先给工作小组的成员谈谈自己的修改计划,让大家都能了解你的思想,了解你即将对软件作出的修改,这样能尽可能的减少在开发过程中可能出现的冲突,提高开发效率。同时你也能够在和成员的交流中发现自己之前设计的不足,完善你的设计。

对提交的信息采用明晰的标注

+) 表示增加了功能

*) 表示对某些功能进行了更改

-) 表示删除了文件,或者对某些功能进行了裁剪,删除,屏蔽。

b) 表示修正了具体的某个bug

svn常用命令

svn常用命令

又是一篇记录,摘要,原文来自:http://cwg.bloghome.cn/posts/75845.html

svn命令 通常都有帮助,可通过如下方式查询:

$ svn help 

知道了子命令,但是不知道子命令的用法,还可以查询:

$ svn help add 

开发人员常用命令

(1) 导入项目

$ cd ~/project
$ mkdir -p svntest/{trunk,branches,tags}
$ svn import svntest https://localhost/test/svntest --message "Start project"
...
$ rm -rf svntest

我们新建一个项目svntest,在该项目下新建三个子目录:trunk,开发主干;branches,开发分支;tags,开发阶段性标签。然后导入到版本库test下,然后把svntest拿掉。

(2) 导出项目

$ svn checkout https://localhost/test/svntest/trunk

修订版本号的指定方式是每个开发人员必须了解的,以下是几个参考例子,说明可参考svn推荐书。

$ svn diff --revision PREV:COMMITTED foo.c
# shows the last change committed to foo.c

$ svn log --revision HEAD
# shows log message for the latest repository commit

$ svn diff --revision HEAD
# compares your working file (with local changes) to the latest version
# in the repository

$ svn diff --revision BASE:HEAD foo.c
# compares your “pristine” foo.c (no local changes) with the
# latest version in the repository

$ svn log --revision BASE:HEAD
# shows all commit logs since you last updated

$ svn update --revision PREV foo.c
# rewinds the last change on foo.c
# (foo.c's working revision is decreased)

$ svn checkout --revision 3
# specified with revision number

$ svn checkout --revision {2002-02-17}
$ svn checkout --revision {15:30}
$ svn checkout --revision {15:30:00.200000}
$ svn checkout --revision {"2002-02-17 15:30"}
$ svn checkout --revision {"2002-02-17 15:30 +0230"}
$ svn checkout --revision {2002-02-17T15:30}
$ svn checkout --revision {2002-02-17T15:30Z}
$ svn checkout --revision {2002-02-17T15:30-04:00}
$ svn checkout --revision {20020217T1530}
$ svn checkout --revision {20020217T1530Z}
$ svn checkout --revision {20020217T1530-0500}

(3) 日常指令

$ svn update

$ svn add foo.file
$ svn add foo1.dir
$ svn add foo2.dir --non-recursive
$ svn delete README
$ svn copy foo bar
$ svn move foo1 bar1

$ svn status
$ svn status --verbose
$ svn status --verbose --show-updates
$ svn status stuff/fox.c

$ svn diff
$ svn diff > patchfile

$ svn revert README
$ svn revert

修改冲突发生时,会生成三个文件:.mine, .rOLDREV, .rNEWREV。比如:

$ ls -l
sandwich.txt
sandwich.txt.mine
sandwich.txt.r1
sandwich.txt.r2

解决修改冲突方式之一:修改冲突的文件sandwich.txt,然后运行命令:

$ svn resolved sandwich.txt

方式之二:用库里的新版本覆盖你的修改:

$ cp sandwich.txt.r2 sandwich.txt
$ svn resolved sandwich.txt

方式之三:撤销你的修改,这种方式不需要运行resolved子命令:

$ svn revert sandwich.txt
Reverted 'sandwich.txt'
$ ls sandwich.*
sandwich.txt

确保没问题后,就可以提交了。

$ svn commit --message "Correct some fatal problems"
$ svn commit --file logmsg
$ svn commit

(4) 检验版本历史

$ svn log
$ svn log --revision 5:19
$ svn log foo.c
$ svn log -r 8 -v

$ svn diff
$ svn diff --revision 3 rules.txt
$ svn diff --revision 2:3 rules.txt
$ svn diff --revision 4:5 http://svn.red-bean.com/repos/example/trunk/text/rules.txt

$ svn cat --revision 2 rules.txt
$ svn cat --revision 2 rules.txt > rules.txt.v2

$ svn list http://svn.collab.net/repos/svn
$ svn list --verbose http://svn.collab.net/repos/svn

$ svn checkout --revision 1729 # Checks out a new working copy at r1729
…
$ svn update --revision 1729 # Updates an existing working copy to r1729
…

(5) 其他有用的命令

svn cleanup

为失败的事务清场。

(6) 分支和合并

建立分支方法一:先checkout然后做拷贝,最后提交拷贝。

$ svn checkout http://svn.example.com/repos/calc bigwc
A bigwc/trunk/
A bigwc/trunk/Makefile
A bigwc/trunk/integer.c
A bigwc/trunk/button.c
A bigwc/branches/
Checked out revision 340.

$ cd bigwc
$ svn copy trunk branches/my-calc-branch
$ svn status
A + branches/my-calc-branch

$ svn commit -m "Creating a private branch of /calc/trunk."
Adding branches/my-calc-branch
Committed revision 341.

建立分支方法二:直接远程拷贝。

$ svn copy http://svn.example.com/repos/calc/trunk \
http://svn.example.com/repos/calc/branches/my-calc-branch \
-m "Creating a private branch of /calc/trunk."

Committed revision 341.

建立分支后,你可以把分支checkout并继续你的开发。

$ svn checkout http://svn.example.com/repos/calc/branches/my-calc-branch

假设你已经checkout了主干,现在想切换到某个分支开发,可做如下的操作:

$ cd calc
$ svn info | grep URL
URL: http://svn.example.com/repos/calc/trunk
$ svn switch http://svn.example.com/repos/calc/branches/my-calc-branch
U integer.c
U button.c
U Makefile
Updated to revision 341.
$ svn info | grep URL
URL: http://svn.example.com/repos/calc/branches/my-calc-branch

合并文件的命令参考:

$ svn diff -r 343:344 http://svn.example.com/repos/calc/trunk
$ svn merge -r 343:344 http://svn.example.com/repos/calc/trunk
$ svn commit -m "integer.c: ported r344 (spelling fixes) from trunk."
$ svn merge -r 343:344 http://svn.example.com/repos/calc/trunk my-calc-branch
$ svn merge http://svn.example.com/repos/branch1@150 \
http://svn.example.com/repos/branch2@212 \
my-working-copy
$ svn merge -r 100:200 http://svn.example.com/repos/trunk my-working-copy
$ svn merge -r 100:200 http://svn.example.com/repos/trunk
$ svn merge --dry-run -r 343:344 http://svn.example.com/repos/calc/trunk

最后一条命令仅仅做合并测试,并不执行合并操作。

建立标签和建立分支没什么区别,不过是拷贝到不同的目录而已。

$ svn copy http://svn.example.com/repos/calc/trunk \
http://svn.example.com/repos/calc/tags/release-1.0 \
-m "Tagging the 1.0 release of the 'calc' project."

$ ls
my-working-copy/
$ svn copy my-working-copy http://svn.example.com/repos/calc/tags/mytag
Committed revision 352.

后一种方式直接把本地的工作拷贝复制为标签。

此外,你还可以删除某个分支。

$ svn delete http://svn.example.com/repos/calc/branches/my-calc-branch \
-m "Removing obsolete branch of calc project."

管理人员常用命令

(7) 版本库管理

$ svnadmin help
...
$ svnadmin help create
...
$ svnadmin create --fs-type bdb /usr/local/repository/svn/test
$ chown -R svn.svn /usr/local/repository/svn/test

建立版本库,库类型为bdb(使用Berkeley DB做仓库),库名称为test。
svn版本库有两种存储方式:基于Berkeley DB(bdb)或者基于文件系统(fsfs),通过 --fs-type可指定存储方式。

(8) 查询版本库信息

$ svnlook help
...
$ svnlook help tree
...
$ svnlook tree /usr/local/repository/svn/test --show-ids