注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

简约男人

简约,不能简单

 
 
 

日志

 
 
关于我

一个过分渴望被理解的人其实就是一个软弱的人, 勇往直前的力量来自斩钉截铁的决心,不是来自别人的理解.

网易考拉推荐

【引用】Mercurial - 分布式版本控制系统(学习笔记)  

2012-02-04 23:37:26|  分类: 开发工具 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

Mercurial 简介

Mercurial 是一种轻量级分布式版本控制系统,采用 Python 语言实现,易于学习和使用,扩展性强。其是基于 GNU General Public License (GPL) 授权的开源项目。相对于传统的版本控制,具有如下优点:

  • 更轻松的管理。传统的版本控制系统使用集中式的 repository,一些和 repository相关的管理就只能由管理员一个人进行。由于采用了分布式的模型,Mercurial 中就没有这样的困扰,每个用户管理自己的 repository,管理员只需协调同步这些repository。
  • 更健壮的系统。分布式系统比集中式的单服务器系统更健壮,单服务器系统一旦服务器出现问题整个系统就不能运行了,分布式系统通常不会因为一两个节点而受到影响。
  • 对网络的依赖性更低。由于同步可以放在任意时刻进行,Mercurial 甚至可以离线进行管理,只需在有网络连接时同步。


从 repository 开始

版本控制系统中的 repository 就像一个仓库一样,用来存储被管理的数据文件,包含数据文件的不同版本。传统的版本控制系统中,这样的repository 是集中式的。除了这样一个集中式的 repository 之外,每个用户会有一份自己的工作版本拷贝。用户通过命令同步自己的拷贝和集中式的repository。

分布式版本控制系统中的 repository 则采用的是对等网络式的方式。传统集中式的管理中,只有一份 repository,其他的只是工作拷贝,不包含额外的版本。分布式的管理当中,每个用户所持有的都是一个真实的 repository,当中存储有不同的版本信息和维护一个 repository 的必要的辅助元数据。这样一个对等工作模式当中,用户通过交换下文即将提到的 changeset 来完成同步。

这样做的一些优点在于,工作的并行度将大大的提高。每个用户都可以带着这样的repository,从这里他可以把当前的工作拷贝切换到 repository 里面存储的任何一个版本。这个版本可以是之前正在工作的版本,现在需要合并进一些别人的意见,也可以是用户私有的一个版本,当前正在做很多前瞻性的工作, 还没有能同步给其他用户使用。也同样是因为这样的模式,每个用户可以任意把自己的 repository 当中的一个版本交换给其他用户,而不需要对自己手头正在工作的版本进行回退。下图是这样一个灵活的工作模式的演示。


图 1. 工作模式的演示
工作模式的演示



Mercurial 里的元素

Revision

在使用 Mercurial 的系统中每个改动隔离在各自的 repository 里,既避免把不相关的代码混杂起来, 又便于一个接一个的测试每一部分工作,用户做的每个改动称为一个 revision。一般会有一个所有用户都可以访问得到的 repository 保存了项目的“主要”版本,工作repository 是用户自己做事情的地方,实现新的特性,修改漏洞,重构,实验等,当完成改变后,你可以 push 到共用的 repository中,即完成了一个 revision。

Changeset

一个或多个文件的改变集合在一起形成一个逻辑单元,称为 changeset。每一个 changeset由两部分内容描述,版本号和 changeset 标识,例如:

 changeset:   207:58e4906e69e3 

冒号前面的数字代表版本号,它用来标识本地 changeset。这个版本号只有在用户的本地repository 中才有意义。冒号后面的那个很长的十六进制串是 changeset标识, 它是确定changeset的全局唯一标识符, 在所有包含这个 changese 的 repository 中都相同。多个用户之间讨论changeset,一般使用这个 changeset 标识,而不是上面说的版本号,因为完全有可能每个用户的 repository 中同样的 changeset 版本号不同。

Head

Head 表示 repository 中每个分支最新的 revision,通常在合并几个分支时会用到这个概念。

Tip

Tip 是最新的一个 changeset 的版本号的一个别名。在命令中任何使用版本号的地方都可以使用 tip 来代替最新的 changeset的版本号。Tip在各个repository中是不同的,同时一个repository 中只有一个 tip。

Log

Log 命令按时间顺序从近到远的记录着在 repository 中发生的每一次事件。可以通过指定-v诊断输出选项来获得更多更详细的历史信息,或者指定—debug选项来获得历史信息中的一切细节。



Mercurial的指令简介

当安装完Mercurial后,可以用不加参数的hg指令,查看指令的用法如下所示:
D:\hg>hg
Mercurial Distributed SCM

basic commands:

add add the specified files on the next commit
annotate show changeset information by line for each file
clone make a copy of an existing repository
commit commit the specified files or all outstanding changes
diff diff repository (or selected files)
export dump the header and diffs for one or more changesets
forget forget the specified files on the next commit
init create a new repository in the given directory
log show revision history of entire repository or files
merge merge working directory with another revision
pull pull changes from the specified source
push push changes to the specified destination
remove remove the specified files on the next commit
serve start stand-alone webserver
status show changed files in the working directory
summary summarize working directory state
update update working directory (or switch revisions)

use "hg help" for the full list of commands or "hg -v" for details
  
hg version 指令可以查看 Mercurial 的版本。
D:\hg>hg version
Mercurial Distributed SCM (version 1.6.2)

Copyright (C) 2005-2010 Matt Mackall <mpm@selenic.com> and others
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE

hg init 
将本地的一个目录初始化为一个 Mercurial 的 repository
,版本库的文件放在一个.hg的文件夹下面在本地的workspace目录下新建文件夹project1,在project1目录下运行如下命令:
 hg init

hg serve -n "project1" -p 8000 运行网络服务。
 hg serve -n "project1" -p 8000
之后可以在浏览器中输入http://localhost:8000/project1 来查看这个版本库。

在project1文件夹下新建一个txt文件,此处为main.txt,内容如下
public static void main(String args[]){

}

hg add 添加未版本化的文件
 hg add
adding main.txt
将main.txt版本化,即可以用Mercurial管理该文件。

对main.txt做一些修改并保存。
public static void main(String args[]){
       System.out,println("first modify");
}
hg status 显示修改过的文件
hg status
A main.txt


hg diff 对比版本间的差异
hg diff
diff -r 000000000000 main.txt
--- /dev/null The Jan 01 00:00:00 1970 +0000
+++ b/main.txt Thu Feb 24 14:44:55 2011 +0800
@@ -0,0 +1,3 @@
+public static void main(String args[]){
+        System.out.println("first modify");
+}
\No newline at end of file

  
hg commit 提交修改,使用-m 填写comments,同svn是一样的
 hg commit
填写comments
 add a new line"first modify"
第一个正式版本产生了。

hg tip 查看当前版本库的最新版本,注意:不是当前工作目录的最新版本。tip是版本库最新版本的意思
hg tip
changeset:      0:e4b3496ca779
tag:                 tip
user:               user1
date:              
Thu Feb 24 14:53:04 2011 +0800
summary:       
add a new line"first modify"

hg clone 克隆一个版本库到本地,当项目开始的时候,建议在一台电脑上init项目后,然后大家从他那clone出来,而不是各自init。用户user2user3在本地的workspace目录下运行如下命令:
 hg clone http://localhost:8000/project1 project1
 如果所有都没问题,clone 命令输出:
 destination directory: project1
requesting all changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
此时,我们应该在当前目录下发现一个目录叫 project1,目录下的文件是我们刚克隆的 repository 的精确复本。在 Mercurial 中,每一个 repository 是自包含的。当你克隆一个repository 后,新 repository 变成克隆时它的精确复本,但是后续的两个 repository 当中任一方改变都不会在对方显示,除非用户使用 pull 或 push 命令明确地传递改变,这个将在后面介绍。

user2对main.txt进行修改如下:

 public static void main(String args[]){
       System.out,println("first modify");
       System.out.println("second modify");
}
user3对main.txt进行修改如下:
 public static void main(String args[]){
       System.out,println("first modify");

       System.out.println("third modify");
}

user2将修改更新到服务器
hg commit

hg outgoing
将本地版本库同其他版本库进行比较,看看有哪些changeset可以push到其他版本库中

hg outgoing
comparing with http://localhost:8000
searching for changes
changeset:       1:b6b6dd8c038c
tag:                  tip
user:                user2
date                
Thu Feb 24 15:36:04 2011 +0800
summary:         add a line "second modify"

hg push 将本地版本库更新到其他版本库中,其他版本库需要开通ssh服务,Windows下需要cygwin来启动ssh,linux下用openssh实现。Windows客户端连接ssh服务器时,需要在mercurial.ini的ui段配置,如下
 [ui]
ssh = "C:\Program Files\TortoiseHg\TortoisePlink.exe"


hg push

user3
hg incoming 将本地版本库同其他版本库进行比较,看看有哪些changeset在其他版本库中可以pull过来
 hg incoming
comparing with http://localhost:8000
searching for changes
changeset:       1:b6b6dd8c038c
tag:                  tip
user:                user2
date                
Thu Feb 24 15:36:04 2011 +0800
summary:         add a line "second modify"

先对自己的修改进行commit
 hg commit

hg pull 从另一个版本库更新版本到本地
hg pull
pulling from http://localhost:8000
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 file <+1 heads>
  
hg merge 合并版本到当前工作目录,hg pull之后会提示hg update,hg update之后如果提示hg merge,这时候的merge是在最新版本的基础上进行的merge,merge之后所作的修改需要通过commit来生成新的版本号。
 hg merge
merging main.txt
0 files updateed, 1 files merged, 0 files removed, 0 files unresolved

再执行一次commit把merge后的版本也commit上去,最后push

hg update 更新工作目录,默认参数是tip,参数也可以是版本号、tag名字、branch名字。svn中的切换branch/tag通过这个命令来实现。
user1当前的main.txt文件的内容仍为:
 public static void main(String args[]){
       System.out,println("first modify");
}
表明其workspace和repository并不是同一个概念,并不会同步更新,只有update后workspace中的内容才能和repository里一致
 hg update
此时查看main.txt,其内容如下:
  public static void main(String args[]){
       System.out,println("first modify");
       System.out.println("second modify");
       System.out.println("third modify");
}
并会发现三个用户的workspace中的main.txt文件的内容相同


hg parents
查 看当前工作目录的最新版本,如果这个版本有多个parent,会显示出来,如果没有则不显示。parent是指某个版本的前一个版本,如果某个版本通过 两个版本merge而来,则会出现多个parents。mercurial还不支持超过两个的parents,也就是说只能将版本两个两个的合并,合并3 个版本需要操作2次,合并4个版本需要操作3次,依次类推,如果碰到8个版本需要合并,则需要合并7次...

hg tag
制定一个永久的版本号,tag存放在.hgtags文件中,这个文件也需要版本化
hg branch
显示当前branch,或者新建一个branch,默认的branch名字是default。

hg heads
head指的是没有儿子chaneset的changeset,也就是 版本树的叶子节点,多个叶子节点可以进行合并为一个叶子, branch heads指那些给了tag但还没有儿子changeset的changeset。 用hg heads显示当前库所有的heads , 如果存在多个heads则说明有多条并行开发的路径,这时需要考虑是否需要合并。
hg export
导出changeset,默认导出tip,需要用重定向来导出到文件中,之后这个文件可以通过邮件附件发出,这样可以实现无网络连接状态下的版本同步
hg import
导入changeset




扩展 Mercurial

Mercurial 系统中提供一种扩展机制来添加新的命令。通过扩展添加的命令可以在现有的Mercurial 系统的基础上添加新的功能,这些命令跟随 hg 后被调用时就像原生的命令一样。本文介绍两个常用的Mercurial扩展:Patchbomb和Mq。

Patchbomb

Patchbomb是一个在Mercurial系统中利用发送邮件的方式来交换changeset的扩展。Patchbomb添加了一个新的email命令。通过调用 hg email 命 令,changeset 提交时的信息的第一行将作为邮件的主题,信件的正文包括完整的 changese t提交信息,以 patch 的形式发布出来的 changeset 完整补丁。如果一次发送的是多个changeset,那么Patchbomb会提示输入本次 changeset 集的总提示信息,这部分信息将作为第一封信,信件主题以[PATCH 0 of N]开头,changeset 则会以[PATCH i of N]将的主题开头发出,其中i是 changeset在本地 repository 当中的顺序。多changeset 系列邮件中,每封信会在邮件头中包含合适的回复信息,这样在邮件客户端可以清晰的显示出系列 changeset 之间的层次关系。


图 3. 层次关系
层次关系

Patchbomb 支持使用本地系统中的 sendmail 程序来发送邮件,同时支持使用 SMTP 邮件服务器。用户如果长期固定为某个项目工作,还可以将邮件的收件地址和发信地址提供给Patchbomb,免去每次手动输入的麻烦。这一切都可以在 Mercurial 统一的 .hgrc 当中设置,以下是一个完整的例子。

[extensions]
hgext.patchbomb =
[email]
method = smtp # 还可以在这里指定/usr/sbin/sendmail
from = Zhengang Li <lizg@cn.ibm.com>
to = groupmail@foo.com
[smtp]
host = smtp.foo.com

Patchbomb 作者为Bryan O’Sullivan,该扩展现在随同 Mercurial 系统一起发布,用户不需额外下载安装,只需如上例中一样启用即可。

Mq

Mq 扩展的全名是Mercurial Queues,顾名思义该扩展将用户本地的多个 changeset 排列到队列中。原先分布式版本控制系统中,changeset 一旦提交并不能修改。有了 Mq 扩展之后,用户可以将本地的任意数量的 changeset 存放至一个本地的队列当中,对这些 changeset 用户除了可以使用传统的 changeset 上的任何命令之外,还可以修改changeset,包括提交信息和版本补丁的改动。

启用 Mq 扩展的办法同其他扩展一样,在 .hgrc 当中添加如下信息:

[extensions]
hgext.mq=

Mq的命令是一系列以字母q打头的命令,qinit, qnew, qrefresh, qdiff, qpop和qpush等。Qinit 用来初始化用来存放补丁队列的目录,qnew创建一个新的补丁changeset,qrefresh 将改动刷新到当前的补丁当中去,qdiff 将当前的补丁打印到屏幕,qpop qpush 用来移动当前存放在队列顶部的补丁。完整的 q 系列命令可以从 hg help给出的列表中获得。

Mq中所有的 changeset 补丁存放在项目顶层目录的.hg/patches下面,用户可以手动修改这些补丁当中的提交信息。Changeset 补丁的顺序存放在.hg/patches/series文件当中,同样的,用户可以修改这些补丁的顺序。

Mq的作者是Chris Mason,该扩展现在随同 Mercurial 系统一起发布,用户不需额外下载安装。

如果现有的扩展不能满足用户的要求,编写自己的扩展也不困难。Mercurial 使用 Python编写,编写一个新的扩展相当于在 Mercurial 系统的 hgext 包当中编写一个新的模块。具体的扩展实现还有些约定的规则,用户可以参考 Mercurial 所提供的文档。



其他分布式版本控制系统

分布式版本控制系统领域还有一些其他的系统,如GNU arch,monotone,Bazaar,git,darcs。

各类系统在各在一定的领域内长处,如GNU arch在GNU Savannah主机上应用,Bazaar 主要用于 Ubuntu Linux 系统的开发当中,git 源于Linux kernel 的开发,现在在多处和内核相关的项目中使用。他们大多数提供友好的Web界面和多种版本同步协议的支持。Git 和Gnu arch 由 C 和 shell 脚本语言编写实现,monotone 由C++语言实现,darcs 由 Haskell语言实现,Bazaar 和本文介绍的 Mercurial 由 Python 语言实现。从开放和扩展性方面来说,类似 Python 这样的脚本语言的更易于用户编写自己的扩展。

在众多的分布式版本控制系统中,Mercurial 是最年轻的,它的第一个版本发布于2005年4月。Mercurial 吸收了众多前辈的特性,被众多的项目采用。




errors & solution(待补充)
1、"ssl required" error
在mercurial.ini配置文件内添加如下信息:
[web]
push_ssl = false

2、"autorization failed" error
在mercurial.ini配置文件内添加如下信息:
[web]
allow_push = *
  评论这张
 
阅读(465)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017