- 13
- 06月
Mercurial 是一种轻量级分布式版本控制系统,采用 Python 语言实现, 易于学习和使用,扩展性强。其是基于 GNU General Public License (GPL) 授权的开源项目。
1 基本概念
- Revision
- 在使用 Mercurial 的系统中每个改动隔离在各自的 repository 里, 既避免把不相关的代码混杂起来,又便于一个接一个的测试每一部分工作, 用户做的每个改动称为一个 revision。 一般会有一个所有用户都可以访问得到的 repository 保存了项目的“主要”版本, 工作repository 是用户自己做事情的地方,实现新的特性,修改漏洞,重构,实验等, 当完成改变后,你可以 push 到共用的 repositor y中,即完成了一个 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 选项来获得历史信息中的一切细节。
英文说明: Revisions, changesets, heads, and tip
Mercurial groups related changes to multiple files into single atomic changesets, which are revisions of the whole project. These each get a sequential revision number. Because Mercurial allows distributed parallel development, these revision numbers may disagree between users. So Mercurial also assigns each revision a global changeset ID. Changeset IDs are 40-digit hexadecimal numbers, but they can be abbreviated to any unambiguous prefix, like "e38487".
Branches and merges in the revision history can occur at any point. Each unmerged branch creates a new head of the revision history. Here, revisions 5 and 6 are heads. Mercurial considers revision 6 to be the tip of the repository, the head with the highest revision number. Revision 4 is a merge changeset, as it has two parent changesets (revisions 2 and 3).
2 基本操作
2.1 安装
- Linux
- Linux 系统一般会带有命令行版本的 Mercurial, 当然, 也可以安装 TortoiseHg. 另外, 早期的 Mercurial 版本和 TortoiseHg 版本可能会存在一定的差异, 比如Mercurial 2.7.x 版本, 对应使用 TortoiseHg 2.9.x 版本.
- Windows
- Windows 下直接安装 TortoiseHg 即可, 这是一个功能相当强大的图形客户端.
2.2 配置
第一步, 设置用户名
方法1, 通过 TortoiseHg 工作台来设置, 点击 File 菜单, 选择 Settings 命令, 在弹出的对话框中点击 Commit 标签, 在 Username 这栏填写类似这样的用户名 xxx <xxx@xxx.com>, 然后点击 OK 按钮保存.
方法2, 直接编辑 ~/.hgrc 并添加或更新以下内容:
[ui] username = xxx <xxx@xxx.com> verbose = True
第二步, 启用记住密码功能
Windows 下, 打开 TortoiseHg 工作台, 进入 Settings 对话框, 点击 Extensions 标签, 勾选 mercurial_keyring 插件, 点击 OK 按钮保存.
Linux 下, 需要先安装 mercurial_keyring 软件包 (可通过 pip 或者 easy_install 安装), 然后再在 TortoiseHg 中启用插件, 或者编辑 ~/.hgrc 启用:
[extensions] mercurial_keyring =
注解
本人使用 Slackware 14.1 系统, 桌面环境为 KDE4, 若要使用这个插件, 需要开启 KDE 钱包.
第三步, KDiff3 工具(可选)
Windows 下, TortoiseHg 默认已经安装并启用, 无须设置.
Linux 下, 需要先安装 KDiff3 软件, 然后再启用:
[extensions] hgext.extdiff = [extdiff] cmd.kdiff3 = [merge-tools] kdiff3.args = $base $local $other -o $output
2.3 添加仓库
hg init example
2.5 遗忘(forget)
对指定文件进行标记, 以便在下一次提交时不再被追踪. 被标记的文件只会在当前分支删 除, 而不是从整个项目历史. 标记后的文件不会从当前工作目录中删除.
hg forgot hello.txt
2.9 复制和移动(copy, move)
hg copy hello.txt hello2.txt hg mv hello.txt hello1.txt
技巧
mv, move, rename 是相同的命令, 若要更改文件名, 可以使用 mv 命令.
2.10 删除(remove)
对仓库中指定文件进行标记, 以便在下一次提交时被删除. 被标记的文件只会在当前分支删除. 标记后的文件会从当前工作目录中删除.
hg remove hello.txt
若要撤消删除操作, 使用 hg revert 命令.
若要撤销已添加的文件, 使用 hg forget 命令.
remove 对不同状态的文件的反应:
opt/state | A | C | M | ! |
none | W | RD | W | R |
-f | R | RD | RD | R |
-A | W | W | W | R |
-Af | R | R | R | R |
注解
- 文件状态: Added [A], Clean [C], Modified [M] and Missing [!]
- 动作: Warn, Remove (from branch), Delete (from disk)
2.11 查阅历史(log)
hg log
2.12 版本切换(update)
hg update hg update tip hg update -r 3
2.13 撤消修改(revert)
将文件到恢复到检出(未提交)的状态.
注解
revert 命令会恢复文件内容到未提交的状态, 但添加(add), 删除(remove), 复制(copy), 重命名(rename)的文件除外.
撤销当前工作目录中某个文件的修改:
hg revert hello.txt
注解
一般会生成一个 .orig 后缀的备份文件.
撤消当前工作目录中所有的修改:
hg revert --all
撤消某个历史版本中某个文件的修改:
hg revert -r 3 hello.txt
3 进阶操作
3.1 克隆(clone)
hg clone example example2 hg clone http://bitbucket.org/xxxx xxxx
3.5 解决冲突
合并过程中会自动解决冲突, 若某些冲突无法自动解决, 则需要手工解决.
3.6 回滚(rollback)
若对最后一次提交的变更集不满意, 可以执行回滚操作:
hg rollback
注解
只有一级回滚, 回滚操作不能被还原. 它会恢复最后一次事务那个时间的目录状态, 损失从那时起的所有目录状态. 而且合并操作是不能回滚的.
可以回滚的操作:
- commit
- import
- pull
- push (需要在这个仓库的目的仓库进行回滚操作)
- unbundle
3.8 书签(bookmark)
书签与 Git 的本地分支类似, 是指向某个版本的指针.
查看书签:
hg bookmarks
添加一个 feature-a 的书签:
hg bookmark feature-a
书签改名:
hg bookmark --rename feature-a feature-hello
删除书签:
hg bookmark --delete feature-a
注解
更多书签相关的操作可以参考: http://mercurial.aragost.com/kick-start/en/bookmarks/
3.9 分支(branch)
Mercurial 中的分支是不能删除的, 只能关闭, 不像 Git 的本地分支那样, 可以随时删除, Mercurial 中和它类似的功能是书签 (Bookmark).
查看分支:
hg branches
增加一个分支:
hg branch stable hg commit -m "Started stable branch." hg tag 1.0
注解
不同分支之间只能合并, 分支切换可以使用 hg update 命令.
一般情况下, default 是日常开发分支, stable 分支只做重要的版本发布. 某些情况下, 某个 Bug 可能在 default 分支修正了, 但 stable 分支又不能马上与 default 分支合并, 这时就需要把修正这个 Bug 的版本复制到 stable 分支:
hg update stable hg graft tip # 或者 hg graft -r 12 hg tag 1.0.1 hg update default hg merge stable
注解
更多分支相关的操作可以参考: http://mercurial.aragost.com/kick-start/en/tasks/
4 使用 Hgweb 架设服务器
参考: http://mercurial.selenic.com/wiki/PublishingRepositories
系统环境:
- Apache 2.2 - 2.4
- Mod_wsgi 3.5
- Python 2.7.x
- Mercurial 3.2 - 3.4
- Virtualenv
Hgweb 从 Mercurial 代码仓库中获取.
相关路径:
- Hgweb 目录: /var/www/hgweb
- 虚拟环境路径: /var/www/hgweb/env
- 仓库路径: /var/www/hgweb/repos
文件 /var/www/hgweb/hgweb.wsgi:
# An example WSGI for use with mod_wsgi, edit as necessary # See http://mercurial.selenic.com/wiki/modwsgi for more information # Path to repo or hgweb config to serve (see 'hg help hgweb') config = "/var/www/hgweb/hgweb.conf" # Uncomment and adjust if Mercurial is not installed system-wide # (consult "installed modules" path from 'hg debuginstall'): # import sys; sys.path.insert(0, "/var/www/hgweb") # Uncomment to send python tracebacks to the browser if an error occurs: #import cgitb; cgitb.enable() activate_this = '/var/www/hgweb/env/bin/activate_this.py' execfile(activate_this, dict(__file__=activate_this)) # enable demandloading to reduce startup time from mercurial import demandimport; demandimport.enable() from mercurial.hgweb import hgweb application = hgweb(config)
配置文件 /var/www/hgweb/hgweb.conf:
[paths] # mysite = /var/www/hgweb/repos/mysite / = /var/www/hgweb/repos/* [web] baseurl = /hg encoding = "UTF-8" allow_archive = bz2 gz zip descend = True collapse = True allow_push = * push_ssl = False
创建仓库路径:
cd /var/www/hgweb/ mkdir repos chown -R daemon:daemon repos cd repos hg init mysite chown -R daemon:daemon mysite
注解
本例中, 需要设置拥有者为 daemon:daemon, 而不是 apache:apache. 若 httpd 为 centos 6 仓库中安装的, 则拥有者设置为 apache:apache.
Httpd 配置:
WSGIScriptReloading On WSGIDaemonProcess hgweb threads=5 display-name=%{GROUP} WSGIScriptAlias /hg /var/www/hgweb/hgweb.wsgi WSGIProcessGroup hgweb <Location /hg> AuthType Basic AuthName "Mercurial repositories" AuthUserFile /var/www/hgweb/hgweb_users <LimitExcept GET> Require valid-user # Require user digwtx </LimitExcept> # Require valid-user </Location>
注解
若要做成私有仓库, 则把 LimitExcept 段注释掉; 把下面那行 # Require valid-user 前面的 # 去掉.
用户认证文件的操作:
htpasswd -c /var/www/hgweb/hgweb_users digwtx # 创建文件和用户 htpasswd /var/www/hgweb/hgweb_users digwtx01 # 追加用户, 或修改密码