生成第一个[变更]
完成了教程-历史 的学习之后, 我们来到 my-hello [仓库]里面,就是我们在 教程-克隆中 [克隆] 得到的。
在 Mercurial 开发实践中一个好的做法是把每个变更隔离在各自的仓库里。这样可以避免把不相关的代码混杂起来, 并且便于一个接一个的测试每一部分工作。我们现在就开始采用这一模式。
我们的目标很简单,让“hello, world”程序打印另外一行输出。 首先, 我们给这个小项目创建一个新的仓库叫做 my-hello-new-output,方法是对my-hello做克隆。
$ cd .. $ hg clone my-hello my-hello-new-output
updating to branch default 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
注: 注意我们给新的 仓库 命名了一个描述性 的名字,基本上是说明这个仓库的目的。 在Mercurial里面给一个仓库创建[克隆]很方便,我们会很快的积攒起很多稍微不同的仓库。如果我们不给他们描述性的命名, 很快就会没法分辨它们。
现在可以在新的仓库里面进行修改了 。 我们进入工作目录,使用我们喜欢的编辑软件修改源文件。
$ cd my-hello-new-output * Placed in the public domain by Bryan O'Sullivan * * This program is not covered by patents in the United States or other * countries. */ #include <stdio.h> int main(int argc, char **argv) { printf("hello, world!\n"); return 0; }
我们要修改 main 让它再多打印一行输出:
function isnumbered(obj) {
return obj.childNodes.length && obj.firstChild.childNodes.length && obj.firstChild.firstChild.className == 'LineNumber';
}
function nformat(num,chrs,add) {
var nlen = Math.max(0,chrs-(''+num).length), res = '';
while (nlen>0) { res += ' '; nlen-- }
return res+num+add;
}
function addnumber(did, nstart, nstep) {
var c = document.getElementById(did), l = c.firstChild, n = 1;
if (!isnumbered(c)) {
if (typeof nstart == 'undefined') nstart = 1;
if (typeof nstep == 'undefined') nstep = 1;
var n = nstart;
while (l != null) {
if (l.tagName == 'SPAN') {
var s = document.createElement('SPAN');
var a = document.createElement('A');
s.className = 'LineNumber';
a.appendChild(document.createTextNode(nformat(n,4,'')));
a.href = '#' + did + '_' + n;
s.appendChild(a);
s.appendChild(document.createTextNode(' '));
n += nstep;
if (l.childNodes.length) {
l.insertBefore(s, l.firstChild);
}
else {
l.appendChild(s);
}
}
l = l.nextSibling;
}
}
return false;
}
function remnumber(did) {
var c = document.getElementById(did), l = c.firstChild;
if (isnumbered(c)) {
while (l != null) {
if (l.tagName == 'SPAN' && l.firstChild.className == 'LineNumber') l.removeChild(l.firstChild);
l = l.nextSibling;
}
}
return false;
}
function togglenumber(did, nstart, nstep) {
var c = document.getElementById(did);
if (isnumbered(c)) {
remnumber(did);
} else {
addnumber(did,nstart,nstep);
}
return false;
}
document.write('Revert")。
$ hg revert hello.c
revert重命名被编辑文件hello.c为hello.c.orig并恢复hello.c到它的未编辑状态。 status命令现在会将hello.c.orig视为不被追踪的(以"?"为前缀)。
$ hg st ? hello.c.orig
如果我们又改变主意想要重用我们做的修改,我们只需要移除未编辑状态的hello.c然后重命名我们改过的hello.c.orig为hello.c
$ rm hello.c $ mv hello.c.orig hello.c $ hg st M hello.c
创建一个变更集的动作称为Commit"它。我们用commit命令来执行Commit"。
$ hg commit
这个命令把我们带到一个编辑器内,同时给我们展示了几行语焉不详的文字。
注: 缺省的编辑器是vi。这可以用环境变量EDITOR 或 HGEDITOR 来改变。同样,根据你怎样输入和保存文件,变更集记录哈希表可能不一样。
HG: Enter commit message. Lines beginning with 'HG:' are removed. HG: -- HG: user: mpm@selenic.com HG: branch 'default' HG: changed hello.c
第一行是空的,接下来的几行标明用户,分支名和哪些文件将进入本变更集。
默认的分支名是 "default" (参见NamedBranches). "user"的默认值来自于~/.hgrc配置文件UI段下"username"属性的值(参见Commit"变更集,我们必须描述它的原因(参见变更集注释)。让我们输入一些:
Express great joy at existence of Mercurial HG: Enter commit message. Lines beginning with 'HG:' are removed. HG: -- HG: user: mpm@selenic.com HG: branch 'default' HG: changed hello.c
接着,我保存测试并退出编辑器,如果一切正常,commit命令将没有任何提示地退出。
如果你在没有保存文本的情况下退出编辑器,commit 将中断操作,这样你可以在提交前改变你的想法。
让我们看看status命令现在告诉我们什么?
$ hg status
什么也没有!我们的变更已经Commit"到变更集里了,那里没有修改的文件需要提交的。我们的Tip"现在和我们工作目录的内容一致了。
Parent"命令向我们展示我们的仓库的工作路径现在与新提交的变更集同步了 (参见Update") (这里,我们只有一个父修订版, 它即是每次提交之后的修订版。我们将在TutorialMerge里看到两个父修订版的情况):
$ hg par changeset: 2:86794f718fb1 tag: tip user: mpm@selenic.com date: Mon May 05 01:20:46 2008 +0200 summary: Express great joy at existence of Mercurial
就是它了!我们已经Commit"了一个变更集。
我们现在可以为我们的新工作检查变更的历史:
$ hg log changeset: 2:86794f718fb1 tag: tip user: mpm@selenic.com date: Mon May 05 01:20:46 2008 +0200 summary: Express great joy at existence of Mercurial (...)
注: 用户,日期和变更集号当然和我的是不一样的。
正如我们在教程--复制中讨论的,新的变更集只存在于本仓库中。 这是Mercurial关键的一部分工作方法。