努力思考 + 实践, 眼高手低是不行的. 注册 | 登陆
浏览模式: 标准 | 列表全部文章

[置顶] 资料备忘,保持更新。

SVN trunk, branches and tags

翻译者:zwws
原 文:
SVN trunk, branches and tags
译 言:http://article.yeeyan.org/view/132319/81358
转载请注明原链接,谢谢。

因水平所限,如果翻译得和原文有差,敬请评论指正。

  在本篇文章中, 我将会详细说明我是如何应用SVN trunk(树干)、branches(分支)和tags(标记)。这种方法同样被称为“branch always”,两者非常接近。可能我所介绍的并不是最好的方法,但是它会给新手一些解释说明,告诉他们trunk、branches和tags是什么,并且该如何去应用它们。

  当然,如果本文有些要点需要澄清/确认,亦或者有一些错误的观点,还请你评论,自由发表自己的观点。

——简单的对比

  SVN的工作机制在某种程度上就像一颗正在生长的树:

  • 一颗有树干和许多分支的树
  • 分支从树干生长出来,并且细的分支从相对较粗的树干中长出
  • 一棵树可以只有树干没有分支(但是这种情况不会持续很久,随着树的成长,肯定会有分支啦,^^)
  • 一颗没有树干但是有很多分支的树看起来更像是地板上的一捆树枝
  • 如果树干患病了,最终分支也会受到影响,然后整棵树就会死亡
  • 如果分支患病了,你可以剪掉它,然后其他分支还会生长出来的哦!
  • 如果分支生长太快了,对于树干它可能会非常沉重,最后整棵树会垮塌掉
  • 当你感觉你的树、树干或者是分支看起来很漂亮的时候,你可以给它照张相,这样就就可以记得它在那时是多么的赞。

——Trunk

  Trunk是放置稳定代码的主要环境,就好像一个汽车工厂,负责将成品的汽车零件组装在一起。

  以下内容将告诉你如何使用SVN trunk:

  • 除非你必须处理一些容易且能迅速解决的BUG,或者你必须添加一些无关逻辑的文件(比如媒体文件:图像,视频,CSS等等),否则永远不要在trunk直接做开发
  • 不要因为特殊的需求而去对先前的版本做太大的改变,如何相关的情况都意味着需要建立一个branch(如下所述)
  • 不要提交一些可能破坏trunk的内容,例如从branch合并
  • 如果你在某些时候偶然间破坏了trunk,bring some cake the next day (”with great responsibilities come… huge cakes”)

——Branches

  一个branch就是从一个SVN仓库中的子树所作的一份普通拷贝。通常情况它的工作类似与UNIX系统上的符号链接,但是你一旦在一个SVN branch里修改了一些文件,并且这些被修改的文件从拷贝过来的源文件独立发展,就不能这么认为了。当一个branch完成了,并且认为它足够稳定的时候,它必须合并回它原来的拷贝的地方,也就是说:如果原来是从trunk中拷贝的,就应该回到trunk去,或者合并回它原来拷贝的父级branch。

  以下内容将告诉你如何使用SVN branches:

  • 如果你需要修改你的应用程序,或者为它开发一个新的特性,请从trunk中创建一个新的branch,然后基于这个新的分支进行开发
  • 除非是因为必须从一个branch中创建一个新的子branch,否则新的branch必须从trunk创建
  • 当你创建了一个新branch,你应当立即切换过去。如果你没有这么做,那你为什么要在最初的地方创建这个分支呢?

——Tags

  从表面上看,SVN branches和SVN tags没有什么差别,但是从概念上来说,它们有许多差别。其实一个SVN tags就是上文所述的“为这棵树照张相”:一个trunk或者一个branch修订版的命名快照。

  以下内容将告诉你如何使用SVN tags:

  • 作为一个开发者,永远不要切换至、取出,或者向一个SVN tag提交任何内容:一个tag好比某种“照片”,并不是实实在在的东西,tags只可读,不可写。
  • 在特殊或者需要特别注意的环境中,如:生产环境(production)、?(staging)、测试环境(testing)等等,只能从一个修复过的(fixed)tag中checkout和update,永远不要commit至一个tag。
  • 对于上述提及到的环境,可以创建如下的tags:“production”,“staging”,“testing”等等。你也可以根据软件版本、项目的成熟程度来命名tag:“1.0.3”,“stable”,“latest”等等。
  • 当trunk已经稳定,并且可以对外发布,也要相应地重新创建tags,然后再更新相关的环境(production, staging, etc)

——工作流样例

  假设你必须添加了一个特性至一个项目,且这个项目是受版本控制的,你差不多需要完成如下几个步骤:

  1. 使用SVN checkout或者SVN switch从这个项目的trunk获得一个新的工作拷贝(branch)
  2. 使用SVN切换至新的branch
  3. 完成新特性的开发(当然,要做足够的测试,包括在开始编码前)
  4. 一旦这个特性完成并且稳定(已提交),并经过你的同事们确认,切换至trunk
  5. 合并你的分支至你的工作拷贝(trunk),并且解决一系列的冲突
  6. 重新检查合并后的代码
  7. 如果可能的话,麻烦你的同事对你所编写、更改的代码进行一次复查(review)
  8. 提交合并后的工作拷贝至trunk
  9. 如果某些部署需要特殊的环境(生成环境等等),请更新相关的tag至你刚刚提交到trunk的修订版本
  10. 使用SVN update部署至相关环境

Tags: svn, 翻译

Nginx(PHP/FastCGI)的PATH_INFO问题补充

注: 本文是 http://www.laruence.com/2009/11/13/1138.html 的补充.  
仅为解决使用上文配置PATH_INFO后, 当请求的URI为"<script>/"的情况下PATH_INFO为"/index.php"的问题, 使nginx下的PAHT_INFO表现与Apache一致.
 
如: 访问 "http://localhost/p.php/" 输出的PATH_INFO为"/index.php"  
 
    location ~ \.php($|/) {  
        root           D:/WWW/Localhost;  
        fastcgi_pass   127.0.0.1:9000;  
        fastcgi_index  index.php;  
 
        set $script    $uri;  
        set $path_info "";  
        if ($uri ~ "^(.+\.php)(/.*)") {  
            set  $script     $1;  
            set  $path_info  $2;  
        }  
  
        fastcgi_param SCRIPT_FILENAME $document_root$script;  
        fastcgi_param SCRIPT_NAME $script;  
        fastcgi_param PATH_INFO $path_info;  
 
        include        fastcgi_params;  
    }  
 
参考文档: http://wiki.nginx.org/NginxSymfony, 有细微修改

Tags: nginx, fastcgi

守护进程删除smarty的缓存文件(注释版)

原文: 鸭嘴的Blog

偶参阅了网上资料加了注释.

详见全文

» 阅读全文

Tags: php, pcntl_fork

顽皮的闭包

部分引用来源:http://www.cnblogs.com/rubylouvre/archive/2009/07/24/1530074.html

问题描述
有个函数fn, 定义在某作用域r中, 函数fn的定义语句中包含对作用域v的某个变量v的引用, 由于变量v的作用域在v中, 所以倘若函数a将变量v绑定到位于其他作用域的应用中时, 变量v无法以window.v 或者 obj.v 的形式在后期引用, 只好以指针或者变量地址方式保存在函数a中用以持久变量v.

[详见全文]

» 阅读全文

Tags: javascript, 闭包

PHP 输出缓存一二

PHP中的output_buffering可以堆砌, 即可以多次调用ob_start()以开启缓冲区,具体参照手册中ob_start()的介绍,相关摘录如下:

Output buffers are stackable, that is, you may call ob_start() while another ob_start() is active. Just make sure that you call ob_end_flush() the appropriate number of times. If multiple output callback functions are active, output is being filtered sequentially through each of them in nesting order.

php.ini中的output_buffering不为Off时, 会自动开启一个缓冲区(等同于调用一次ob_start()), 如果为数值, 即为缓冲区的缺省大小.

ob_get_contents()在未开启缓冲区的情况下调用不报错, 返回false.而ob_end_clean()以及相类似操作会报告Notice级别错误, 告知未开启缓冲区. 

使用位运算来实现PHP权限控制

原理: 将每个二进制位为一个权限标识位

  • 增加权限使用 | (无论存在与否, 将对应的权限位置1)
  • 删除权限使用 ^& ~ (无论存在与否, 将对应的权限位置0)
  • 判断权限使用 & (使用与判断对应的权限位是否为1, 是, 返回非0; 不是, 返回0)
http://xiaobin.net/archives/8/
http://www.lizhijin.com/view.php/PHP/140.html
http://topic.csdn.net/u/20090421/23/25ff3c5c-8bd1-4899-a05e-ecac2bad36e6.html (算法与前两则不同)

利用Curl、socket、file_get_contents POST数据

PHP代码
  1. <?php   
  2. /**  
  3. * Socket版本  
  4. * 使用方法:  
  5. * $post_string = "app=socket&version=beta";  
  6. * request_by_socket('facebook.cn','/restServer.php',$post_string);  
  7. */  
  8. function request_by_socket($remote_server,$remote_path,$post_string,$port = 80,$timeout = 30){   
  9.     $socket = fsockopen($remote_server,$port,$errno,$errstr,$timeout);   
  10.     if (!$socketdie("$errstr($errno)");   
  11.       
  12.     fwrite($socket,"POST $remote_path HTTP/1.0");   
  13.     fwrite($socket,"User-Agent: Socket Example");   
  14.     fwrite($socket,"HOST: $remote_server");   
  15.     fwrite($socket,"Content-type: application/x-www-form-urlencoded");   
  16.     fwrite($socket,"Content-length: ".strlen($post_string)+8."");   
  17.     fwrite($socket,"Accept:*/*");   
  18.     fwrite($socket,"");   
  19.     fwrite($socket,"mypost=$post_string");   
  20.     fwrite($socket,"");   
  21.       
  22.     $header = "";   
  23.     while ($str = trim(fgets($socket,4096))) {   
  24.         $header.=$str;   
  25.     }   
  26.       
  27.     $data = "";   
  28.     while (!feof($socket)) {   
  29.         $data .= fgets($socket,4096);   
  30.     }   
  31.       
  32.     return $data;   
  33. }   
  34.   
  35.   
  36. /**   
  37. * Curl版本   
  38. * 使用方法:   
  39. $post_string = "app=request&version=beta";   
  40. * request_by_curl('http://facebook.cn/restServer.php',$post_string);   
  41. */   
  42. function request_by_curl($remote_server,$post_string){   
  43.     $ch = curl_init();   
  44.     curl_setopt($ch,CURLOPT_URL,$remote_server);   
  45.     curl_setopt($ch,CURLOPT_POSTFIELDS,'mypost='.$post_string);   
  46.     curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);   
  47.     curl_setopt($ch,CURLOPT_USERAGENT,"Jimmy's CURL Example beta");   
  48.     $data = curl_exec($ch);   
  49.     curl_close($ch);   
  50.     return $data;   
  51. }   
  52. /**  
  53. * 其它版本  
  54. * 使用方法:  
  55. * $post_string = "app=request&version=beta";  
  56. * request_by_other('http://facebook.cn/restServer.php',$post_string);  
  57. */  
  58. function request_by_other($remote_server,$post_string){   
  59.     $context = array(   
  60.         'http'=>array(  
  61.             'method'=>'POST',  
  62.             'header'=>'Content-type: application/x-www-form-urlencoded'."".  
  63.                       'User-Agent : Jimmy's POST Example beta'."".   
  64.                       'Content-length: '.strlen($post_string)+8,   
  65.             'content'=>'mypost='.$post_string)   
  66.         );   
  67.     $stream_context = stream_context_create($context);   
  68.     $data = file_get_contents($remote_server,FALSE,$stream_context);   
  69.     return $data;   
  70. }   
  71.   
  72. ?>  

Tags: curl, socket

Records:11112345678910»