# # Simplified Chinese translation for hgbook # This file is distributed under the same license as the hgbook. # # Authors: # Dongsheng Song , 2009 # # Check translation: # msgfmt --statistics -c -o zh.mo zh.po # # Please format your translation before commit: # msgcat --sort-by-file --width=80 -o zh_new.po zh.po # mv -f zh_new.po zh.po # # Dictionary: # blame 追溯 # branch 分支 # changes 修改 # changeset 修改集 # checkout 检出 # remove 移除(从版本库删除) # delete 删除(只从文件系统删除) # filelog 文件日志 # patchset 补丁集 # pushing to 推到 # pulling from 拉自,抓取 # rename 改名 # repository 版本库 # revert 恢复 # revision 版本 # revlog 版本日志 # tag 标签 # tip 顶点 # undo 撤销 # unversioned 未版本控制 # updated 更新到,同步到(适用于旧版本) # versioned 受版本控制 # working copy 工作副本 # identifiers 标识符 # ... # msgid "" msgstr "" "Project-Id-Version: hgbook 1.2\n" "POT-Creation-Date: 2009-11-04 14:06+0800\n" "PO-Revision-Date: 2009-10-21 16:42+0800\n" "Last-Translator: 宋冬生 \n" "Language-Team: Simplified Chinese \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Language: Chinese\n" "X-Poedit-Country: CHINA\n" "X-Poedit-SourceCharset: utf-8\n" #. type: Content of: #: ../en/00book.xml:42 msgid "Mercurial: The Definitive Guide" msgstr "Mercurial 权威指南" #. type: Content of: <book><subtitle> #: ../en/00book.xml:47 msgid "Compiled from $rev_id$" msgstr "编译自 $rev_id$" #. type: Content of: <book><bookinfo> #: ../en/00book.xml:49 msgid "<edition>1</edition> <isbn>9780596800673</isbn>" msgstr "<edition>1</edition> <isbn>9780596800673</isbn>" #. type: Content of: <book><bookinfo><authorgroup><author><firstname> #: ../en/00book.xml:53 msgid "Bryan" msgstr "Bryan" #. type: Content of: <book><bookinfo><authorgroup><author><surname> #: ../en/00book.xml:54 msgid "O'Sullivan" msgstr "O'Sullivan" #. type: Content of: <book><bookinfo> #: ../en/00book.xml:58 msgid "" "<editor> <firstname>Mike</firstname> <surname>Loukides</surname> </editor> " "<copyright> <year>2006</year> <year>2007</year> <year>2008</year> <year>2009</" "year> <holder>Bryan O'Sullivan</holder> </copyright>" msgstr "" "<editor> <firstname>Mike</firstname> <surname>Loukides</surname> </editor> " "<copyright> <year>2006</year> <year>2007</year> <year>2008</year> <year>2009</" "year> <holder>Bryan O'Sullivan</holder> </copyright>" #. type: Content of: <book><appendix><title> #: ../en/appA-svn.xml:5 msgid "Migrating to Mercurial" msgstr "迁移到 Mercurial" #. type: Content of: <book><appendix><para> #: ../en/appA-svn.xml:7 msgid "" "A common way to test the waters with a new revision control tool is to " "experiment with switching an existing project, rather than starting a new " "project from scratch." msgstr "" #. type: Content of: <book><appendix><para> #: ../en/appA-svn.xml:11 msgid "" "In this appendix, we discuss how to import a project's history into " "Mercurial, and what to look out for if you are used to a different revision " "control system." msgstr "" #. type: Content of: <book><appendix><sect1><title> #: ../en/appA-svn.xml:16 msgid "Importing history from another system" msgstr "从其它版本控制系统导入历史" #. type: Content of: <book><appendix><sect1><para> #: ../en/appA-svn.xml:18 msgid "" "Mercurial ships with an extension named <literal>convert</literal>, which can " "import project history from most popular revision control systems. At the " "time this book was written, it could import history from the following " "systems:" msgstr "" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><thead><row><entry> #: ../en/appA-svn.xml:25 ../en/appA-svn.xml:369 ../en/ch01-intro.xml:416 #: ../en/ch01-intro.xml:627 msgid "Subversion" msgstr "Subversion" #. type: Content of: <book><appendix><sect1><itemizedlist><listitem><para> #: ../en/appA-svn.xml:28 ../en/ch01-intro.xml:532 ../en/ch01-intro.xml:628 msgid "CVS" msgstr "CVS" #. type: Content of: <book><appendix><sect1><itemizedlist><listitem><para> #: ../en/appA-svn.xml:31 msgid "git" msgstr "git" #. type: Content of: <book><appendix><sect1><itemizedlist><listitem><para> #: ../en/appA-svn.xml:34 ../en/ch01-intro.xml:630 msgid "Darcs" msgstr "Darcs" #. type: Content of: <book><appendix><sect1><itemizedlist><listitem><para> #: ../en/appA-svn.xml:37 msgid "Bazaar" msgstr "Bazaar" #. type: Content of: <book><appendix><sect1><itemizedlist><listitem><para> #: ../en/appA-svn.xml:40 msgid "Monotone" msgstr "Monotone" #. type: Content of: <book><appendix><sect1><itemizedlist><listitem><para> #: ../en/appA-svn.xml:43 msgid "GNU Arch" msgstr "GNU Arch" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><thead><row><entry> #: ../en/appA-svn.xml:46 ../en/appA-svn.xml:370 msgid "Mercurial" msgstr "Mercurial" #. type: Content of: <book><appendix><sect1><para> #: ../en/appA-svn.xml:50 msgid "" "(To see why Mercurial itself is supported as a source, see <xref linkend=" "\"svn.filemap\"/>.)" msgstr "" #. type: Content of: <book><appendix><sect1><para> #: ../en/appA-svn.xml:53 msgid "" "You can enable the extension in the usual way, by editing your <filename>~/." "hgrc</filename> file." msgstr "" "你可以通过常用的方式,编辑<filename>~./hgrc</filename>文件来使用这个扩展。" #. type: Content of: <book><appendix><sect1><para> #: ../en/appA-svn.xml:59 msgid "" "This will make a <command>hg convert</command> command available. The " "command is easy to use. For instance, this command will import the " "Subversion history for the Nose unit testing framework into Mercurial." msgstr "" #. type: Content of: <book><appendix><sect1><screen><prompt> #: ../en/appA-svn.xml:64 ../en/appA-svn.xml:207 ../en/appA-svn.xml:212 #: ../en/appA-svn.xml:213 ../en/appA-svn.xml:218 ../en/appA-svn.xml:224 #: ../en/appA-svn.xml:229 ../en/appA-svn.xml:532 msgid "$" msgstr "$" #. type: Content of: <book><appendix><sect1><screen><userinput> #: ../en/appA-svn.xml:64 msgid "hg convert http://python-nose.googlecode.com/svn/trunk" msgstr "" #. type: Content of: <book><appendix><sect1><para> #: ../en/appA-svn.xml:66 msgid "" "The <literal>convert</literal> extension operates incrementally. In other " "words, after you have run <command>hg convert</command> once, running it " "again will import any new revisions committed after the first run began. " "Incremental conversion will only work if you run <command>hg convert</" "command> in the same Mercurial repository that you originally used, because " "the <literal>convert</literal> extension saves some private metadata in a non-" "revision-controlled file named <filename>.hg/shamap</filename> inside the " "target repository." msgstr "" #. type: Content of: <book><appendix><sect1><para> #: ../en/appA-svn.xml:78 msgid "" "When you want to start making changes using Mercurial, it's best to clone the " "tree in which you are doing your conversions, and leave the original tree for " "future incremental conversions. This is the safest way to let you pull and " "merge future commits from the source revision control system into your newly " "active Mercurial project." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><title> #: ../en/appA-svn.xml:86 msgid "Converting multiple branches" msgstr "转换多个分支" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appA-svn.xml:88 msgid "" "The <command>hg convert</command> command given above converts only the " "history of the <literal>trunk</literal> branch of the Subversion repository. " "If we instead use the URL <literal>http://python-nose.googlecode.com/svn</" "literal>, Mercurial will automatically detect the <literal>trunk</literal>, " "<literal>tags</literal> and <literal>branches</literal> layout that " "Subversion projects usually use, and it will import each as a separate " "Mercurial branch." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appA-svn.xml:98 msgid "" "By default, each Subversion branch imported into Mercurial is given a branch " "name. After the conversion completes, you can get a list of the active " "branch names in the Mercurial repository using <command>hg branches -a</" "command>. If you would prefer to import the Subversion branches without " "names, pass the <option>--config convert.hg.usebranchnames=false</option> " "option to <command>hg convert</command>." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appA-svn.xml:107 msgid "" "Once you have converted your tree, if you want to follow the usual Mercurial " "practice of working in a tree that contains a single branch, you can clone " "that single branch using <command>hg clone -r mybranchname</command>." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><title> #: ../en/appA-svn.xml:114 msgid "Mapping user names" msgstr "映射用户名称" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appA-svn.xml:116 msgid "" "Some revision control tools save only short usernames with commits, and these " "can be difficult to interpret. The norm with Mercurial is to save a " "committer's name and email address, which is much more useful for talking to " "them after the fact." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appA-svn.xml:122 msgid "" "If you are converting a tree from a revision control system that uses short " "names, you can map those names to longer equivalents by passing a <option>--" "authors</option> option to <command>hg convert</command>. This option " "accepts a file name that should contain entries of the following form." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appA-svn.xml:132 msgid "" "Whenever <literal>convert</literal> encounters a commit with the username " "<literal>arist</literal> in the source repository, it will use the name " "<literal>Aristotle <aristotle@phil.example.gr></literal> in the " "converted Mercurial revision. If no match is found for a name, it is used " "verbatim." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><title> #: ../en/appA-svn.xml:141 msgid "Tidying up the tree" msgstr "清理目录树" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appA-svn.xml:143 msgid "" "Not all projects have pristine history. There may be a directory that should " "never have been checked in, a file that is too big, or a whole hierarchy that " "needs to be refactored." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appA-svn.xml:148 msgid "" "The <literal>convert</literal> extension supports the idea of a <quote>file " "map</quote> that can reorganize the files and directories in a project as it " "imports the project's history. This is useful not only when importing " "history from other revision control systems, but also to prune or refactor a " "Mercurial tree." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appA-svn.xml:155 msgid "" "To specify a file map, use the <option>--filemap</option> option and supply a " "file name. A file map contains lines of the following forms." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appA-svn.xml:169 msgid "" "The <literal>include</literal> directive causes a file, or all files under a " "directory, to be included in the destination repository. This also excludes " "all other files and dirs not explicitely included. The <literal>exclude</" "literal> directive causes files or directories to be omitted, and others not " "explicitly mentioned to be included." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appA-svn.xml:176 msgid "" "To move a file or directory from one location to another, use the " "<literal>rename</literal> directive. If you need to move a file or directory " "from a subdirectory into the root of the repository, use <literal>.</literal> " "as the second argument to the <literal>rename</literal> directive." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><title> #: ../en/appA-svn.xml:184 msgid "Improving Subversion conversion performance" msgstr "改进 Subversion 的转换性能" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appA-svn.xml:186 msgid "" "You will often need several attempts before you hit the perfect combination " "of user map, file map, and other conversion parameters. Converting a " "Subversion repository over an access protocol like <literal>ssh</literal> or " "<literal>http</literal> can proceed thousands of times more slowly than " "Mercurial is capable of actually operating, due to network delays. This can " "make tuning that perfect conversion recipe very painful." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appA-svn.xml:195 msgid "" "The <ulink url=\"http://svn.collab.net/repos/svn/trunk/notes/svnsync.txt" "\"><command>svnsync</command></ulink> command can greatly speed up the " "conversion of a Subversion repository. It is a read-only mirroring program " "for Subversion repositories. The idea is that you create a local mirror of " "your Subversion tree, then convert the mirror into a Mercurial repository." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appA-svn.xml:203 msgid "" "Suppose we want to convert the Subversion repository for the popular " "Memcached project into a Mercurial tree. First, we create a local Subversion " "repository." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><screen><userinput> #: ../en/appA-svn.xml:207 msgid "svnadmin create memcached-mirror" msgstr "svnadmin create memcached-mirror" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appA-svn.xml:209 msgid "Next, we set up a Subversion hook that <command>svnsync</command> needs." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><screen><userinput> #: ../en/appA-svn.xml:212 msgid "echo '#!/bin/sh' > memcached-mirror/hooks/pre-revprop-change" msgstr "echo '#!/bin/sh' > memcached-mirror/hooks/pre-revprop-change" #. type: Content of: <book><appendix><sect1><sect2><screen><userinput> #: ../en/appA-svn.xml:213 msgid "chmod +x memcached-mirror/hooks/pre-revprop-change" msgstr "chmod +x memcached-mirror/hooks/pre-revprop-change" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appA-svn.xml:215 msgid "We then initialize <command>svnsync</command> in this repository." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><screen><userinput> #: ../en/appA-svn.xml:218 msgid "" "svnsync --init file://`pwd`/memcached-mirror \\ http://code.sixapart.com/svn/" "memcached" msgstr "" "svnsync --init file://`pwd`/memcached-mirror \\ http://code.sixapart.com/svn/" "memcached" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appA-svn.xml:221 msgid "" "Our next step is to begin the <command>svnsync</command> mirroring process." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><screen><userinput> #: ../en/appA-svn.xml:224 msgid "svnsync sync file://`pwd`/memcached-mirror" msgstr "svnsync sync file://`pwd`/memcached-mirror" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appA-svn.xml:226 msgid "" "Finally, we import the history of our local Subversion mirror into Mercurial." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><screen><userinput> #: ../en/appA-svn.xml:229 msgid "hg convert memcached-mirror" msgstr "" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appA-svn.xml:231 msgid "" "We can use this process incrementally if the Subversion repository is still " "in use. We run <command>svnsync</command> to pull new changes into our " "mirror, then <command>hg convert</command> to import them into our Mercurial " "tree." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appA-svn.xml:237 msgid "" "There are two advantages to doing a two-stage import with <command>svnsync</" "command>. The first is that it uses more efficient Subversion network " "syncing code than <command>hg convert</command>, so it transfers less data " "over the network. The second is that the import from a local Subversion tree " "is so fast that you can tweak your conversion setup repeatedly without having " "to sit through a painfully slow network-based conversion process each time." msgstr "" #. type: Content of: <book><appendix><sect1><title> #: ../en/appA-svn.xml:249 msgid "Migrating from Subversion" msgstr "从 Subversion 迁移" #. type: Content of: <book><appendix><sect1><para> #: ../en/appA-svn.xml:251 msgid "" "Subversion is currently the most popular open source revision control system. " "Although there are many differences between Mercurial and Subversion, making " "the transition from Subversion to Mercurial is not particularly difficult. " "The two have similar command sets and generally uniform interfaces." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><title> #: ../en/appA-svn.xml:259 msgid "Philosophical differences" msgstr "哲学的差别" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appA-svn.xml:261 msgid "" "The fundamental difference between Subversion and Mercurial is of course that " "Subversion is centralized, while Mercurial is distributed. Since Mercurial " "stores all of a project's history on your local drive, it only needs to " "perform a network access when you want to explicitly communicate with another " "repository. In contrast, Subversion stores very little information locally, " "and the client must thus contact its server for many common operations." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appA-svn.xml:270 msgid "" "Subversion more or less gets away without a well-defined notion of a branch: " "which portion of a server's namespace qualifies as a branch is a matter of " "convention, with the software providing no enforcement. Mercurial treats a " "repository as the unit of branch management." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><sect3><title> #: ../en/appA-svn.xml:277 msgid "Scope of commands" msgstr "命令作用域" #. type: Content of: <book><appendix><sect1><sect2><sect3><para> #: ../en/appA-svn.xml:279 msgid "" "Since Subversion doesn't know what parts of its namespace are really " "branches, it treats most commands as requests to operate at and below " "whatever directory you are currently visiting. For instance, if you run " "<command>svn log</command>, you'll get the history of whatever part of the " "tree you're looking at, not the tree as a whole." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><sect3><para> #: ../en/appA-svn.xml:286 msgid "" "Mercurial's commands behave differently, by defaulting to operating over an " "entire repository. Run <command>hg log</command> and it will tell you the " "history of the entire tree, no matter what part of the working directory " "you're visiting at the time. If you want the history of just a particular " "file or directory, simply supply it by name, e.g. <command>hg log src</" "command>." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><sect3><para> #: ../en/appA-svn.xml:294 msgid "" "From my own experience, this difference in default behaviors is probably the " "most likely to trip you up if you have to switch back and forth frequently " "between the two tools." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><sect3><title> #: ../en/appA-svn.xml:301 msgid "Multi-user operation and safety" msgstr "多用户操作与安全" #. type: Content of: <book><appendix><sect1><sect2><sect3><para> #: ../en/appA-svn.xml:303 msgid "" "With Subversion, it is normal (though slightly frowned upon) for multiple " "people to collaborate in a single branch. If Alice and Bob are working " "together, and Alice commits some changes to their shared branch, Bob must " "update his client's view of the branch before he can commit. Since at this " "time he has no permanent record of the changes he has made, he can corrupt or " "lose his modifications during and after his update." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><sect3><para> #: ../en/appA-svn.xml:312 msgid "" "Mercurial encourages a commit-then-merge model instead. Bob commits his " "changes locally before pulling changes from, or pushing them to, the server " "that he shares with Alice. If Alice pushed her changes before Bob tries to " "push his, he will not be able to push his changes until he pulls hers, merges " "with them, and commits the result of the merge. If he makes a mistake during " "the merge, he still has the option of reverting to the commit that recorded " "his changes." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><sect3><para> #: ../en/appA-svn.xml:321 msgid "" "It is worth emphasizing that these are the common ways of working with these " "tools. Subversion supports a safer work-in-your-own-branch model, but it is " "cumbersome enough in practice to not be widely used. Mercurial can support " "the less safe mode of allowing changes to be pulled in and merged on top of " "uncommitted edits, but this is considered highly unusual." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><sect3><title> #: ../en/appA-svn.xml:331 msgid "Published vs local changes" msgstr "已发布的修改与本地修改" #. type: Content of: <book><appendix><sect1><sect2><sect3><para> #: ../en/appA-svn.xml:333 msgid "" "A Subversion <command>svn commit</command> command immediately publishes " "changes to a server, where they can be seen by everyone who has read access." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><sect3><para> #: ../en/appA-svn.xml:337 msgid "" "With Mercurial, commits are always local, and must be published via a " "<command>hg push</command> command afterwards." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><sect3><para> #: ../en/appA-svn.xml:341 msgid "" "Each approach has its advantages and disadvantages. The Subversion model " "means that changes are published, and hence reviewable and usable, " "immediately. On the other hand, this means that a user must have commit " "access to a repository in order to use the software in a normal way, and " "commit access is not lightly given out by most open source projects." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><sect3><para> #: ../en/appA-svn.xml:349 msgid "" "The Mercurial approach allows anyone who can clone a repository to commit " "changes without the need for someone else's permission, and they can then " "publish their changes and continue to participate however they see fit. The " "distinction between committing and pushing does open up the possibility of " "someone committing changes to their laptop and walking away for a few days " "having forgotten to push them, which in rare cases might leave collaborators " "temporarily stuck." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><title> #: ../en/appA-svn.xml:362 msgid "Quick reference" msgstr "快速参考" #. type: Content of: <book><appendix><sect1><sect2><table><title> #: ../en/appA-svn.xml:365 msgid "Subversion commands and Mercurial equivalents" msgstr "Subversion 命令与 Mercurial 对照表" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><thead><row><entry> #: ../en/appA-svn.xml:371 msgid "Notes" msgstr "备注" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:376 msgid "<command>svn add</command>" msgstr "<command>svn add</command>" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:377 msgid "<command>hg add</command>" msgstr "<command>hg add</command>" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:381 msgid "<command>svn blame</command>" msgstr "<command>svn blame</command>" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:382 msgid "<command>hg annotate</command>" msgstr "<command>hg annotate</command>" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:386 msgid "<command>svn cat</command>" msgstr "<command>svn cat</command>" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:387 msgid "<command>hg cat</command>" msgstr "<command>hg cat</command>" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:391 msgid "<command>svn checkout</command>" msgstr "<command>svn checkout</command>" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:392 ../en/appA-svn.xml:409 msgid "<command>hg clone</command>" msgstr "<command>hg clone</command>" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:396 msgid "<command>svn cleanup</command>" msgstr "<command>svn cleanup</command>" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:397 ../en/appA-svn.xml:472 msgid "n/a" msgstr "n/a" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:398 msgid "No cleanup needed" msgstr "不需要清理" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:401 msgid "<command>svn commit</command>" msgstr "<command>svn commit</command>" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:402 msgid "<command>hg commit</command>; <command>hg push</command>" msgstr "<command>hg commit</command>; <command>hg push</command>" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:404 msgid "<command>hg push</command> publishes after commit" msgstr "提交后使用 <command>hg push</command> 发布" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:408 ../en/appA-svn.xml:413 msgid "<command>svn copy</command>" msgstr "<command>svn copy</command>" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:410 msgid "To create a new branch" msgstr "创建新补丁" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:414 msgid "<command>hg copy</command>" msgstr "<command>hg copy</command>" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:415 msgid "To copy files or directories" msgstr "复制文件或目录" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:418 msgid "<command>svn delete</command> (<command>svn remove</command>)" msgstr "<command>svn delete</command> (<command>svn remove</command>)" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:420 msgid "<command>hg remove</command>" msgstr "<command>hg remove</command>" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:424 msgid "<command>svn diff</command>" msgstr "<command>svn diff</command>" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:425 msgid "<command>hg diff</command>" msgstr "<command>hg diff</command>" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:429 msgid "<command>svn export</command>" msgstr "<command>svn export</command>" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:430 msgid "<command>hg archive</command>" msgstr "<command>hg archive</command>" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:434 msgid "<command>svn help</command>" msgstr "<command>svn help</command>" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:435 msgid "<command>hg help</command>" msgstr "<command>hg help</command>" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:439 msgid "<command>svn import</command>" msgstr "<command>svn import</command>" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:440 msgid "<command>hg addremove</command>; <command>hg commit</command>" msgstr "<command>hg addremove</command>; <command>hg commit</command>" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:445 ../en/appA-svn.xml:450 msgid "<command>svn info</command>" msgstr "<command>svn info</command>" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:446 msgid "<command>hg parents</command>" msgstr "<command>hg parents</command>" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:447 msgid "Shows what revision is checked out" msgstr "显示检出的版本信息" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:451 msgid "<command>hg showconfig paths.parent</command>" msgstr "<command>hg showconfig paths.parent</command>" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:453 msgid "Shows what URL is checked out" msgstr "显示检出的 URL" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:456 msgid "<command>svn list</command>" msgstr "<command>svn list</command>" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:457 msgid "<command>hg manifest</command>" msgstr "<command>hg manifest</command>" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:461 msgid "<command>svn log</command>" msgstr "<command>svn log</command>" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:462 msgid "<command>hg log</command>" msgstr "<command>hg log</command>" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:466 msgid "<command>svn merge</command>" msgstr "" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:467 msgid "<command>hg merge</command>" msgstr "<command>hg merge</command>" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:471 msgid "<command>svn mkdir</command>" msgstr "<command>svn mkdir</command>" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:473 msgid "Mercurial does not track directories" msgstr "Mercurial 不跟踪目录" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:476 msgid "<command>svn move</command> (<command>svn rename</command>)" msgstr "<command>svn move</command> (<command>svn rename</command>)" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:478 msgid "<command>hg rename</command>" msgstr "<command>hg rename</command>" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:482 msgid "<command>svn resolved</command>" msgstr "<command>svn resolved</command>" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:483 msgid "<command>hg resolve -m</command>" msgstr "<command>hg resolve -m</command>" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:487 msgid "<command>svn revert</command>" msgstr "<command>svn revert</command>" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:488 msgid "<command>hg revert</command>" msgstr "<command>hg revert</command>" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:492 msgid "<command>svn status</command>" msgstr "<command>svn status</command>" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:493 msgid "<command>hg status</command>" msgstr "<command>hg status</command>" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:497 msgid "<command>svn update</command>" msgstr "<command>svn update</command>" #. type: Content of: <book><appendix><sect1><sect2><table><tgroup><tbody><row><entry> #: ../en/appA-svn.xml:498 msgid "<command>hg pull -u</command>" msgstr "<command>hg pull -u</command>" #. type: Content of: <book><appendix><sect1><title> #: ../en/appA-svn.xml:508 msgid "Useful tips for newcomers" msgstr "新手需要了解的技巧" #. type: Content of: <book><appendix><sect1><para> #: ../en/appA-svn.xml:510 msgid "" "Under some revision control systems, printing a diff for a single committed " "revision can be painful. For instance, with Subversion, to see what changed " "in revision 104654, you must type <command>svn diff -r104653:104654</" "command>. Mercurial eliminates the need to type the revision ID twice in this " "common case. For a plain diff, <command>hg export 104654</command>. For a log " "message followed by a diff, <command>hg log -r104654 -p</command>." msgstr "" #. type: Content of: <book><appendix><sect1><para> #: ../en/appA-svn.xml:519 msgid "" "When you run <command>hg status</command> without any arguments, it prints " "the status of the entire tree, with paths relative to the root of the " "repository. This makes it tricky to copy a file name from the output of " "<command>hg status</command> into the command line. If you supply a file or " "directory name to <command>hg status</command>, it will print paths relative " "to your current location instead. So to get tree-wide status from " "<command>hg status</command>, with paths that are relative to your current " "directory and not the root of the repository, feed the output of <command>hg " "root</command> into <command>hg status</command>. You can easily do this as " "follows on a Unix-like system:" msgstr "" #. type: Content of: <book><appendix><sect1><screen><userinput> #: ../en/appA-svn.xml:532 msgid "hg status `hg root`" msgstr "hg status `hg root`" #. type: Content of: <book><appendix><title> #: ../en/appB-mq-ref.xml:5 msgid "Mercurial Queues reference" msgstr "Mercurial 队列参考" #. type: Content of: <book><appendix><sect1><title> #: ../en/appB-mq-ref.xml:8 msgid "MQ command reference" msgstr "MQ 命令参考" #. type: Content of: <book><appendix><sect1><para> #: ../en/appB-mq-ref.xml:10 msgid "" "For an overview of the commands provided by MQ, use the command <command role=" "\"hg-cmd\">hg help mq</command>." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><title> #: ../en/appB-mq-ref.xml:14 msgid "" "<command role=\"hg-ext-mq\">qapplied</command>&emdash;print applied patches" msgstr "<command role=\"hg-ext-mq\">qapplied</command>—显示已应用的补丁" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:17 msgid "" "The <command role=\"hg-ext-mq\">qapplied</command> command prints the current " "stack of applied patches. Patches are printed in oldest-to-newest order, so " "the last patch in the list is the <quote>top</quote> patch." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><title> #: ../en/appB-mq-ref.xml:24 msgid "" "<command role=\"hg-ext-mq\">qcommit</command>&emdash;commit changes in the " "queue repository" msgstr "<command role=\"hg-ext-mq\">qcommit</command>—提交队列中的修改" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:27 msgid "" "The <command role=\"hg-ext-mq\">qcommit</command> command commits any " "outstanding changes in the <filename role=\"special\" class=\"directory\">.hg/" "patches</filename> repository. This command only works if the <filename role=" "\"special\" class=\"directory\">.hg/patches</filename> directory is a " "repository, i.e. you created the directory using <command role=\"hg-cmd\">hg " "qinit <option role=\"hg-ext-mq-cmd-qinit-opt\">-c</option></command> or ran " "<command role=\"hg-cmd\">hg init</command> in the directory after running " "<command role=\"hg-ext-mq\">qinit</command>." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:39 msgid "" "This command is shorthand for <command role=\"hg-cmd\">hg commit --cwd .hg/" "patches</command>." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><title> #: ../en/appB-mq-ref.xml:43 msgid "" "<command role=\"hg-ext-mq\">qdelete</command>&emdash;delete a patch from the " "<filename role=\"special\">series</filename> file" msgstr "" "<command role=\"hg-ext-mq\">qdelete</command>—从文件 <filename role=\"special" "\">series</filename> 中删除补丁" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:48 msgid "" "The <command role=\"hg-ext-mq\">qdelete</command> command removes the entry " "for a patch from the <filename role=\"special\">series</filename> file in the " "<filename role=\"special\" class=\"directory\">.hg/patches</filename> " "directory. It does not pop the patch if the patch is already applied. By " "default, it does not delete the patch file; use the <option role=\"hg-ext-mq-" "cmd-qdel-opt\">-f</option> option to do that." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:57 ../en/appB-mq-ref.xml:109 ../en/appB-mq-ref.xml:167 #: ../en/appB-mq-ref.xml:207 ../en/appB-mq-ref.xml:274 #: ../en/appB-mq-ref.xml:345 ../en/appB-mq-ref.xml:414 #: ../en/appB-mq-ref.xml:492 msgid "Options:" msgstr "选项:" #. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> #: ../en/appB-mq-ref.xml:59 msgid "" "<option role=\"hg-ext-mq-cmd-qdel-opt\">-f</option>: Delete the patch file." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><title> #: ../en/appB-mq-ref.xml:66 msgid "" "<command role=\"hg-ext-mq\">qdiff</command>&emdash;print a diff of the " "topmost applied patch" msgstr "<command role=\"hg-ext-mq\">qdiff</command>—显示最新应用补丁的差异" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:69 msgid "" "The <command role=\"hg-ext-mq\">qdiff</command> command prints a diff of the " "topmost applied patch. It is equivalent to <command role=\"hg-cmd\">hg diff -" "r-2:-1</command>." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><title> #: ../en/appB-mq-ref.xml:75 msgid "" "<command role=\"hg-ext-mq\">qfold</command>&emdash;move applied patches into " "repository history" msgstr "" "<command role=\"hg-ext-mq\">qfold</command>&emdash;将已应用的补丁提交到版本库" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:78 msgid "" "The <command>hg qfinish</command> command converts the specified applied " "patches into permanent changes by moving them out of MQ's control so that " "they will be treated as normal repository history." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><title> #: ../en/appB-mq-ref.xml:85 msgid "" "<command role=\"hg-ext-mq\">qfold</command>&emdash;merge (<quote>fold</" "quote>) several patches into one" msgstr "" "<command role=\"hg-ext-mq\">qfold</command>—将多个补丁合并(<quote>折叠</" "quote>)成一个" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:88 msgid "" "The <command role=\"hg-ext-mq\">qfold</command> command merges multiple " "patches into the topmost applied patch, so that the topmost applied patch " "makes the union of all of the changes in the patches in question." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:93 msgid "" "The patches to fold must not be applied; <command role=\"hg-ext-mq\">qfold</" "command> will exit with an error if any is. The order in which patches are " "folded is significant; <command role=\"hg-cmd\">hg qfold a b</command> means " "<quote>apply the current topmost patch, followed by <literal>a</literal>, " "followed by <literal>b</literal></quote>." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:101 msgid "" "The comments from the folded patches are appended to the comments of the " "destination patch, with each block of comments separated by three asterisk " "(<quote><literal>*</literal></quote>) characters. Use the <option role=\"hg-" "ext-mq-cmd-qfold-opt\">-e</option> option to edit the commit message for the " "combined patch/changeset after the folding has completed." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> #: ../en/appB-mq-ref.xml:111 msgid "" "<option role=\"hg-ext-mq-cmd-qfold-opt\">-e</option>: Edit the commit message " "and patch description for the newly folded patch." msgstr "" "<option role=\"hg-ext-mq-cmd-qfold-opt\">-e</option>:为新创建的补丁编辑提交信" "息和补丁说明。" #. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> #: ../en/appB-mq-ref.xml:116 msgid "" "<option role=\"hg-ext-mq-cmd-qfold-opt\">-l</option>: Use the contents of the " "given file as the new commit message and patch description for the folded " "patch." msgstr "" "<option role=\"hg-ext-mq-cmd-qfold-opt\">-l</option>: 使用给定文件的内容作为创" "建补丁新的提交信息和补丁说明。" #. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> #: ../en/appB-mq-ref.xml:121 msgid "" "<option role=\"hg-ext-mq-cmd-qfold-opt\">-m</option>: Use the given text as " "the new commit message and patch description for the folded patch." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><title> #: ../en/appB-mq-ref.xml:129 msgid "" "<command role=\"hg-ext-mq\">qheader</command>&emdash;display the header/" "description of a patch" msgstr "<command role=\"hg-ext-mq\">qheader</command>—显示补丁头部描述" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:133 msgid "" "The <command role=\"hg-ext-mq\">qheader</command> command prints the header, " "or description, of a patch. By default, it prints the header of the topmost " "applied patch. Given an argument, it prints the header of the named patch." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><title> #: ../en/appB-mq-ref.xml:140 msgid "" "<command role=\"hg-ext-mq\">qimport</command>&emdash;import a third-party " "patch into the queue" msgstr "<command role=\"hg-ext-mq\">qimport</command>—将第三方补丁导入队列" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:143 msgid "" "The <command role=\"hg-ext-mq\">qimport</command> command adds an entry for " "an external patch to the <filename role=\"special\">series</filename> file, " "and copies the patch into the <filename role=\"special\" class=\"directory\">." "hg/patches</filename> directory. It adds the entry immediately after the " "topmost applied patch, but does not push the patch." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:151 msgid "" "If the <filename role=\"special\" class=\"directory\">.hg/patches</filename> " "directory is a repository, <command role=\"hg-ext-mq\">qimport</command> " "automatically does an <command role=\"hg-cmd\">hg add</command> of the " "imported patch." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><title> #: ../en/appB-mq-ref.xml:159 msgid "" "<command role=\"hg-ext-mq\">qinit</command>&emdash;prepare a repository to " "work with MQ" msgstr "<command role=\"hg-ext-mq\">qinit</command>—为使用 MQ 配置版本库" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:162 msgid "" "The <command role=\"hg-ext-mq\">qinit</command> command prepares a repository " "to work with MQ. It creates a directory called <filename role=\"special\" " "class=\"directory\">.hg/patches</filename>." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> #: ../en/appB-mq-ref.xml:169 msgid "" "<option role=\"hg-ext-mq-cmd-qinit-opt\">-c</option>: Create <filename role=" "\"special\" class=\"directory\">.hg/patches</filename> as a repository in its " "own right. Also creates a <filename role=\"special\">.hgignore</filename> " "file that will ignore the <filename role=\"special\">status</filename> file." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:179 msgid "" "When the <filename role=\"special\" class=\"directory\">.hg/patches</" "filename> directory is a repository, the <command role=\"hg-ext-mq\">qimport</" "command> and <command role=\"hg-ext-mq\">qnew</command> commands " "automatically <command role=\"hg-cmd\">hg add</command> new patches." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><title> #: ../en/appB-mq-ref.xml:188 msgid "<command role=\"hg-ext-mq\">qnew</command>&emdash;create a new patch" msgstr "<command role=\"hg-ext-mq\">qnew</command>—创建新补丁" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:191 msgid "" "The <command role=\"hg-ext-mq\">qnew</command> command creates a new patch. " "It takes one mandatory argument, the name to use for the patch file. The " "newly created patch is created empty by default. It is added to the " "<filename role=\"special\">series</filename> file after the current topmost " "applied patch, and is immediately pushed on top of that patch." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:199 msgid "" "If <command role=\"hg-ext-mq\">qnew</command> finds modified files in the " "working directory, it will refuse to create a new patch unless the <option " "role=\"hg-ext-mq-cmd-qnew-opt\">-f</option> option is used (see below). This " "behavior allows you to <command role=\"hg-ext-mq\">qrefresh</command> your " "topmost applied patch before you apply a new patch on top of it." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> #: ../en/appB-mq-ref.xml:209 msgid "" "<option role=\"hg-ext-mq-cmd-qnew-opt\">-f</option>: Create a new patch if " "the contents of the working directory are modified. Any outstanding " "modifications are added to the newly created patch, so after this command " "completes, the working directory will no longer be modified." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> #: ../en/appB-mq-ref.xml:216 msgid "" "<option role=\"hg-ext-mq-cmd-qnew-opt\">-m</option>: Use the given text as " "the commit message. This text will be stored at the beginning of the patch " "file, before the patch data." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><title> #: ../en/appB-mq-ref.xml:225 msgid "" "<command role=\"hg-ext-mq\">qnext</command>&emdash;print the name of the next " "patch" msgstr "<command role=\"hg-ext-mq\">qnext</command>—显示下个补丁的名称" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:228 msgid "" "The <command role=\"hg-ext-mq\">qnext</command> command prints the name name " "of the next patch in the <filename role=\"special\">series</filename> file " "after the topmost applied patch. This patch will become the topmost applied " "patch if you run <command role=\"hg-ext-mq\">qpush</command>." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><title> #: ../en/appB-mq-ref.xml:237 msgid "" "<command role=\"hg-ext-mq\">qpop</command>&emdash;pop patches off the stack" msgstr "<command role=\"hg-ext-mq\">qpop</command>—删除堆栈顶部的补丁" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:240 msgid "" "The <command role=\"hg-ext-mq\">qpop</command> command removes applied " "patches from the top of the stack of applied patches. By default, it removes " "only one patch." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:244 msgid "" "This command removes the changesets that represent the popped patches from " "the repository, and updates the working directory to undo the effects of the " "patches." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:248 msgid "" "This command takes an optional argument, which it uses as the name or index " "of the patch to pop to. If given a name, it will pop patches until the named " "patch is the topmost applied patch. If given a number, <command role=\"hg-" "ext-mq\">qpop</command> treats the number as an index into the entries in the " "series file, counting from zero (empty lines and lines containing only " "comments do not count). It pops patches until the patch identified by the " "given index is the topmost applied patch." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:258 msgid "" "The <command role=\"hg-ext-mq\">qpop</command> command does not read or write " "patches or the <filename role=\"special\">series</filename> file. It is thus " "safe to <command role=\"hg-ext-mq\">qpop</command> a patch that you have " "removed from the <filename role=\"special\">series</filename> file, or a " "patch that you have renamed or deleted entirely. In the latter two cases, " "use the name of the patch as it was when you applied it." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:267 msgid "" "By default, the <command role=\"hg-ext-mq\">qpop</command> command will not " "pop any patches if the working directory has been modified. You can override " "this behavior using the <option role=\"hg-ext-mq-cmd-qpop-opt\">-f</option> " "option, which reverts all modifications in the working directory." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> #: ../en/appB-mq-ref.xml:276 msgid "" "<option role=\"hg-ext-mq-cmd-qpop-opt\">-a</option>: Pop all applied " "patches. This returns the repository to its state before you applied any " "patches." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> #: ../en/appB-mq-ref.xml:281 msgid "" "<option role=\"hg-ext-mq-cmd-qpop-opt\">-f</option>: Forcibly revert any " "modifications to the working directory when popping." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> #: ../en/appB-mq-ref.xml:286 msgid "" "<option role=\"hg-ext-mq-cmd-qpop-opt\">-n</option>: Pop a patch from the " "named queue." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:291 msgid "" "The <command role=\"hg-ext-mq\">qpop</command> command removes one line from " "the end of the <filename role=\"special\">status</filename> file for each " "patch that it pops." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><title> #: ../en/appB-mq-ref.xml:298 msgid "" "<command role=\"hg-ext-mq\">qprev</command>&emdash;print the name of the " "previous patch" msgstr "<command role=\"hg-ext-mq\">qprev</command>—显示上个补丁的名称" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:301 msgid "" "The <command role=\"hg-ext-mq\">qprev</command> command prints the name of " "the patch in the <filename role=\"special\">series</filename> file that comes " "before the topmost applied patch. This will become the topmost applied patch " "if you run <command role=\"hg-ext-mq\">qpop</command>." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><title> #: ../en/appB-mq-ref.xml:310 msgid "" "<command role=\"hg-ext-mq\">qpush</command>&emdash;push patches onto the stack" msgstr "<command role=\"hg-ext-mq\">qpush</command>—增加补丁到堆栈" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:313 msgid "" "The <command role=\"hg-ext-mq\">qpush</command> command adds patches onto the " "applied stack. By default, it adds only one patch." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:317 msgid "" "This command creates a new changeset to represent each applied patch, and " "updates the working directory to apply the effects of the patches." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:321 msgid "The default data used when creating a changeset are as follows:" msgstr "" #. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> #: ../en/appB-mq-ref.xml:324 msgid "" "The commit date and time zone are the current date and time zone. Because " "these data are used to compute the identity of a changeset, this means that " "if you <command role=\"hg-ext-mq\">qpop</command> a patch and <command role=" "\"hg-ext-mq\">qpush</command> it again, the changeset that you push will have " "a different identity than the changeset you popped." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> #: ../en/appB-mq-ref.xml:332 msgid "" "The author is the same as the default used by the <command role=\"hg-cmd\">hg " "commit</command> command." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> #: ../en/appB-mq-ref.xml:336 msgid "" "The commit message is any text from the patch file that comes before the " "first diff header. If there is no such text, a default commit message is " "used that identifies the name of the patch." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:341 msgid "" "If a patch contains a Mercurial patch header, the information in the patch " "header overrides these defaults." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> #: ../en/appB-mq-ref.xml:347 msgid "" "<option role=\"hg-ext-mq-cmd-qpush-opt\">-a</option>: Push all unapplied " "patches from the <filename role=\"special\">series</filename> file until " "there are none left to push." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> #: ../en/appB-mq-ref.xml:353 msgid "" "<option role=\"hg-ext-mq-cmd-qpush-opt\">-l</option>: Add the name of the " "patch to the end of the commit message." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> #: ../en/appB-mq-ref.xml:357 msgid "" "<option role=\"hg-ext-mq-cmd-qpush-opt\">-m</option>: If a patch fails to " "apply cleanly, use the entry for the patch in another saved queue to compute " "the parameters for a three-way merge, and perform a three-way merge using the " "normal Mercurial merge machinery. Use the resolution of the merge as the new " "patch content." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> #: ../en/appB-mq-ref.xml:365 msgid "" "<option role=\"hg-ext-mq-cmd-qpush-opt\">-n</option>: Use the named queue if " "merging while pushing." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:370 msgid "" "The <command role=\"hg-ext-mq\">qpush</command> command reads, but does not " "modify, the <filename role=\"special\">series</filename> file. It appends " "one line to the <command role=\"hg-cmd\">hg status</command> file for each " "patch that it pushes." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><title> #: ../en/appB-mq-ref.xml:378 msgid "" "<command role=\"hg-ext-mq\">qrefresh</command>&emdash;update the topmost " "applied patch" msgstr "<command role=\"hg-ext-mq\">qrefresh</command>—更新最新的补丁" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:382 msgid "" "The <command role=\"hg-ext-mq\">qrefresh</command> command updates the " "topmost applied patch. It modifies the patch, removes the old changeset that " "represented the patch, and creates a new changeset to represent the modified " "patch." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:388 msgid "" "The <command role=\"hg-ext-mq\">qrefresh</command> command looks for the " "following modifications:" msgstr "" #. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> #: ../en/appB-mq-ref.xml:391 msgid "" "Changes to the commit message, i.e. the text before the first diff header in " "the patch file, are reflected in the new changeset that represents the patch." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> #: ../en/appB-mq-ref.xml:396 msgid "" "Modifications to tracked files in the working directory are added to the " "patch." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> #: ../en/appB-mq-ref.xml:399 msgid "" "Changes to the files tracked using <command role=\"hg-cmd\">hg add</command>, " "<command role=\"hg-cmd\">hg copy</command>, <command role=\"hg-cmd\">hg " "remove</command>, or <command role=\"hg-cmd\">hg rename</command>. Added " "files and copy and rename destinations are added to the patch, while removed " "files and rename sources are removed." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:408 msgid "" "Even if <command role=\"hg-ext-mq\">qrefresh</command> detects no changes, it " "still recreates the changeset that represents the patch. This causes the " "identity of the changeset to differ from the previous changeset that " "identified the patch." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> #: ../en/appB-mq-ref.xml:416 msgid "" "<option role=\"hg-ext-mq-cmd-qrefresh-opt\">-e</option>: Modify the commit " "and patch description, using the preferred text editor." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> #: ../en/appB-mq-ref.xml:421 msgid "" "<option role=\"hg-ext-mq-cmd-qrefresh-opt\">-m</option>: Modify the commit " "message and patch description, using the given text." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> #: ../en/appB-mq-ref.xml:426 msgid "" "<option role=\"hg-ext-mq-cmd-qrefresh-opt\">-l</option>: Modify the commit " "message and patch description, using text from the given file." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><title> #: ../en/appB-mq-ref.xml:434 msgid "<command role=\"hg-ext-mq\">qrename</command>&emdash;rename a patch" msgstr "<command role=\"hg-ext-mq\">qrename</command>—改名补丁" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:437 msgid "" "The <command role=\"hg-ext-mq\">qrename</command> command renames a patch, " "and changes the entry for the patch in the <filename role=\"special\">series</" "filename> file." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:441 msgid "" "With a single argument, <command role=\"hg-ext-mq\">qrename</command> renames " "the topmost applied patch. With two arguments, it renames its first argument " "to its second." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><title> #: ../en/appB-mq-ref.xml:448 msgid "" "<command role=\"hg-ext-mq\">qseries</command>&emdash;print the entire patch " "series" msgstr "<command role=\"hg-ext-mq\">qseries</command>—显示补丁序列" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:451 msgid "" "The <command role=\"hg-ext-mq\">qseries</command> command prints the entire " "patch series from the <filename role=\"special\">series</filename> file. It " "prints only patch names, not empty lines or comments. It prints in order " "from first to be applied to last." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><title> #: ../en/appB-mq-ref.xml:459 msgid "" "<command role=\"hg-ext-mq\">qtop</command>&emdash;print the name of the " "current patch" msgstr "<command role=\"hg-ext-mq\">qtop</command>—显示当前补丁的名称" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:462 msgid "" "The <command role=\"hg-ext-mq\">qtop</command> prints the name of the topmost " "currently applied patch." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><title> #: ../en/appB-mq-ref.xml:467 msgid "" "<command role=\"hg-ext-mq\">qunapplied</command>&emdash;print patches not yet " "applied" msgstr "<command role=\"hg-ext-mq\">qunapplied</command>—显示尚未应用的补丁" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:471 msgid "" "The <command role=\"hg-ext-mq\">qunapplied</command> command prints the names " "of patches from the <filename role=\"special\">series</filename> file that " "are not yet applied. It prints them in order from the next patch that will " "be pushed to the last." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><title> #: ../en/appB-mq-ref.xml:479 msgid "" "<command role=\"hg-cmd\">hg strip</command>&emdash;remove a revision and " "descendants" msgstr "<command role=\"hg-cmd\">hg strip</command>—删除一个版本及其后继" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:482 msgid "" "The <command role=\"hg-cmd\">hg strip</command> command removes a revision, " "and all of its descendants, from the repository. It undoes the effects of " "the removed revisions from the repository, and updates the working directory " "to the first parent of the removed revision." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:488 msgid "" "The <command role=\"hg-cmd\">hg strip</command> command saves a backup of the " "removed changesets in a bundle, so that they can be reapplied if removed in " "error." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> #: ../en/appB-mq-ref.xml:494 msgid "" "<option role=\"hg-opt-strip\">-b</option>: Save unrelated changesets that are " "intermixed with the stripped changesets in the backup bundle." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> #: ../en/appB-mq-ref.xml:498 msgid "" "<option role=\"hg-opt-strip\">-f</option>: If a branch has multiple heads, " "remove all heads." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><itemizedlist><listitem><para> #: ../en/appB-mq-ref.xml:501 msgid "<option role=\"hg-opt-strip\">-n</option>: Do not save a backup bundle." msgstr "" #. type: Content of: <book><appendix><sect1><title> #: ../en/appB-mq-ref.xml:508 msgid "MQ file reference" msgstr "MQ 文件参考" #. type: Content of: <book><appendix><sect1><sect2><title> #: ../en/appB-mq-ref.xml:511 msgid "The <filename role=\"special\">series</filename> file" msgstr "<filename role=\"special\">序列</filename>文件" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:514 msgid "" "The <filename role=\"special\">series</filename> file contains a list of the " "names of all patches that MQ can apply. It is represented as a list of " "names, with one name saved per line. Leading and trailing white space in " "each line are ignored." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:520 msgid "" "Lines may contain comments. A comment begins with the <quote><literal>#</" "literal></quote> character, and extends to the end of the line. Empty lines, " "and lines that contain only comments, are ignored." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:525 msgid "" "You will often need to edit the <filename role=\"special\">series</filename> " "file by hand, hence the support for comments and empty lines noted above. " "For example, you can comment out a patch temporarily, and <command role=\"hg-" "ext-mq\">qpush</command> will skip over that patch when applying patches. " "You can also change the order in which patches are applied by reordering " "their entries in the <filename role=\"special\">series</filename> file." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:534 msgid "" "Placing the <filename role=\"special\">series</filename> file under revision " "control is also supported; it is a good idea to place all of the patches that " "it refers to under revision control, as well. If you create a patch " "directory using the <option role=\"hg-ext-mq-cmd-qinit-opt\">-c</option> " "option to <command role=\"hg-ext-mq\">qinit</command>, this will be done for " "you automatically." msgstr "" #. type: Content of: <book><appendix><sect1><sect2><title> #: ../en/appB-mq-ref.xml:544 msgid "The <filename role=\"special\">status</filename> file" msgstr "<filename role=\"special\">状态</filename>文件" #. type: Content of: <book><appendix><sect1><sect2><para> #: ../en/appB-mq-ref.xml:547 msgid "" "The <filename role=\"special\">status</filename> file contains the names and " "changeset hashes of all patches that MQ currently has applied. Unlike the " "<filename role=\"special\">series</filename> file, this file is not intended " "for editing. You should not place this file under revision control, or " "modify it in any way. It is used by MQ strictly for internal book-keeping." msgstr "" #. type: Content of: <book><appendix><title> #: ../en/appC-srcinstall.xml:5 msgid "Installing Mercurial from source" msgstr "从源代码安装 Mercurial" #. type: Content of: <book><appendix><sect1><title> #: ../en/appC-srcinstall.xml:8 msgid "On a Unix-like system" msgstr "类 Unix 系统" #. type: Content of: <book><appendix><sect1><para> #: ../en/appC-srcinstall.xml:10 msgid "" "If you are using a Unix-like system that has a sufficiently recent version of " "Python (2.3 or newer) available, it is easy to install Mercurial from source." msgstr "" "如果你使用类 Unix 系统,并且有足够新的 Python (2.3 更新),从源代码安装 " "Mercurial 就很容易了。" #. type: Content of: <book><appendix><sect1><orderedlist><listitem><para> #: ../en/appC-srcinstall.xml:14 msgid "" "Download a recent source tarball from <ulink url=\"http://www.selenic.com/" "mercurial/download\">http://www.selenic.com/mercurial/download</ulink>." msgstr "" "从 <ulink url=\"http://www.selenic.com/mercurial/download\">http://www." "selenic.com/mercurial/download</ulink> 下载最新的源代码。" #. type: Content of: <book><appendix><sect1><orderedlist><listitem><para> #: ../en/appC-srcinstall.xml:17 msgid "Unpack the tarball:" msgstr "解压:" #. type: Content of: <book><appendix><sect1><orderedlist><listitem><para> #: ../en/appC-srcinstall.xml:20 msgid "" "Go into the source directory and run the installer script. This will build " "Mercurial and install it in your home directory." msgstr "进入源代码目录,执行安装教本。这会构建 Mercurial,安装到你的家目录。" #. type: Content of: <book><appendix><sect1><para> #: ../en/appC-srcinstall.xml:27 msgid "" "Once the install finishes, Mercurial will be in the <literal>bin</literal> " "subdirectory of your home directory. Don't forget to make sure that this " "directory is present in your shell's search path." msgstr "" "安装完成后,Mercurial 就位于家目录的 <literal>bin</literal> 子目录。不要忘记将" "这个目录加入到你的可执行文件搜索路径中。" #. type: Content of: <book><appendix><sect1><para> #: ../en/appC-srcinstall.xml:32 msgid "" "You will probably need to set the <envar>PYTHONPATH</envar> environment " "variable so that the Mercurial executable can find the rest of the Mercurial " "packages. For example, on my laptop, I have set it to <literal>/home/bos/lib/" "python</literal>. The exact path that you will need to use depends on how " "Python was built for your system, but should be easy to figure out. If " "you're uncertain, look through the output of the installer script above, and " "see where the contents of the <literal>mercurial</literal> directory were " "installed to." msgstr "" "你可能需要设置环境变量 <envar>PYTHONPATH</envar>,以便 Mercurial 可执行文件能" "找到 Mercurial 包。例如,在我的笔记本电脑中,必须设置为 <literal>/home/bos/" "lib/python</literal>。你需要使用的路径依赖于 Python 的构建方式,这很容易找出" "来。如果你不确定,仔细察看上面的安装脚本输出,检查包含 <literal>mercurial</" "literal> 目录的内容的安装位置。" #. type: Content of: <book><appendix><sect1><title> #: ../en/appC-srcinstall.xml:44 msgid "On Windows" msgstr "Windows 系统" #. type: Content of: <book><appendix><sect1><para> #: ../en/appC-srcinstall.xml:46 msgid "" "Building and installing Mercurial on Windows requires a variety of tools, a " "fair amount of technical knowledge, and considerable patience. I very much " "<emphasis>do not recommend</emphasis> this route if you are a <quote>casual " "user</quote>. Unless you intend to hack on Mercurial, I strongly suggest " "that you use a binary package instead." msgstr "" "在 Windows 中构建和安装 Mercurial 需要各种工具,相当多的技术背景,以及足够的耐" "心。如果你是一个<quote>初级用户</quote>,我<emphasis>很不赞成</emphasis>这个方" "法。我强烈建议你使用二进制安装包,除非你想深入研究 Mercurial 本身。" #. type: Content of: <book><appendix><sect1><para> #: ../en/appC-srcinstall.xml:53 msgid "" "If you are intent on building Mercurial from source on Windows, follow the " "<quote>hard way</quote> directions on the Mercurial wiki at <ulink url=" "\"http://www.selenic.com/mercurial/wiki/index.cgi/WindowsInstall\">http://www." "selenic.com/mercurial/wiki/index.cgi/WindowsInstall</ulink>, and expect the " "process to involve a lot of fiddly work." msgstr "" "If you are intent on building Mercurial from source on Windows, follow the " "<quote>hard way</quote> directions on the Mercurial wiki at <ulink url=" "\"http://www.selenic.com/mercurial/wiki/index.cgi/WindowsInstall\">http://www." "selenic.com/mercurial/wiki/index.cgi/WindowsInstall</ulink>, and expect the " "process to involve a lot of fiddly work." #. type: Content of: <book><appendix><title> #: ../en/appD-license.xml:5 msgid "Open Publication License" msgstr "开放出版协议" #. type: Content of: <book><appendix><para> #: ../en/appD-license.xml:7 msgid "Version 1.0, 8 June 1999" msgstr "版本 1.0,1999 年 6 月 8 日。" #. type: Content of: <book><appendix><sect1><title> #: ../en/appD-license.xml:10 msgid "Requirements on both unmodified and modified versions" msgstr "" #. type: Content of: <book><appendix><sect1><para> #: ../en/appD-license.xml:13 msgid "" "The Open Publication works may be reproduced and distributed in whole or in " "part, in any medium physical or electronic, provided that the terms of this " "license are adhered to, and that this license or an incorporation of it by " "reference (with any options elected by the author(s) and/or publisher) is " "displayed in the reproduction." msgstr "" #. type: Content of: <book><appendix><sect1><para> #: ../en/appD-license.xml:20 msgid "Proper form for an incorporation by reference is as follows:" msgstr "" #. type: Content of: <book><appendix><sect1><blockquote><para> #: ../en/appD-license.xml:24 msgid "" "Copyright (c) <emphasis>year</emphasis> by <emphasis>author's name or " "designee</emphasis>. This material may be distributed only subject to the " "terms and conditions set forth in the Open Publication License, v<emphasis>x." "y</emphasis> or later (the latest version is presently available at <ulink " "url=\"http://www.opencontent.org/openpub/\">http://www.opencontent.org/" "openpub/</ulink>)." msgstr "" #. type: Content of: <book><appendix><sect1><para> #: ../en/appD-license.xml:33 msgid "" "The reference must be immediately followed with any options elected by the " "author(s) and/or publisher of the document (see <xref linkend=\"sec:opl:" "options\"/>)." msgstr "" #. type: Content of: <book><appendix><sect1><para> #: ../en/appD-license.xml:37 msgid "" "Commercial redistribution of Open Publication-licensed material is permitted." msgstr "" #. type: Content of: <book><appendix><sect1><para> #: ../en/appD-license.xml:40 msgid "" "Any publication in standard (paper) book form shall require the citation of " "the original publisher and author. The publisher and author's names shall " "appear on all outer surfaces of the book. On all outer surfaces of the book " "the original publisher's name shall be as large as the title of the work and " "cited as possessive with respect to the title." msgstr "" #. type: Content of: <book><appendix><sect1><title> #: ../en/appD-license.xml:49 msgid "Copyright" msgstr "" #. type: Content of: <book><appendix><sect1><para> #: ../en/appD-license.xml:51 msgid "" "The copyright to each Open Publication is owned by its author(s) or designee." msgstr "" #. type: Content of: <book><appendix><sect1><title> #: ../en/appD-license.xml:56 msgid "Scope of license" msgstr "" #. type: Content of: <book><appendix><sect1><para> #: ../en/appD-license.xml:58 msgid "" "The following license terms apply to all Open Publication works, unless " "otherwise explicitly stated in the document." msgstr "" #. type: Content of: <book><appendix><sect1><para> #: ../en/appD-license.xml:62 msgid "" "Mere aggregation of Open Publication works or a portion of an Open " "Publication work with other works or programs on the same media shall not " "cause this license to apply to those other works. The aggregate work shall " "contain a notice specifying the inclusion of the Open Publication material " "and appropriate copyright notice." msgstr "" #. type: Content of: <book><appendix><sect1><para> #: ../en/appD-license.xml:69 msgid "" "<emphasis role=\"bold\">Severability</emphasis>. If any part of this license " "is found to be unenforceable in any jurisdiction, the remaining portions of " "the license remain in force." msgstr "" #. type: Content of: <book><appendix><sect1><para> #: ../en/appD-license.xml:74 msgid "" "<emphasis role=\"bold\">No warranty</emphasis>. Open Publication works are " "licensed and provided <quote>as is</quote> without warranty of any kind, " "express or implied, including, but not limited to, the implied warranties of " "merchantability and fitness for a particular purpose or a warranty of non-" "infringement." msgstr "" #. type: Content of: <book><appendix><sect1><title> #: ../en/appD-license.xml:83 msgid "Requirements on modified works" msgstr "" #. type: Content of: <book><appendix><sect1><para> #: ../en/appD-license.xml:85 msgid "" "All modified versions of documents covered by this license, including " "translations, anthologies, compilations and partial documents, must meet the " "following requirements:" msgstr "" #. type: Content of: <book><appendix><sect1><orderedlist><listitem><para> #: ../en/appD-license.xml:90 msgid "The modified version must be labeled as such." msgstr "" #. type: Content of: <book><appendix><sect1><orderedlist><listitem><para> #: ../en/appD-license.xml:93 msgid "" "The person making the modifications must be identified and the modifications " "dated." msgstr "" #. type: Content of: <book><appendix><sect1><orderedlist><listitem><para> #: ../en/appD-license.xml:96 msgid "" "Acknowledgement of the original author and publisher if applicable must be " "retained according to normal academic citation practices." msgstr "" #. type: Content of: <book><appendix><sect1><orderedlist><listitem><para> #: ../en/appD-license.xml:100 msgid "The location of the original unmodified document must be identified." msgstr "" #. type: Content of: <book><appendix><sect1><orderedlist><listitem><para> #: ../en/appD-license.xml:103 msgid "" "The original author's (or authors') name(s) may not be used to assert or " "imply endorsement of the resulting document without the original author's (or " "authors') permission." msgstr "" #. type: Content of: <book><appendix><sect1><title> #: ../en/appD-license.xml:111 msgid "Good-practice recommendations" msgstr "" #. type: Content of: <book><appendix><sect1><para> #: ../en/appD-license.xml:113 msgid "" "In addition to the requirements of this license, it is requested from and " "strongly recommended of redistributors that:" msgstr "" #. type: Content of: <book><appendix><sect1><orderedlist><listitem><para> #: ../en/appD-license.xml:118 msgid "" "If you are distributing Open Publication works on hardcopy or CD-ROM, you " "provide email notification to the authors of your intent to redistribute at " "least thirty days before your manuscript or media freeze, to give the authors " "time to provide updated documents. This notification should describe " "modifications, if any, made to the document." msgstr "" #. type: Content of: <book><appendix><sect1><orderedlist><listitem><para> #: ../en/appD-license.xml:125 msgid "" "All substantive modifications (including deletions) be either clearly marked " "up in the document or else described in an attachment to the document." msgstr "" #. type: Content of: <book><appendix><sect1><orderedlist><listitem><para> #: ../en/appD-license.xml:129 msgid "" "Finally, while it is not mandatory under this license, it is considered good " "form to offer a free copy of any hardcopy and CD-ROM expression of an Open " "Publication-licensed work to its author(s)." msgstr "" #. type: Content of: <book><appendix><sect1><title> #: ../en/appD-license.xml:137 msgid "License options" msgstr "" #. type: Content of: <book><appendix><sect1><para> #: ../en/appD-license.xml:139 msgid "" "The author(s) and/or publisher of an Open Publication-licensed document may " "elect certain options by appending language to the reference to or copy of " "the license. These options are considered part of the license instance and " "must be included with the license (or its incorporation by reference) in " "derived works." msgstr "" #. type: Content of: <book><appendix><sect1><orderedlist><listitem><para> #: ../en/appD-license.xml:147 msgid "" "To prohibit distribution of substantively modified versions without the " "explicit permission of the author(s). <quote>Substantive modification</quote> " "is defined as a change to the semantic content of the document, and excludes " "mere changes in format or typographical corrections." msgstr "" #. type: Content of: <book><appendix><sect1><orderedlist><listitem><para> #: ../en/appD-license.xml:154 msgid "" "To accomplish this, add the phrase <quote>Distribution of substantively " "modified versions of this document is prohibited without the explicit " "permission of the copyright holder.</quote> to the license reference or copy." msgstr "" #. type: Content of: <book><appendix><sect1><orderedlist><listitem><para> #: ../en/appD-license.xml:160 msgid "" "To prohibit any publication of this work or derivative works in whole or in " "part in standard (paper) book form for commercial purposes is prohibited " "unless prior permission is obtained from the copyright holder." msgstr "" #. type: Content of: <book><appendix><sect1><orderedlist><listitem><para> #: ../en/appD-license.xml:165 msgid "" "To accomplish this, add the phrase <quote>Distribution of the work or " "derivative of the work in any standard (paper) book form is prohibited unless " "prior permission is obtained from the copyright holder.</quote> to the " "license reference or copy." msgstr "" #. type: Content of: <book><preface><title> #: ../en/ch00-preface.xml:5 msgid "Preface" msgstr "序言" #. type: Content of: <book><preface><sect1><title> #: ../en/ch00-preface.xml:8 msgid "Technical storytelling" msgstr "技术背景" #. type: Content of: <book><preface><sect1><para> #: ../en/ch00-preface.xml:10 msgid "" "A few years ago, when I wanted to explain why I believed that distributed " "revision control is important, the field was then so new that there was " "almost no published literature to refer people to." msgstr "" "数年之前,当我想解释为什么我相信分布式版本控制非常重要的时候,这个领域实在太新" "了,几乎没有公开的文献供人们参考。" #. type: Content of: <book><preface><sect1><para> #: ../en/ch00-preface.xml:15 msgid "" "Although at that time I spent some time working on the internals of Mercurial " "itself, I switched to writing this book because that seemed like the most " "effective way to help the software to reach a wide audience, along with the " "idea that revision control ought to be distributed in nature. I publish the " "book online under a liberal license for the same reason: to get the word out." msgstr "" "虽然在那个时候,我已经在Mercurial的内核上花了一些时间,我转而写这本书是因为我" "发现这可能是帮助软件吸引更多用户,和让大家接受版本控制本质上就应该是分布式的最" "有效的方式,我把这本书在网上以自由许可的方式发布也是基于同样的原因:让大家都了" "解。" #. type: Content of: <book><preface><sect1><para> #: ../en/ch00-preface.xml:23 msgid "" "There's a familiar rhythm to a good software book that closely resembles " "telling a story: What is this thing? Why does it matter? How will it help me? " "How do I use it? In this book, I try to answer those questions for " "distributed revision control in general, and for Mercurial in particular." msgstr "" "一本好的关于软件的书应该和讲故事类似:这是个什么东西?为什么需要它?它会怎样帮" "助我?我怎么使用它?本书中,我会为分布式版本控制回答这些问题,特别是" "Mercurial。" #. type: Content of: <book><preface><sect1><title> #: ../en/ch00-preface.xml:31 msgid "Thank you for supporting Mercurial" msgstr "谢谢你支持 Mercurial" #. type: Content of: <book><preface><sect1><para> #: ../en/ch00-preface.xml:33 msgid "" "By purchasing a copy of this book, you are supporting the continued " "development and freedom of Mercurial in particular, and of open source and " "free software in general. O'Reilly Media and I are donating my royalties on " "the sales of this book to the Software Freedom Conservancy (<ulink url=" "\"http://www.softwarefreedom.org/\">http://www.softwarefreedom.org/</ulink>) " "which provides clerical and legal support to Mercurial and a number of other " "prominent and worthy open source software projects." msgstr "" "通过购买此书,你支持了开源和自由软件的持续发展和自由,特别是Mercurial。" "O'Reilly Media和我将本书的收入捐献给Software Freedom Conservancy (<ulink url=" "\"http://www.softwarefreedom.org/\">http://www.softwarefreedom.org/</ulink>) ," "这个组织为Mercurial和其他一些有潜力和价值的开源软件项目提供了办公和法律支持。" #. type: Content of: <book><preface><sect1><title> #: ../en/ch00-preface.xml:45 msgid "Acknowledgments" msgstr "致谢" #. type: Content of: <book><preface><sect1><para> #: ../en/ch00-preface.xml:47 msgid "" "This book would not exist were it not for the efforts of Matt Mackall, the " "author and project lead of Mercurial. He is ably assisted by hundreds of " "volunteer contributors across the world." msgstr "" "没有Matt Mackall,Mercurial项目的开发者和领导的努力,这本书不可能存在。他得到" "了全球数以百计的志愿者的帮助。" #. type: Content of: <book><preface><sect1><para> #: ../en/ch00-preface.xml:52 msgid "" "My children, Cian and Ruairi, always stood ready to help me to unwind with " "wonderful, madcap little-boy games. I'd also like to thank my ex-wife, " "Shannon, for her support." msgstr "" #. type: Content of: <book><preface><sect1><para> #: ../en/ch00-preface.xml:56 msgid "" "My colleagues and friends provided help and support in innumerable ways. " "This list of people is necessarily very incomplete: Stephen Hahn, Karyn " "Ritter, Bonnie Corwin, James Vasile, Matt Norwood, Eben Moglen, Bradley Kuhn, " "Robert Walsh, Jeremy Fitzhardinge, Rachel Chalmers." msgstr "" "我的同事和朋友以各种方式提供了帮助和支持,这里的名单非常不全:Stephen Hahn, " "Karyn Ritter, Bonnie Corwin, James Vasile, Matt Norwood, Eben Moglen, Bradley " "Kuhn, Robert Walsh, Jeremy Fitzhardinge, Rachel Chalmers." #. type: Content of: <book><preface><sect1><para> #: ../en/ch00-preface.xml:62 msgid "" "I developed this book in the open, posting drafts of chapters to the book web " "site as I completed them. Readers then submitted feedback using a web " "application that I developed. By the time I finished writing the book, more " "than 100 people had submitted comments, an amazing number considering that " "the comment system was live for only about two months towards the end of the " "writing process." msgstr "" "我以开放的方式完成了本书,当我完成各章的草稿后,就将其放在了网上。读者可以使用" "我开发的一个网络程序提交反馈。到我完成本书时,有100多人提交了评论。考虑到评论" "系统是在写作完成之前两个月才开放的,这是一个惊人的数字。" #. type: Content of: <book><preface><sect1><para> #: ../en/ch00-preface.xml:70 msgid "" "I would particularly like to recognize the following people, who between them " "contributed over a third of the total number of comments. I would like to " "thank them for their care and effort in providing so much detailed feedback." msgstr "" "我特别希望认识以下人员,他们中有的人提交了超过总数三分之一的评论。我要感谢他们" "的关心和努力,提供了那么多详细的反馈。" #. type: Content of: <book><preface><sect1><para> #: ../en/ch00-preface.xml:75 msgid "" "Martin Geisler, Damien Cassou, Alexey Bakhirkin, Till Plewe, Dan Himes, Paul " "Sargent, Gokberk Hamurcu, Matthijs van der Vleuten, Michael Chermside, John " "Mulligan, Jordi Fita, Jon Parise." msgstr "" #. type: Content of: <book><preface><sect1><para> #: ../en/ch00-preface.xml:80 msgid "" "I also want to acknowledge the help of the many people who caught errors and " "provided helpful suggestions throughout the book." msgstr "我同样要感谢许多在书中找出错误和提供了有帮助的建议的人。" #. type: Content of: <book><preface><sect1><para> #: ../en/ch00-preface.xml:84 msgid "" "Jeremy W. Sherman, Brian Mearns, Vincent Furia, Iwan Luijks, Billy Edwards, " "Andreas Sliwka, Paweł Sołyga, Eric Hanchrow, Steve Nicolai, Michał Masłowski, " "Kevin Fitch, Johan Holmberg, Hal Wine, Volker Simonis, Thomas P Jakobsen, Ted " "Stresen-Reuter, Stephen Rasku, Raphael Das Gupta, Ned Batchelder, Lou Keeble, " "Li Linxiao, Kao Cardoso Félix, Joseph Wecker, Jon Prescot, Jon Maken, John " "Yeary, Jason Harris, Geoffrey Zheng, Fredrik Jonson, Ed Davies, David " "Zumbrunnen, David Mercer, David Cabana, Ben Karel, Alan Franzoni, Yousry " "Abdallah, Whitney Young, Vinay Sajip, Tom Towle, Tim Ottinger, Thomas " "Schraitle, Tero Saarni, Ted Mielczarek, Svetoslav Agafonkin, Shaun Rowland, " "Rocco Rutte, Polo-Francois Poli, Philip Jenvey, Petr Tesałék, Peter R. " "Annema, Paul Bonser, Olivier Scherler, Olivier Fournier, Nick Parker, Nick " "Fabry, Nicholas Guarracino, Mike Driscoll, Mike Coleman, Mietek Bák, Michael " "Maloney, László Nagy, Kent Johnson, Julio Nobrega, Jord Fita, Jonathan March, " "Jonas Nockert, Jim Tittsler, Jeduan Cornejo Legorreta, Jan Larres, James " "Murphy, Henri Wiechers, Hagen Möbius, Gábor Farkas, Fabien Engels, Evert Rol, " "Evan Willms, Eduardo Felipe Castegnaro, Dennis Decker Jensen, Deniz Dogan, " "David Smith, Daed Lee, Christine Slotty, Charles Merriam, Guillaume Catto, " "Brian Dorsey, Bob Nystrom, Benoit Boissinot, Avi Rosenschein, Andrew Watts, " "Andrew Donkin, Alexey Rodriguez, Ahmed Chaudhary." msgstr "" #. type: Content of: <book><preface><sect1><title> #: ../en/ch00-preface.xml:111 msgid "Conventions Used in This Book" msgstr "本书的约定" #. type: Content of: <book><preface><sect1><para> #: ../en/ch00-preface.xml:113 msgid "The following typographical conventions are used in this book:" msgstr "本书使用如下的印刷约定:" #. type: Content of: <book><preface><sect1><variablelist><varlistentry><term> #: ../en/ch00-preface.xml:118 msgid "Italic" msgstr "斜体" #. type: Content of: <book><preface><sect1><variablelist><varlistentry><listitem><para> #: ../en/ch00-preface.xml:121 msgid "" "Indicates new terms, URLs, email addresses, filenames, and file extensions." msgstr "标识新术语,URL,电子邮件地址,文件名称与扩展名。" #. type: Content of: <book><preface><sect1><variablelist><varlistentry><term> #: ../en/ch00-preface.xml:127 msgid "<literal>Constant width</literal>" msgstr "<literal>等宽</literal>" #. type: Content of: <book><preface><sect1><variablelist><varlistentry><listitem><para> #: ../en/ch00-preface.xml:130 msgid "" "Used for program listings, as well as within paragraphs to refer to program " "elements such as variable or function names, databases, data types, " "environment variables, statements, and keywords." msgstr "" "用于程序列表,以及段内引用的程序元素,例如变量、函数名称、数据库、数据类型、环" "境变量、声明和关键字。" #. type: Content of: <book><preface><sect1><variablelist><varlistentry><term> #: ../en/ch00-preface.xml:138 msgid "<userinput>Constant width bold</userinput>" msgstr "<userinput>等宽粗体</userinput>" #. type: Content of: <book><preface><sect1><variablelist><varlistentry><listitem><para> #: ../en/ch00-preface.xml:141 msgid "Shows commands or other text that should be typed literally by the user." msgstr "标识命令或者其它用户应该逐字输入的文本。" #. type: Content of: <book><preface><sect1><variablelist><varlistentry><term> #: ../en/ch00-preface.xml:147 msgid "<replaceable>Constant width italic</replaceable>" msgstr "<replaceable>等宽斜体</replaceable>" #. type: Content of: <book><preface><sect1><variablelist><varlistentry><listitem><para> #: ../en/ch00-preface.xml:150 msgid "" "Shows text that should be replaced with user-supplied values or by values " "determined by context." msgstr "标识应该被用户提供的值或者取决于上下文的值替换的文本。" #. type: Content of: <book><preface><sect1><tip><para> #: ../en/ch00-preface.xml:157 msgid "This icon signifies a tip, suggestion, or general note." msgstr "此图标表示提示,建议或者一般的的注释。" #. type: Content of: <book><preface><sect1><caution><para> #: ../en/ch00-preface.xml:162 msgid "This icon indicates a warning or caution." msgstr "此图标表示警告。" #. type: Content of: <book><preface><sect1><title> #: ../en/ch00-preface.xml:167 msgid "Using Code Examples" msgstr "使用样例代码" #. type: Content of: <book><preface><sect1><para> #: ../en/ch00-preface.xml:169 msgid "" "This book is here to help you get your job done. In general, you may use the " "code in this book in your programs and documentation. You do not need to " "contact us for permission unless you’re reproducing a significant portion of " "the code. For example, writing a program that uses several chunks of code " "from this book does not require permission. Selling or distributing a CD-ROM " "of examples from O’Reilly books does require permission. Answering a " "question by citing this book and quoting example code does not require " "permission. Incorporating a significant amount of example code from this book " "into your product’s documentation does require permission." msgstr "" #. type: Content of: <book><preface><sect1><para> #: ../en/ch00-preface.xml:181 msgid "" "We appreciate, but do not require, attribution. An attribution usually " "includes the title, author, publisher, and ISBN. For example: “<emphasis>Book " "Title</emphasis> by Some Author. Copyright 2008 O’Reilly Media, Inc., 978-0-" "596-xxxx-x.”" msgstr "" #. type: Content of: <book><preface><sect1><para> #: ../en/ch00-preface.xml:187 msgid "" "If you feel your use of code examples falls outside fair use or the " "permission given above, feel free to contact us at <email>permissions@oreilly." "com</email>." msgstr "" #. type: Content of: <book><preface><sect1><title> #: ../en/ch00-preface.xml:193 msgid "Safari® Books Online" msgstr "Safari® 在线书库" #. type: Content of: <book><preface><sect1><note><para> #: ../en/ch00-preface.xml:196 msgid "" "When you see a Safari® Books Online icon on the cover of your favorite " "technology book, that means the book is available online through the O’Reilly " "Network Safari Bookshelf." msgstr "" #. type: Content of: <book><preface><sect1><para> #: ../en/ch00-preface.xml:202 msgid "" "Safari offers a solution that’s better than e-books. It’s a virtual library " "that lets you easily search thousands of top tech books, cut and paste code " "samples, download chapters, and find quick answers when you need the most " "accurate, current information. Try it for free at <ulink role=\"orm:hideurl:" "ital\" url=\"http://my.safaribooksonline.com/?portal=oreilly\">http://my." "safaribooksonline.com</ulink>." msgstr "" #. type: Content of: <book><preface><sect1><title> #: ../en/ch00-preface.xml:211 msgid "How to Contact Us" msgstr "联系我们" #. type: Content of: <book><preface><sect1><para> #: ../en/ch00-preface.xml:213 msgid "" "Please address comments and questions concerning this book to the publisher:" msgstr "" #. type: Content of: <book><preface><sect1><simplelist><member> #: ../en/ch00-preface.xml:217 msgid "O’Reilly Media, Inc." msgstr "" #. type: Content of: <book><preface><sect1><simplelist><member> #: ../en/ch00-preface.xml:219 msgid "1005 Gravenstein Highway North" msgstr "" #. type: Content of: <book><preface><sect1><simplelist><member> #: ../en/ch00-preface.xml:221 msgid "Sebastopol, CA 95472" msgstr "" #. type: Content of: <book><preface><sect1><simplelist><member> #: ../en/ch00-preface.xml:223 msgid "800-998-9938 (in the United States or Canada)" msgstr "" #. type: Content of: <book><preface><sect1><simplelist><member> #: ../en/ch00-preface.xml:225 msgid "707-829-0515 (international or local)" msgstr "" #. type: Content of: <book><preface><sect1><simplelist><member> #: ../en/ch00-preface.xml:227 msgid "707 829-0104 (fax)" msgstr "" #. type: Content of: <book><preface><sect1><para> #: ../en/ch00-preface.xml:230 msgid "" "We have a web page for this book, where we list errata, examples, and any " "additional information. You can access this page at:" msgstr "" #. type: Content of: <book><preface><sect1><simplelist><member> #: ../en/ch00-preface.xml:235 msgid "" "<ulink url=\"http://www.oreilly.com/catalog/<catalog page>\"></ulink>" msgstr "" #. type: Content of: <book><preface><sect1><remark> #: ../en/ch00-preface.xml:239 msgid "Don’t forget to update the <url> attribute, too." msgstr "" #. type: Content of: <book><preface><sect1><para> #: ../en/ch00-preface.xml:242 msgid "To comment or ask technical questions about this book, send email to:" msgstr "" #. type: Content of: <book><preface><sect1><simplelist><member> #: ../en/ch00-preface.xml:246 msgid "<email>bookquestions@oreilly.com</email>" msgstr "<email>bookquestions@oreilly.com</email>" #. type: Content of: <book><preface><sect1><para> #: ../en/ch00-preface.xml:249 msgid "" "For more information about our books, conferences, Resource Centers, and the " "O’Reilly Network, see our web site at:" msgstr "" #. type: Content of: <book><preface><sect1><simplelist><member> #: ../en/ch00-preface.xml:253 msgid "<ulink url=\"http://www.oreilly.com\"></ulink>" msgstr "<ulink url=\"http://www.oreilly.com\"></ulink>" #. type: Content of: <book><chapter><title> #: ../en/ch01-intro.xml:5 msgid "How did we get here?" msgstr "写在前面" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch01-intro.xml:8 msgid "Why revision control? Why Mercurial?" msgstr "为什么使用版本控制? 为什么使用 Mercurial?" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch01-intro.xml:10 msgid "" "Revision control is the process of managing multiple versions of a piece of " "information. In its simplest form, this is something that many people do by " "hand: every time you modify a file, save it under a new name that contains a " "number, each one higher than the number of the preceding version." msgstr "" "版本控制是管理一些信息的多个版本的过程。它最简单的形式莫过于:每次你修改一个文" "件后都重新命名保存,文件名中包含一个数字,每次修改后这个数字都增加。这通常是许" "多人手工完成的。" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch01-intro.xml:16 msgid "" "Manually managing multiple versions of even a single file is an error-prone " "task, though, so software tools to help automate this process have long been " "available. The earliest automated revision control tools were intended to " "help a single user to manage revisions of a single file. Over the past few " "decades, the scope of revision control tools has expanded greatly; they now " "manage multiple files, and help multiple people to work together. The best " "modern revision control tools have no problem coping with thousands of people " "working together on projects that consist of hundreds of thousands of files." msgstr "" "然而,手工管理即使是一个文件的多个版本也是很容易出错的,所以很早就有软件工具来" "使这个过程自动化。最早的自动化软件管理工具的目标是帮助一个用户管理一个文件的版" "本。在过去的几十年里,版本控制工具的范围得到极大扩展;现在它们可以管理多个文" "件,帮助许多人一起工作。最新的版本控制工具可以支持上包含成数十万个文件,几千个" "人一起工作的项目。" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch01-intro.xml:27 msgid "" "The arrival of distributed revision control is relatively recent, and so far " "this new field has grown due to people's willingness to explore ill-charted " "territory." msgstr "" "分布式版本控制是最近才出现的,但是由于人们愿意探索新的疆域,目前这一新的领域已" "经得到了长足的发展" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch01-intro.xml:31 msgid "" "I am writing a book about distributed revision control because I believe that " "it is an important subject that deserves a field guide. I chose to write " "about Mercurial because it is the easiest tool to learn the terrain with, and " "yet it scales to the demands of real, challenging environments where many " "other revision control tools buckle." msgstr "" "我写这本关于分布式版本控制的书是因为我相信这个领域应该有一个指南。我选择" "Mercurial是因为它是在这个领域中学习最容易上手的工具,并且它能够满足真实的,挑" "战性的环境的要求,而其他版本控制工具只能望而兴叹。" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch01-intro.xml:39 msgid "Why use revision control?" msgstr "为什么使用版本控制?" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch01-intro.xml:41 msgid "" "There are a number of reasons why you or your team might want to use an " "automated revision control tool for a project." msgstr "" "为什么你或者你的团队可能需要在项目中使用自动化版本控制工具呢?有很多理由。" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch01-intro.xml:46 msgid "" "It will track the history and evolution of your project, so you don't have " "to. For every change, you'll have a log of <emphasis>who</emphasis> made it; " "<emphasis>why</emphasis> they made it; <emphasis>when</emphasis> they made " "it; and <emphasis>what</emphasis> the change was." msgstr "" "因为它能记录你的项目的历史和演化,所以你不必再给每个变更都记录日志,<emphasis>" "谁</emphasis>做的;<emphasis>为什么</emphasis>他们这样做;<emphasis>什么时候</" "emphasis>做的;做了<emphasis>什么</emphasis>修改。" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch01-intro.xml:53 msgid "" "When you're working with other people, revision control software makes it " "easier for you to collaborate. For example, when people more or less " "simultaneously make potentially incompatible changes, the software will help " "you to identify and resolve those conflicts." msgstr "" "当你和其他人一起工作的时候,版本控制工具让你合作的更容易。例如,当许多人或多或" "少的同时进行有可能冲突的修改的时候,软件可以帮助你确定和解决这些冲突。" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch01-intro.xml:59 msgid "" "It can help you to recover from mistakes. If you make a change that later " "turns out to be in error, you can revert to an earlier version of one or more " "files. In fact, a <emphasis>really</emphasis> good revision control tool " "will even help you to efficiently figure out exactly when a problem was " "introduced (see <xref linkend=\"sec:undo:bisect\"/> for details)." msgstr "" "它能帮助你修正错误。如果你做了一个修改,但是后来发现这是个错误,你能恢复到一个" "或者多个文件以前的版本。实际上,一个<emphasis>相当</emphasis>好的版本控制工具" "甚至会帮助你找出什么什么是时候引入的这个问题(详细信息参考<xref linkend=\"sec:" "undo:bisect\"/>)。 " #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch01-intro.xml:66 msgid "" "It will help you to work simultaneously on, and manage the drift between, " "multiple versions of your project." msgstr "它能帮助你同时工作于项目的多个版本,并管理它们的差异。" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch01-intro.xml:71 msgid "" "Most of these reasons are equally valid&emdash;at least in theory&emdash;" "whether you're working on a project by yourself, or with a hundred other " "people." msgstr "" "大多数这些理由都是等效的&emdash;至少在理论上&emdash;不管你是一个人做项目还是和" "几百个人一起。" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch01-intro.xml:76 msgid "" "A key question about the practicality of revision control at these two " "different scales (<quote>lone hacker</quote> and <quote>huge team</quote>) is " "how its <emphasis>benefits</emphasis> compare to its <emphasis>costs</" "emphasis>. A revision control tool that's difficult to understand or use is " "going to impose a high cost." msgstr "" "版本控制在在不同尺度上(<quote>单个黑客</quote>和<quote>一个大项目组</quote>)" "实践的一个关键问题是它的<emphasis>性价</emphasis>比怎么样。一个很难理解和使用" "的版本控制工具会让你的代价很高。" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch01-intro.xml:84 msgid "" "A five-hundred-person project is likely to collapse under its own weight " "almost immediately without a revision control tool and process. In this case, " "the cost of using revision control might hardly seem worth considering, since " "<emphasis>without</emphasis> it, failure is almost guaranteed." msgstr "" "如果没有版本控制工具和过程,一个五百人的项目很快就可能就将自己压垮。在这种情况" "下,版本控制的代价基本上不用考虑,因为没有它,失败几乎是一定的。" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch01-intro.xml:91 msgid "" "On the other hand, a one-person <quote>quick hack</quote> might seem like a " "poor place to use a revision control tool, because surely the cost of using " "one must be close to the overall cost of the project. Right?" msgstr "" "另一方面,一个人的<quote>快速编程</quote>看起来并不适合使用版本控制工具,因为" "使用一个版本控制工具的代价就是整个项目的代价,对吧?" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch01-intro.xml:96 msgid "" "Mercurial uniquely supports <emphasis>both</emphasis> of these scales of " "development. You can learn the basics in just a few minutes, and due to its " "low overhead, you can apply revision control to the smallest of projects with " "ease. Its simplicity means you won't have a lot of abstruse concepts or " "command sequences competing for mental space with whatever you're " "<emphasis>really</emphasis> trying to do. At the same time, Mercurial's high " "performance and peer-to-peer nature let you scale painlessly to handle large " "projects." msgstr "" "Mercurial的独特之处就是它<emphasis>同时</emphasis>支持这两种尺度的开发。你可以" "在几分钟之内学会基本的使用,因为代价很小,你可以很方便的在最小的项目上应用版本" "管理。它的简洁性意味着不会有很多艰深的概念和命令干扰你<emphasis>真正</" "emphasis>的工作。同时,Mercurial高性能和点对点的特性可以让你轻易的应对大的项" "目。" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch01-intro.xml:106 msgid "" "No revision control tool can rescue a poorly run project, but a good choice " "of tools can make a huge difference to the fluidity with which you can work " "on a project." msgstr "" "没有一个版本控制工具能拯救一个糟糕的项目,但是在项目中选择好的工具会大大的提高" "效率,正是工欲善其事,必先利其器。" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch01-intro.xml:113 msgid "The many names of revision control" msgstr "版本控制的别名" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch01-intro.xml:115 msgid "" "Revision control is a diverse field, so much so that it is referred to by " "many names and acronyms. Here are a few of the more common variations you'll " "encounter:" msgstr "" "版本控制是一个各自为政的领域,以至于有很多名称和缩略语,下面是你可能遇到的一些" "常用的术语:" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch01-intro.xml:119 msgid "Revision control (RCS)" msgstr "版本控制(RCS)" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch01-intro.xml:120 msgid "Software configuration management (SCM), or configuration management" msgstr "软件配置管理(SCM),或配置管理" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch01-intro.xml:122 msgid "Source code management" msgstr "源代码管理" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch01-intro.xml:123 msgid "Source code control, or source control" msgstr "源代码控制,或源控制" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch01-intro.xml:125 msgid "Version control (VCS)" msgstr "版本控制(VCS)" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch01-intro.xml:127 msgid "" "Some people claim that these terms actually have different meanings, but in " "practice they overlap so much that there's no agreed or even useful way to " "tease them apart." msgstr "" "有些人声称这些术语有不同的含义,但实际上它们的含义太重叠了,根本没有一致的,甚" "至有用的方式来区别它们。" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch01-intro.xml:135 msgid "About the examples in this book" msgstr "本书的例子" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch01-intro.xml:137 msgid "" "This book takes an unusual approach to code samples. Every example is " "<quote>live</quote>&emdash;each one is actually the result of a shell script " "that executes the Mercurial commands you see. Every time an image of the " "book is built from its sources, all the example scripts are automatically " "run, and their current results compared against their expected results." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch01-intro.xml:144 msgid "" "The advantage of this approach is that the examples are always accurate; they " "describe <emphasis>exactly</emphasis> the behavior of the version of " "Mercurial that's mentioned at the front of the book. If I update the version " "of Mercurial that I'm documenting, and the output of some command changes, " "the build fails." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch01-intro.xml:151 msgid "" "There is a small disadvantage to this approach, which is that the dates and " "times you'll see in examples tend to be <quote>squashed</quote> together in a " "way that they wouldn't be if the same commands were being typed by a human. " "Where a human can issue no more than one command every few seconds, with any " "resulting timestamps correspondingly spread out, my automated example scripts " "run many commands in one second." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch01-intro.xml:159 msgid "" "As an instance of this, several consecutive commits in an example can show up " "as having occurred during the same second. You can see this occur in the " "<literal role=\"hg-ext\">bisect</literal> example in <xref linkend=\"sec:undo:" "bisect\"/>, for instance." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch01-intro.xml:165 msgid "" "So when you're reading examples, don't place too much weight on the dates or " "times you see in the output of commands. But <emphasis>do</emphasis> be " "confident that the behavior you're seeing is consistent and reproducible." msgstr "" "所以当你研究这些例子的时候,不要太注意命令输出的日期和时间。但是<emphasis>要</" "emphasis>保证你看到的行为是一致的和可以再现的。" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch01-intro.xml:173 msgid "Trends in the field" msgstr "版本控制的发展趋势" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch01-intro.xml:175 msgid "" "There has been an unmistakable trend in the development and use of revision " "control tools over the past four decades, as people have become familiar with " "the capabilities of their tools and constrained by their limitations." msgstr "" "在过去的四十年中,随着人们越来越熟悉他们的工具的能力和限制,开发和使用版本控制" "工具出现了明确的趋势。 " #. type: Content of: <book><chapter><sect1><para> #: ../en/ch01-intro.xml:180 msgid "" "The first generation began by managing single files on individual computers. " "Although these tools represented a huge advance over ad-hoc manual revision " "control, their locking model and reliance on a single computer limited them " "to small, tightly-knit teams." msgstr "" "在第一代软件开始于在个人计算机上管理单个文件。虽然这些工具比手工管理版本有了巨" "大的飞跃。但是加锁模型和依赖于单个计算机限制了他们之能用于小的,组织严密的团" "队。" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch01-intro.xml:186 msgid "" "The second generation loosened these constraints by moving to network-" "centered architectures, and managing entire projects at a time. As projects " "grew larger, they ran into new problems. With clients needing to talk to " "servers very frequently, server scaling became an issue for large projects. " "An unreliable network connection could prevent remote users from being able " "to talk to the server at all. As open source projects started making read-" "only access available anonymously to anyone, people without commit privileges " "found that they could not use the tools to interact with a project in a " "natural way, as they could not record their changes." msgstr "" "第二代软件因为采用以网络为中心的结构,一次性管理整个项目而放松了这些限制。随着" "项目增长,又出现了新的问题。客户需要频繁的和服务器交互,服务器的可伸缩性成为大" "项目的主要问题。不可靠的网络会妨碍客户和服务器的交互。随着开源项目开始开放只读" "权限给匿名用户,没有提交权限的用户发现他们不能以自然的方式使用工具和项目交互," "因为他们不能记录他们的修改。" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch01-intro.xml:198 msgid "" "The current generation of revision control tools is peer-to-peer in nature. " "All of these systems have dropped the dependency on a single central server, " "and allow people to distribute their revision control data to where it's " "actually needed. Collaboration over the Internet has moved from constrained " "by technology to a matter of choice and consensus. Modern tools can operate " "offline indefinitely and autonomously, with a network connection only needed " "when syncing changes with another repository." msgstr "" "新一代的版本控制工具本质上是点对点的。所有的这些系统都抛弃了对单个中央服务器的" "依赖,允许用户发布他们的版本控制数据到任何需要的地方。通过互联网的协作摆脱了技" "术的限制,走向选择和审查。现代的工具可以进行自治的,不受限制的离线操作。只需要" "在有网络的时候和其他的版本库同步即可。" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch01-intro.xml:210 msgid "A few of the advantages of distributed revision control" msgstr "分布版本控制的优点" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch01-intro.xml:213 msgid "" "Even though distributed revision control tools have for several years been as " "robust and usable as their previous-generation counterparts, people using " "older tools have not yet necessarily woken up to their advantages. There are " "a number of ways in which distributed tools shine relative to centralised " "ones." msgstr "" "与他们的上一代竞争者相比,虽然分布式版本控制工具多年来已经很稳定和实用了,但是" "使用旧的工具的人们还没有完全了解它们的优点,分布式的工具在很多方面明显由于集中" "式的工具。" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch01-intro.xml:220 msgid "" "For an individual developer, distributed tools are almost always much faster " "than centralised tools. This is for a simple reason: a centralised tool " "needs to talk over the network for many common operations, because most " "metadata is stored in a single copy on the central server. A distributed " "tool stores all of its metadata locally. All else being equal, talking over " "the network adds overhead to a centralised tool. Don't underestimate the " "value of a snappy, responsive tool: you're going to spend a lot of time " "interacting with your revision control software." msgstr "" "对于个人开发者,分布式工具几乎永远比集中式工具快的多。原因很简单:集中式工具的" "很多操作需要网络交互,因为大部分元数据都只在中央服务器上有一份拷贝。而一个分布" "式工具将所有的元数据保存在本地。其他的相同,通过网络的交互增加了集中式工具的负" "担。不要低估了反应迅速的工具的价值:你要花很多时间和你的版本控制软件交互。" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch01-intro.xml:231 msgid "" "Distributed tools are indifferent to the vagaries of your server " "infrastructure, again because they replicate metadata to so many locations. " "If you use a centralised system and your server catches fire, you'd better " "hope that your backup media are reliable, and that your last backup was " "recent and actually worked. With a distributed tool, you have many backups " "available on every contributor's computer." msgstr "" "分布式工具对你的服务器结构并不感冒,因为他们在将元数据复制到很多地方。如果你的" "集中式系统和你的服务器着火了,你最好希望你的备份介质是可靠的,同时你最后的备份" "是最近的,而且还能用。而对于分布式工具,你在贡献者的计算机上有很多备份。" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch01-intro.xml:239 msgid "" "The reliability of your network will affect distributed tools far less than " "it will centralised tools. You can't even use a centralised tool without a " "network connection, except for a few highly constrained commands. With a " "distributed tool, if your network connection goes down while you're working, " "you may not even notice. The only thing you won't be able to do is talk to " "repositories on other computers, something that is relatively rare compared " "with local operations. If you have a far-flung team of collaborators, this " "may be significant." msgstr "" "网络的可靠性对分布式工具的影响要远远小于集中式工具。如果没有网络你根本不能使用" "集中式工具,除了少数几个功能有限命令。而对于分布式工具,即使在你工作的时候网络" "瘫痪了,你可能根本不会注意到。你不能做的事情仅仅是不能和其它计算机上的版本库交" "互了,这种事在本地操作相当罕见。而如果你的团队有异地的人员,那这就很有可能了。" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch01-intro.xml:250 msgid "Advantages for open source projects" msgstr "开源项目的优点" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch01-intro.xml:252 msgid "" "If you take a shine to an open source project and decide that you would like " "to start hacking on it, and that project uses a distributed revision control " "tool, you are at once a peer with the people who consider themselves the " "<quote>core</quote> of that project. If they publish their repositories, you " "can immediately copy their project history, start making changes, and record " "your work, using the same tools in the same ways as insiders. By contrast, " "with a centralised tool, you must use the software in a <quote>read only</" "quote> mode unless someone grants you permission to commit changes to their " "central server. Until then, you won't be able to record changes, and your " "local modifications will be at risk of corruption any time you try to update " "your client's view of the repository." msgstr "" "如果你喜欢一个开源项目并且决定准备开始改进它,同时这个项目使用分布式版本控制工" "具的话,你立刻可以和其他人一样认为自己成为项目的<quote>核心</quote>。如果他们" "发布了他们的版本库,你可以立即拷贝他们的项目。开始修改,记录你自己的工作,和内" "部人员一样使用同样的工具。相比之下,如果使用集中式工具,除非有人给你向中央服务" "器提交修改的权限,你只能用只读的方式使用软件。这样,你就不能记录你的修改,而且" "当你从版本库更新的时候,本地的修改随时有崩溃的可能。 " #. type: Content of: <book><chapter><sect1><sect2><sect3><title> #: ../en/ch01-intro.xml:268 msgid "The forking non-problem" msgstr "分叉不是问题" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch01-intro.xml:270 msgid "" "It has been suggested that distributed revision control tools pose some sort " "of risk to open source projects because they make it easy to <quote>fork</" "quote> the development of a project. A fork happens when there are " "differences in opinion or attitude between groups of developers that cause " "them to decide that they can't work together any longer. Each side takes a " "more or less complete copy of the project's source code, and goes off in its " "own direction." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch01-intro.xml:280 msgid "" "Sometimes the camps in a fork decide to reconcile their differences. With a " "centralised revision control system, the <emphasis>technical</emphasis> " "process of reconciliation is painful, and has to be performed largely by " "hand. You have to decide whose revision history is going to <quote>win</" "quote>, and graft the other team's changes into the tree somehow. This " "usually loses some or all of one side's revision history." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch01-intro.xml:289 msgid "" "What distributed tools do with respect to forking is they make forking the " "<emphasis>only</emphasis> way to develop a project. Every single change that " "you make is potentially a fork point. The great strength of this approach is " "that a distributed revision control tool has to be really good at " "<emphasis>merging</emphasis> forks, because forks are absolutely fundamental: " "they happen all the time." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch01-intro.xml:298 msgid "" "If every piece of work that everybody does, all the time, is framed in terms " "of forking and merging, then what the open source world refers to as a " "<quote>fork</quote> becomes <emphasis>purely</emphasis> a social issue. If " "anything, distributed tools <emphasis>lower</emphasis> the likelihood of a " "fork:" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> #: ../en/ch01-intro.xml:305 msgid "" "They eliminate the social distinction that centralised tools impose: that " "between insiders (people with commit access) and outsiders (people without)." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> #: ../en/ch01-intro.xml:309 msgid "" "They make it easier to reconcile after a social fork, because all that's " "involved from the perspective of the revision control software is just " "another merge." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch01-intro.xml:314 msgid "" "Some people resist distributed tools because they want to retain tight " "control over their projects, and they believe that centralised tools give " "them this control. However, if you're of this belief, and you publish your " "CVS or Subversion repositories publicly, there are plenty of tools available " "that can pull out your entire project's history (albeit slowly) and recreate " "it somewhere that you don't control. So while your control in this case is " "illusory, you are forgoing the ability to fluidly collaborate with whatever " "people feel compelled to mirror and fork your history." msgstr "" "有些人拒绝分布式工具因为他们想保持对项目的控制,他们相信集中式工具会给他们这种" "控制。如果你这种想法,并你将CVS或者Subversion版本库向大众发布了,那么别人可用" "现有的很多工具将整个项目的历史抓取出来(可能很慢),在其它你控制不了的地方重建" "版本库。这时你的控制只不过是一种幻觉罢了,一些人被迫从你的版本库创建映像和分" "支,而你失去了和他们协作的机会。" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch01-intro.xml:329 msgid "Advantages for commercial projects" msgstr "商业项目的优点" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch01-intro.xml:331 msgid "" "Many commercial projects are undertaken by teams that are scattered across " "the globe. Contributors who are far from a central server will see slower " "command execution and perhaps less reliability. Commercial revision control " "systems attempt to ameliorate these problems with remote-site replication add-" "ons that are typically expensive to buy and cantankerous to administer. A " "distributed system doesn't suffer from these problems in the first place. " "Better yet, you can easily set up multiple authoritative servers, say one per " "site, so that there's no redundant communication between repositories over " "expensive long-haul network links." msgstr "" "遍布全球的团队正在进行许多商业项目。远离中央服务器的贡献者会发现执行命令速度很" "慢同时不怎么可靠。商业的版本控制系统改善这个问题的办法就是让你购买远程复制插" "件,这通常很昂贵,并且很难管理。分布式系统首先不会有这样的问题。其次,你可以很" "容易的建立多个授权服务器,假设每个站点一个,这样可以避免在昂贵的长途线路上的冗" "余的通讯。" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch01-intro.xml:343 msgid "" "Centralised revision control systems tend to have relatively low " "scalability. It's not unusual for an expensive centralised system to fall " "over under the combined load of just a few dozen concurrent users. Once " "again, the typical response tends to be an expensive and clunky replication " "facility. Since the load on a central server&emdash;if you have one at " "all&emdash;is many times lower with a distributed tool (because all of the " "data is replicated everywhere), a single cheap server can handle the needs of " "a much larger team, and replication to balance load becomes a simple matter " "of scripting." msgstr "" "集中式的版本控制系统的扩展性相对较低。只要不多的并行用户的组合负载就可以将一个" "昂贵的中央服务器压垮。同样,典型的反应就是昂贵笨重的复制设备。因为中央服务器的" "最大负载&emdash;如果你有的话&emdash;比分布式工具低很多(因为所有的数据要北复制" "到其它地方),一个廉价的服务器就可以满足一个相当大的团队的要求,为平衡负载而进" "行的复制只需要简单的脚本就够了。" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch01-intro.xml:355 msgid "" "If you have an employee in the field, troubleshooting a problem at a " "customer's site, they'll benefit from distributed revision control. The tool " "will let them generate custom builds, try different fixes in isolation from " "each other, and search efficiently through history for the sources of bugs " "and regressions in the customer's environment, all without needing to connect " "to your company's network." msgstr "" "如果你有员工需要在客户方解决问题,那么他们会受益于分布式版本控制。工具允许他们" "创建定制的环境,互相独立的尝试不同的解决方案。并且可以高效的从历史代码中查找" "bug的根源,在客户环境中进行回归,所有的这些都不需要连接公司的网络。" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch01-intro.xml:366 msgid "Why choose Mercurial?" msgstr "为什么选择 Mercurial?" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch01-intro.xml:368 msgid "" "Mercurial has a unique set of properties that make it a particularly good " "choice as a revision control system." msgstr "Mercurial是一个非常好的版本控制系统,因为它有很多独一无二的特点。" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch01-intro.xml:371 msgid "It is easy to learn and use." msgstr "它易学易用。" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch01-intro.xml:372 msgid "It is lightweight." msgstr "它轻量级。" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch01-intro.xml:373 msgid "It scales excellently." msgstr "它扩展性很好。" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch01-intro.xml:374 msgid "It is easy to customise." msgstr "它很容易定制。" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch01-intro.xml:377 msgid "" "If you are at all familiar with revision control systems, you should be able " "to get up and running with Mercurial in less than five minutes. Even if not, " "it will take no more than a few minutes longer. Mercurial's command and " "feature sets are generally uniform and consistent, so you can keep track of a " "few general rules instead of a host of exceptions." msgstr "" "如果你熟悉版本控制系统,你在五分钟之内只能就可以使用Mercurial工作了。即使你不" "熟悉,也不过是再多花几分钟。Mercurial的命令和功能集非常统一一致,你只要遵守几" "个通用的规则就够了,很少有例外。" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch01-intro.xml:384 msgid "" "On a small project, you can start working with Mercurial in moments. Creating " "new changes and branches; transferring changes around (whether locally or " "over a network); and history and status operations are all fast. Mercurial " "attempts to stay nimble and largely out of your way by combining low " "cognitive overhead with blazingly fast operations." msgstr "" "在很小的项目上,你马上就可以使用Mercurial开始工作。创建新的修改和分支;到处交" "换修改(不管本机还是通过网络);获取历史和状态数据非常快。Mercurial努力保持小" "巧灵活,在眨眼之间就能完成操作。" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch01-intro.xml:391 msgid "" "The usefulness of Mercurial is not limited to small projects: it is used by " "projects with hundreds to thousands of contributors, each containing tens of " "thousands of files and hundreds of megabytes of source code." msgstr "" "不仅小的项目可以使用Mercurial:有成百上千的贡献者的项目也在使用它,这些项目每" "个都有上万个文件和几百兆的源码。" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch01-intro.xml:396 msgid "" "If the core functionality of Mercurial is not enough for you, it's easy to " "build on. Mercurial is well suited to scripting tasks, and its clean " "internals and implementation in Python make it easy to add features in the " "form of extensions. There are a number of popular and useful extensions " "already available, ranging from helping to identify bugs to improving " "performance." msgstr "" "如果觉得Mercurial的核心功能不能满足要求,你很容易在现有基础上开发。Mercurial非" "常适合于脚本任务,它的核心简洁,并且用Python实现,用扩展的方式增加新的功能非常" "方便,现在已经有很多流行和有用的扩展了,像帮助你确定bug或者提高性能等。" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch01-intro.xml:406 msgid "Mercurial compared with other tools" msgstr "Mercurial 与其它工具的比较" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch01-intro.xml:408 msgid "" "Before you read on, please understand that this section necessarily reflects " "my own experiences, interests, and (dare I say it) biases. I have used every " "one of the revision control tools listed below, in most cases for several " "years at a time." msgstr "" "在你继续阅读之前,请理解本节完全反映了我的个人经验,兴趣,和偏好(我敢说)。下" "面列的每个版本控制工具我都使用过,大多数情况下都用过好几年。" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch01-intro.xml:418 msgid "" "Subversion is a popular revision control tool, developed to replace CVS. It " "has a centralised client/server architecture." msgstr "" "Subversion是一个流行的版本控制工具,是用来替代CVS的,它采用的是集中式的客户/服" "务器结构。" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch01-intro.xml:422 msgid "" "Subversion and Mercurial have similarly named commands for performing the " "same operations, so if you're familiar with one, it is easy to learn to use " "the other. Both tools are portable to all popular operating systems." msgstr "" "Subversion和Mercurial相同操作的命令的命名上非常相似,所以如果你熟悉一个,很容" "易学会另外一个,两个工具都可以在大多数平台上运行。" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch01-intro.xml:427 msgid "" "Prior to version 1.5, Subversion had no useful support for merges. At the " "time of writing, its merge tracking capability is new, and known to be <ulink " "url=\"http://svnbook.red-bean.com/nightly/en/svn.branchmerge.advanced." "html#svn.branchmerge.advanced.finalword\">complicated and buggy</ulink>." msgstr "" "在1.5版之前,Subversion对合并的支持并不好。在我写本书的时候,它刚新增了并跟踪" "的功能,出名的<ulink url=\"http://svnbook.red-bean.com/nightly/en/svn." "branchmerge.advanced.html#svn.branchmerge.advanced.finalword\">复杂和容易出错" "</ulink>。" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch01-intro.xml:433 msgid "" "Mercurial has a substantial performance advantage over Subversion on every " "revision control operation I have benchmarked. I have measured its advantage " "as ranging from a factor of two to a factor of six when compared with " "Subversion 1.4.3's <emphasis>ra_local</emphasis> file store, which is the " "fastest access method available. In more realistic deployments involving a " "network-based store, Subversion will be at a substantially larger " "disadvantage. Because many Subversion commands must talk to the server and " "Subversion does not have useful replication facilities, server capacity and " "network bandwidth become bottlenecks for modestly large projects." msgstr "" "在我测量过的每个版本控制操作上Mercurial都比Subversion有很大的性能优势。差距从" "两个数量级到六个数量级不等,我用的是Subversion 1.4.3的<emphasis>ra_local</" "emphasis>文件存储方式,这是已知的最快的存取方式了。在实际的部署中包括网络存" "储,那么Subversion的劣势更大。因为很多Subversion命令必须和主机交互,并且因为" "Subversion没有好的复制机制,使得对于中的等大小的项目而言,服务器容量和网络带宽" "成为主要瓶颈。" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch01-intro.xml:446 msgid "" "Additionally, Subversion incurs substantial storage overhead to avoid network " "transactions for a few common operations, such as finding modified files " "(<literal>status</literal>) and displaying modifications against the current " "revision (<literal>diff</literal>). As a result, a Subversion working copy " "is often the same size as, or larger than, a Mercurial repository and working " "directory, even though the Mercurial repository contains a complete history " "of the project." msgstr "" "另外,Subversion以在客户端使用了更多存储空间的方法,换取降低几个常用操作的网络" "负载,例如查找修改过的文件(<literal>status</literal>)和显示对于当前版本的更" "改(<literal>diff</literal>)。结果Subversion的工作副本经常和Mercurial的版本库" "和工作目录一样大,或者更大,虽然Mercurial的版本库包括了项目的完整历史。" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch01-intro.xml:456 msgid "" "Subversion is widely supported by third party tools. Mercurial currently " "lags considerably in this area. This gap is closing, however, and indeed " "some of Mercurial's GUI tools now outshine their Subversion equivalents. " "Like Mercurial, Subversion has an excellent user manual." msgstr "" "Subversion有很多的第三方工具支持。Mercurial现在在这方面稍微欠缺。然而差距正在" "逐渐缩小,实际上一些有Mercurial的GUI工具比Subversion类似工具还略胜一筹。和" "Mercurial一样,Subversion也有完善的用户手册。" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch01-intro.xml:462 msgid "" "Because Subversion doesn't store revision history on the client, it is well " "suited to managing projects that deal with lots of large, opaque binary " "files. If you check in fifty revisions to an incompressible 10MB file, " "Subversion's client-side space usage stays constant The space used by any " "distributed SCM will grow rapidly in proportion to the number of revisions, " "because the differences between each revision are large." msgstr "" "Subversion并不在客户端存储版本历史,所以它很适合管理那些有很多大的二进制文件的" "项目。如果你对一个未压缩的10MB文件检入了五十次,Subversion客户端的占用的磁盘空" "间基本上保持不变。而对于分布式SCM软件,磁盘空间会随着版本数量的增加成而迅速增" "长,因为每个版本之间的差异非常大。" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch01-intro.xml:471 msgid "" "In addition, it's often difficult or, more usually, impossible to merge " "different versions of a binary file. Subversion's ability to let a user lock " "a file, so that they temporarily have the exclusive right to commit changes " "to it, can be a significant advantage to a project where binary files are " "widely used." msgstr "" "另外,合并不同版本的二进制文件非常困难,换句话说,基本上不可能。Subversion提供" "了锁定功能,用户可以锁定一个文件,这样他就取得了对这个文件临时的独占的提交权," "这对于广泛使用二进制文件的项目而言是个明显优势。" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch01-intro.xml:478 msgid "" "Mercurial can import revision history from a Subversion repository. It can " "also export revision history to a Subversion repository. This makes it easy " "to <quote>test the waters</quote> and use Mercurial and Subversion in " "parallel before deciding to switch. History conversion is incremental, so " "you can perform an initial conversion, then small additional conversions " "afterwards to bring in new changes." msgstr "" "Mercurial可以从Subversion的版本库中导入历史版本。它也可以向Subversion的版本库" "输出历史版本。这样在决定转换之前很容易先<quote>试一下水</quote>,同时并行的使" "用Mercurial和Subversion。版本史的转换是递增的,你可以先构造一个初始版本,每次" "有了新的更改后加入一个小的转换。" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch01-intro.xml:490 ../en/ch01-intro.xml:629 msgid "Git" msgstr "Git" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch01-intro.xml:492 msgid "" "Git is a distributed revision control tool that was developed for managing " "the Linux kernel source tree. Like Mercurial, its early design was somewhat " "influenced by Monotone." msgstr "" "Git是为了管理Linux内核代码而开发的一个分布式版本控制工具。它和Mercurial一样在" "设计上受了Monotone的影响。" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch01-intro.xml:497 msgid "" "Git has a very large command set, with version 1.5.0 providing 139 individual " "commands. It has something of a reputation for being difficult to learn. " "Compared to Git, Mercurial has a strong focus on simplicity." msgstr "" "Git有非常大的命令集,1.5.0版本提供了139个单独的命令。它以难学而闻名于世。与Git" "相比,Mercurial力求简洁。" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch01-intro.xml:502 msgid "" "In terms of performance, Git is extremely fast. In several cases, it is " "faster than Mercurial, at least on Linux, while Mercurial performs better on " "other operations. However, on Windows, the performance and general level of " "support that Git provides is, at the time of writing, far behind that of " "Mercurial." msgstr "" "就性能而言,Git非常快。在很多情况下它都比Mercurial快,至少是在Linux上,但" "Mercurial在其它操作上有优势。而在Windows上,Git不管是性能还是提供的支持,都比" "Mercurial差很多,至少在本书写作的时候是这样。" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch01-intro.xml:509 msgid "" "While a Mercurial repository needs no maintenance, a Git repository requires " "frequent manual <quote>repacks</quote> of its metadata. Without these, " "performance degrades, while space usage grows rapidly. A server that " "contains many Git repositories that are not rigorously and frequently " "repacked will become heavily disk-bound during backups, and there have been " "instances of daily backups taking far longer than 24 hours as a result. A " "freshly packed Git repository is slightly smaller than a Mercurial " "repository, but an unpacked repository is several orders of magnitude larger." msgstr "" "Mercurial的版本库不需要维护,但Git的版本库需要频繁的手工维护,将其元数据" "<quote>repacks</quote>,如果不这样做,性能就会下降,磁盘空间也会迅速增加。有多" "个Git版本库的服务器需要严格和频繁的重新打包,否则在备份的时候就会成为严重的瓶" "颈,曾经有过运行每日备份超过24小时的例子。一个新打包的Git版本库比Mercurial稍小" "一些,但是未打包的版本库则会大几个数量级。" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch01-intro.xml:520 msgid "" "The core of Git is written in C. Many Git commands are implemented as shell " "or Perl scripts, and the quality of these scripts varies widely. I have " "encountered several instances where scripts charged along blindly in the " "presence of errors that should have been fatal." msgstr "" "Git的核心由C语言编写,许多Git命令是用shell或者perl脚本实现的,这些脚本的质量差" "别很大。我碰到过好几次这样的情况,明明已经出现了致命错误了,脚本还在盲目的执" "行。" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch01-intro.xml:526 msgid "Mercurial can import revision history from a Git repository." msgstr "Mercurial可以从Git的版本库中导入版本历史。" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch01-intro.xml:534 msgid "" "CVS is probably the most widely used revision control tool in the world. Due " "to its age and internal untidiness, it has been only lightly maintained for " "many years." msgstr "" "CVS可能是世界上使用最广泛的版本控制工具。因为它是太古老和内部实现很混乱,许多" "年来都处于维护状态。" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch01-intro.xml:538 msgid "" "It has a centralised client/server architecture. It does not group related " "file changes into atomic commits, making it easy for people to <quote>break " "the build</quote>: one person can successfully commit part of a change and " "then be blocked by the need for a merge, causing other people to see only a " "portion of the work they intended to do. This also affects how you work with " "project history. If you want to see all of the modifications someone made as " "part of a task, you will need to manually inspect the descriptions and " "timestamps of the changes made to each file involved (if you even know what " "those files were)." msgstr "" "CVS采用的是集中式客户/服务器结构。它不会将相关的文件变更一起作为原子提交,这使" "得它很容易<quote>破坏构建</quote>:一个人成功的提交了一部分更改,然后要停下来" "处理合并,这使得其他人只能看见他们的部分工作。这样也会影响你和项目历史的工作方" "式。如果你想看到其他人针对他的那部分任务做的全部修改,你必须手动检查每个受影响" "的文件的变更描述和时间戳(假如你知道是哪些文件)。" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch01-intro.xml:550 msgid "" "CVS has a muddled notion of tags and branches that I will not attempt to even " "describe. It does not support renaming of files or directories well, making " "it easy to corrupt a repository. It has almost no internal consistency " "checking capabilities, so it is usually not even possible to tell whether or " "how a repository is corrupt. I would not recommend CVS for any project, " "existing or new." msgstr "" "CVS的分支和标签的概念实在是太混乱了,我都不想给你介绍。它也不支持文件和目录的" "重命名。这使得版本库非常容易崩溃。它几乎没任何的内部一致性检查功能,所以通常你" "不可能知道版本库是不是崩溃了。不管是新项目还是老项目,我都不推荐使用CVS。" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch01-intro.xml:558 msgid "" "Mercurial can import CVS revision history. However, there are a few caveats " "that apply; these are true of every other revision control tool's CVS " "importer, too. Due to CVS's lack of atomic changes and unversioned " "filesystem hierarchy, it is not possible to reconstruct CVS history " "completely accurately; some guesswork is involved, and renames will usually " "not show up. Because a lot of advanced CVS administration has to be done by " "hand and is hence error-prone, it's common for CVS importers to run into " "multiple problems with corrupted repositories (completely bogus revision " "timestamps and files that have remained locked for over a decade are just two " "of the less interesting problems I can recall from personal experience)." msgstr "" "Mercurial可以导入CVS的版本历史。然而,这里面有很多限制;对其版本控制工具的CVS" "导入程序也是一样。因为CVS缺少原子更改并且不支持文件系统层次的版本控制,所以不" "可能完全精确的重建CVS的历史。有些需要猜测,重命名通常发现不了。因为CVS的很多的" "高级管理功能必须手动完成,因此非常容易出错。碰到崩溃的版本库,CVS导入程序通常" "会出现很多问题(完全伪造的版本时间戳,若干文件被锁定十多年,这是我个人经历的两" "个不太有趣的问题)。" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch01-intro.xml:572 msgid "Mercurial can import revision history from a CVS repository." msgstr "Mercurial可以从CVS版本库导入版本历史。" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch01-intro.xml:578 msgid "Commercial tools" msgstr "商业工具" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch01-intro.xml:580 msgid "" "Perforce has a centralised client/server architecture, with no client-side " "caching of any data. Unlike modern revision control tools, Perforce requires " "that a user run a command to inform the server about every file they intend " "to edit." msgstr "" "Perforce采用的是集中式客户/服务器结构,客户端不缓存任何数据。和现代的版本控制" "工具不同,每次想要编辑的一个文件,用户必须运行一个命令通知Perforce服务器。" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch01-intro.xml:586 msgid "" "The performance of Perforce is quite good for small teams, but it falls off " "rapidly as the number of users grows beyond a few dozen. Modestly large " "Perforce installations require the deployment of proxies to cope with the " "load their users generate." msgstr "" "对于小的团队而言,Perforce相当好,但是当用户数目超过数十个以后,性能急剧下降。" "中等大小Perforce安装需要部署代理来处理用户产生的负载。" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch01-intro.xml:595 msgid "Choosing a revision control tool" msgstr "选择版本控制工具" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch01-intro.xml:597 msgid "" "With the exception of CVS, all of the tools listed above have unique " "strengths that suit them to particular styles of work. There is no single " "revision control tool that is best in all situations." msgstr "" "除了CVS之外,以上列出的所有工具都各有所长,没有一个版本控制工具适合所有情况。" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch01-intro.xml:602 msgid "" "As an example, Subversion is a good choice for working with frequently edited " "binary files, due to its centralised nature and support for file locking." msgstr "" "比如说,因为采用集中式的结构并且支持文件锁定,Subversion非常适合频繁编辑二进制" "文件的场合。" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch01-intro.xml:606 msgid "" "I personally find Mercurial's properties of simplicity, performance, and good " "merge support to be a compelling combination that has served me well for " "several years." msgstr "" "我已经使用Mercurial很多年了,个人认为它有简洁,高性能,良好的合并支持诸多特" "点。" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch01-intro.xml:614 msgid "Switching from another tool to Mercurial" msgstr "从其它工具切换到 Mercurial" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch01-intro.xml:616 msgid "" "Mercurial is bundled with an extension named <literal role=\"hg-ext" "\">convert</literal>, which can incrementally import revision history from " "several other revision control tools. By <quote>incremental</quote>, I mean " "that you can convert all of a project's history to date in one go, then rerun " "the conversion later to obtain new changes that happened after the initial " "conversion." msgstr "" "Mercurial包括一个叫<literal role=\"hg-ext\">convert</literal>的扩展,它可以递" "增的从几个其他的版本控制工具导入版本历史。 <quote>增量</quote>的意思是你可以在" "某天将整个项目历史转换,以后再次进行转换获得初始版本以后新增的变更。" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch01-intro.xml:624 msgid "" "The revision control tools supported by <literal role=\"hg-ext\">convert</" "literal> are as follows:" msgstr "<literal role=\"hg-ext\">convert</literal> 支持的版本控制工具有:" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch01-intro.xml:632 msgid "" "In addition, <literal role=\"hg-ext\">convert</literal> can export changes " "from Mercurial to Subversion. This makes it possible to try Subversion and " "Mercurial in parallel before committing to a switchover, without risking the " "loss of any work." msgstr "" "另外<literal role=\"hg-ext\">convert</literal>可以从Mercurial向Subversion导出" "历史,这可以让你在切换之前让Mercurial和Subversion并行工作,而不会丢失任何工" "作。" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch01-intro.xml:638 msgid "" "The <command role=\"hg-ext-convert\">convert</command> command is easy to " "use. Simply point it at the path or URL of the source repository, optionally " "give it the name of the destination repository, and it will start working. " "After the initial conversion, just run the same command again to import new " "changes." msgstr "" "<command role=\"hg-ext-convert\">convert</command>命令非常简单。只要给出源版本" "库的URL或者路径,给出目标版本库的名称(可选),它就开始工作了。第一次转换之" "后,只要运行同样的命令就可以导入新的变更。" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch01-intro.xml:647 msgid "A short history of revision control" msgstr "版本控制简史" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch01-intro.xml:649 msgid "" "The best known of the old-time revision control tools is SCCS (Source Code " "Control System), which Marc Rochkind wrote at Bell Labs, in the early 1970s. " "SCCS operated on individual files, and required every person working on a " "project to have access to a shared workspace on a single system. Only one " "person could modify a file at any time; arbitration for access to files was " "via locks. It was common for people to lock files, and later forget to " "unlock them, preventing anyone else from modifying those files without the " "help of an administrator." msgstr "" "最有名史前的版本控制工具是SCCS(源代码控制系统),它是由Marc Rochkind于七十年" "代在贝尔实验室完成的。SCCS只能控制单个文件,这就要求项目组人员只能使用一个系统" "上的共享工作空间。任何时候一个文件只能由一个人修改;通过加锁来保证。人们很容易" "锁定一个文件,然后忘了解锁,没有管理员的帮助,任何人都不能修改那些文件。" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch01-intro.xml:660 msgid "" "Walter Tichy developed a free alternative to SCCS in the early 1980s; he " "called his program RCS (Revision Control System). Like SCCS, RCS required " "developers to work in a single shared workspace, and to lock files to prevent " "multiple people from modifying them simultaneously." msgstr "" "Walter Tichy在八十年代早期开发了一个开源的SCCS替代软件;他称之RCS(版本控制系" "统)。和SCCS一样,RCS要求开发人员在一个共享的工作空间工作,同时锁定文件,以防" "止多个人他同时修改。" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch01-intro.xml:666 msgid "" "Later in the 1980s, Dick Grune used RCS as a building block for a set of " "shell scripts he initially called cmt, but then renamed to CVS (Concurrent " "Versions System). The big innovation of CVS was that it let developers work " "simultaneously and somewhat independently in their own personal workspaces. " "The personal workspaces prevented developers from stepping on each other's " "toes all the time, as was common with SCCS and RCS. Each developer had a copy " "of every project file, and could modify their copies independently. They had " "to merge their edits prior to committing changes to the central repository." msgstr "" "八十年代后期,Dick Grune在RCS的基础上开发了一套脚本,他开始称之为cmt,后来又改" "名为CVS(并行版本系统)。CVS的最大的创新在于让开发人员可以在自己的工作空间里同" "时而且独立的工作。私人的工作空间防止了开发人员总是互相干扰,这在SCCS和RCS的使" "用中很常见。项目中的每个文件,开发者都有自己的拷贝,可以独立的修改自己的拷贝。" "他们可以在提交到中央版本库之前合并更改。" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch01-intro.xml:677 msgid "" "Brian Berliner took Grune's original scripts and rewrote them in C, releasing " "in 1989 the code that has since developed into the modern version of CVS. " "CVS subsequently acquired the ability to operate over a network connection, " "giving it a client/server architecture. CVS's architecture is centralised; " "only the server has a copy of the history of the project. Client workspaces " "just contain copies of recent versions of the project's files, and a little " "metadata to tell them where the server is. CVS has been enormously " "successful; it is probably the world's most widely used revision control " "system." msgstr "" "Brian Berliner接管了Grune的脚本,用C重写了一遍,并在1989年发布了这些代码,现在" "的CVS就是从那时逐渐发展起来的。CVS随后增加了网络的功能,形成了客户/服务器结" "构。CVS的结构是集中式的;仅在服务器上保存一份项目的历史拷贝。客户工作空间仅包" "含项目中的文件的最近版本的拷贝,一些元数据告诉它们服务器的地址。CVS获得了极大" "成功;它可能是世界上应用最广泛的版本控制系统。" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch01-intro.xml:688 msgid "" "In the early 1990s, Sun Microsystems developed an early distributed revision " "control system, called TeamWare. A TeamWare workspace contains a complete " "copy of the project's history. TeamWare has no notion of a central " "repository. (CVS relied upon RCS for its history storage; TeamWare used " "SCCS.)" msgstr "" "90年代早期,Sun公司开发了一个早期的分布式版本控制系统,叫做TeamWeare。TeamWare" "的工作空间包括项目历史的完整拷贝。TeamWare没有中央版本库的概念。(CVS使用RCS存" "储其历史,TeamWare使用SCCS。" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch01-intro.xml:695 msgid "" "As the 1990s progressed, awareness grew of a number of problems with CVS. It " "records simultaneous changes to multiple files individually, instead of " "grouping them together as a single logically atomic operation. It does not " "manage its file hierarchy well; it is easy to make a mess of a repository by " "renaming files and directories. Worse, its source code is difficult to read " "and maintain, which made the <quote>pain level</quote> of fixing these " "architectural problems prohibitive." msgstr "" "在90年代中,随着时间的流逝,CVS逐渐暴露出很多问题。它对多个文件同时发生的变更" "不能一起记录,不能按照层次管理文件;对目录和文件的重命名很容易破坏版本库。更糟" "的是,它的源代码很难阅读和维护,修复这些架构上的问题的非常困难。" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch01-intro.xml:705 msgid "" "In 2001, Jim Blandy and Karl Fogel, two developers who had worked on CVS, " "started a project to replace it with a tool that would have a better " "architecture and cleaner code. The result, Subversion, does not stray from " "CVS's centralised client/server model, but it adds multi-file atomic commits, " "better namespace management, and a number of other features that make it a " "generally better tool than CVS. Since its initial release, it has rapidly " "grown in popularity." msgstr "" "2001年,原来维护过CVS的两个开发者Jim Blandy和Karl Fogel,开始了一个新项目,其" "目标是替代CVS,新的软件将采用更好的架构和更整洁的代码。于是Subversion诞生了," "它并保留了CVS集中式的客户/服务器模型,但是增加了多文件原子提交,更好的命名空间" "管理,和其他一些功能。总而言之,它比CVS好的多。Subversion在发布后迅速流行起" "来。" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch01-intro.xml:714 msgid "" "More or less simultaneously, Graydon Hoare began working on an ambitious " "distributed revision control system that he named Monotone. While Monotone " "addresses many of CVS's design flaws and has a peer-to-peer architecture, it " "goes beyond earlier (and subsequent) revision control tools in a number of " "innovative ways. It uses cryptographic hashes as identifiers, and has an " "integral notion of <quote>trust</quote> for code from different sources." msgstr "" "大概相同时间,Graydon Hoare开始了一个野心勃勃的分布式版本控制项目,他称之为" "Monotone。Monotone解决了很多CVS设计上的漏洞并且采用了点对点的架构,它在创新方" "面比以前(和以后)的版本控制系统走的更远。它使用加密哈希作为标识符,并且对于不" "同源的代码有了完整的 <quote>信任</quote>概念。" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch01-intro.xml:723 msgid "" "Mercurial began life in 2005. While a few aspects of its design are " "influenced by Monotone, Mercurial focuses on ease of use, high performance, " "and scalability to very large projects." msgstr "" "Mercurial诞生于2005年。设计方面受了Monotone的一些影响,Mercurial的目标是易用," "高性能,对大的项目的良好扩展性。" #. type: Content of: <book><chapter><title> #: ../en/ch02-tour-basic.xml:5 msgid "A tour of Mercurial: the basics" msgstr "Mercurial 教程: 基础知识" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch02-tour-basic.xml:8 msgid "Installing Mercurial on your system" msgstr "安装 Mercurial" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch02-tour-basic.xml:10 msgid "" "Prebuilt binary packages of Mercurial are available for every popular " "operating system. These make it easy to start using Mercurial on your " "computer immediately." msgstr "" "对于每种流行的操作系统,都有已经构建的二进制软件包。这让在你的计算机上开始使" "用 Mercurial 变得很容易。" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch02-tour-basic.xml:15 msgid "Windows" msgstr "Windows" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:17 msgid "" "The best version of Mercurial for Windows is TortoiseHg, which can be found " "at <ulink url=\"http://bitbucket.org/tortoisehg/stable/wiki/Home\">http://" "bitbucket.org/tortoisehg/stable/wiki/Home</ulink>. This package has no " "external dependencies; it <quote>just works</quote>. It provides both " "command line and graphical user interfaces." msgstr "" "Windows 中最好的 Mercurial 版本是TortoiseHg,它的主页地址是 <ulink url=" "\"http://bitbucket.org/tortoisehg/stable/wiki/Home\">http://bitbucket.org/" "tortoisehg/stable/wiki/Home</ulink>。这个软件没有外部依赖,它可以<quote>独立工" "作</quote>,同时提供了命令行和图形用户界面。" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch02-tour-basic.xml:27 msgid "Mac OS X" msgstr "Mac OS X" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:29 msgid "" "Lee Cantey publishes an installer of Mercurial for Mac OS X at <ulink url=" "\"http://mercurial.berkwood.com\">http://mercurial.berkwood.com</ulink>." msgstr "" "Lee Cantey 为 Mac OS X 在 <ulink url=\"http://mercurial.berkwood.com" "\">http://mercurial.berkwood.com</ulink> 发布了 Mercurial 安装程序。" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch02-tour-basic.xml:35 msgid "Linux" msgstr "Linux" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:37 msgid "" "Because each Linux distribution has its own packaging tools, policies, and " "rate of development, it's difficult to give a comprehensive set of " "instructions on how to install Mercurial binaries. The version of Mercurial " "that you will end up with can vary depending on how active the person is who " "maintains the package for your distribution." msgstr "" "由于每种 Linux 发行版都有自己的包管理工具,开发策略和进度,从而很难给出安装 " "Mercurial 二进制包的全面说明。你安装的 Mercurial 版本,在很大程度上依赖于你所" "使用的发行版的 Mercurial 维护者的活跃程度。" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:44 msgid "" "To keep things simple, I will focus on installing Mercurial from the command " "line under the most popular Linux distributions. Most of these distributions " "provide graphical package managers that will let you install Mercurial with a " "single click; the package name to look for is <literal>mercurial</literal>." msgstr "" "为了让事情简单,我会致力于说明在最流行的 Linux 发行版中,从命令行安装 " "Mercurial 的方法。这些发行版都提供了图形界面的包管理器,让你通过点击鼠标安装 " "Mercurial;寻找的包名称是 <literal>mercurial</literal>。" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch02-tour-basic.xml:52 msgid "Ubuntu and Debian:" msgstr "Ubuntu 与 Debian:" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch02-tour-basic.xml:54 msgid "Fedora:" msgstr "Fedora:" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch02-tour-basic.xml:56 msgid "OpenSUSE:" msgstr "OpenSUSE:" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch02-tour-basic.xml:58 msgid "Gentoo:" msgstr "Gentoo:" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch02-tour-basic.xml:64 msgid "Solaris" msgstr "Solaris" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:66 msgid "" "SunFreeWare, at <ulink url=\"http://www.sunfreeware.com\">http://www." "sunfreeware.com</ulink>, provides prebuilt packages of Mercurial." msgstr "" "位于 <ulink url=\"http://www.sunfreeware.com\">http://www.sunfreeware.com</" "ulink> 的 SunFreeWare 提供了 Mercurial 的二进制安装包。" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch02-tour-basic.xml:75 msgid "Getting started" msgstr "开始" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch02-tour-basic.xml:77 msgid "" "To begin, we'll use the <command role=\"hg-cmd\">hg version</command> command " "to find out whether Mercurial is installed properly. The actual version " "information that it prints isn't so important; we simply care whether the " "command runs and prints anything at all." msgstr "" "首先,我们使用 <command role=\"hg-cmd\">hg version</command> 命令检查 " "Mercurial 是否已经正确安装。它打印出来的实际版本信息并不重要;我们只关心它是否" "能够运行,打印出信息。" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch02-tour-basic.xml:86 msgid "Built-in help" msgstr "内置帮助" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:88 msgid "" "Mercurial provides a built-in help system. This is invaluable for those " "times when you find yourself stuck trying to remember how to run a command. " "If you are completely stuck, simply run <command role=\"hg-cmd\">hg help</" "command>; it will print a brief list of commands, along with a description of " "what each does. If you ask for help on a specific command (as below), it " "prints more detailed information." msgstr "" "Mercurial 内置了帮助系统。当你不记得如何执行一个命令时,它会给你重要的帮助。如" "果你完全没有头绪,那就直接运行 <command role=\"hg-cmd\">hg help</command>;它" "会给出命令的简短列表,还描述了每个命令的作用。如果你需要具体命令的帮助(下述)," "它会给出更详细的信息。" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:99 msgid "" "For a more impressive level of detail (which you won't usually need) run " "<command role=\"hg-cmd\">hg help <option role=\"hg-opt-global\">-v</option></" "command>. The <option role=\"hg-opt-global\">-v</option> option is short for " "<option role=\"hg-opt-global\">--verbose</option>, and tells Mercurial to " "print more information than it usually would." msgstr "" "要获得更多的详细信息(通常不需要),可以执行 <command role=\"hg-cmd\">hg help " "<option role=\"hg-opt-global\">-v</option></command>。选项 <option role=\"hg-" "opt-global\">-v</option> 是 <option role=\"hg-opt-global\">--verbose</option> " "的短格式,告诉 Mercurial 要打印通常不需要的更多信息。" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch02-tour-basic.xml:110 msgid "Working with a repository" msgstr "使用版本库" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch02-tour-basic.xml:112 msgid "" "In Mercurial, everything happens inside a <emphasis>repository</emphasis>. " "The repository for a project contains all of the files that <quote>belong to</" "quote> that project, along with a historical record of the project's files." msgstr "在Mercurial中,所有的操作都在<emphasis>版本库</emphasis>中进行。" "项目的版本库包括了属于该项目的所有文件和这些文件的历史记录。" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch02-tour-basic.xml:118 msgid "" "There's nothing particularly magical about a repository; it is simply a " "directory tree in your filesystem that Mercurial treats as special. You can " "rename or delete a repository any time you like, using either the command " "line or your file browser." msgstr "版本库没有什么神秘的地方;仅仅是你系统中的一个目录树,Mercurial会将它们特殊处理。" "你可以在任何喜欢的时候使用命令行或者文件浏览器删除版本库或者给它改名。" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch02-tour-basic.xml:125 msgid "Making a local copy of a repository" msgstr "创建版本库的工作副本" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:127 msgid "" "<emphasis>Copying</emphasis> a repository is just a little bit special. " "While you could use a normal file copying command to make a copy of a " "repository, it's best to use a built-in command that Mercurial provides. " "This command is called <command role=\"hg-cmd\">hg clone</command>, because " "it makes an identical copy of an existing repository." msgstr "<emphasis>拷贝</emphasis>版本库有点特殊。虽然你可以使用文件拷贝命令来复制" "一般版本库,最好还是用Mercurial内置的命令。这个命令叫做 <command role=\"hg-cmd\">hg clone</command>" ",因为它创建了一个原来版本库的拷贝。" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:136 msgid "" "One advantage of using <command role=\"hg-cmd\">hg clone</command> is that, " "as we can see above, it lets us clone repositories over the network. Another " "is that it remembers where we cloned from, which we'll find useful soon when " "we want to fetch new changes from another repository." msgstr "如上所示,使用<command role=\"hg-cmd\">hg clone</command>的好处在于它能够让你" "通过网络克隆版本库。另外一个好处你它会记得这个版本库是从哪里克隆的,稍后会看到,当" "我们想从其他的版本库获取新的变更的时候这点这会非常有用。" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:142 msgid "" "If our clone succeeded, we should now have a local directory called <filename " "class=\"directory\">hello</filename>. This directory will contain some files." msgstr "如果我们克隆成功,我们会得到一个本地目录,叫做 <filename " "class=\"directory\">hello</filename>。这个目录会包括一些文件。" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:148 msgid "" "These files have the same contents and history in our repository as they do " "in the repository we cloned." msgstr "这个版本库中的文件和我们刚才克隆的版本库中的文件相同的内容和版本历史" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:151 msgid "" "Every Mercurial repository is complete, self-contained, and independent. It " "contains its own private copy of a project's files and history. As we just " "mentioned, a cloned repository remembers the location of the repository it " "was cloned from, but Mercurial will not communicate with that repository, or " "any other, unless you tell it to." msgstr "每个Mercurial版本库都是完整的,自包含的,独立的。它包含了项目文件的一份私有" "拷贝和全部历史。我们刚才已经提到,克隆的版本库会记住它克隆的那个版本库的地址,但是" "Mercurial不会和那个或者其他任何一个版本库通信,除非你给它命令。" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:158 msgid "" "What this means for now is that we're free to experiment with our repository, " "safe in the knowledge that it's a private <quote>sandbox</quote> that won't " "affect anyone else." msgstr "这意味着,我们可以随意的在我们的版本库中做实验,非常安全,因为它是一个私有的" "<quote>沙盒</quote>,不会影响任何人。" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch02-tour-basic.xml:164 msgid "What's in a repository?" msgstr "什么是版本库?" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:166 msgid "" "When we take a more detailed look inside a repository, we can see that it " "contains a directory named <filename class=\"directory\">.hg</filename>. " "This is where Mercurial keeps all of its metadata for the repository." msgstr "当我们仔细观察版本库内部时,我们会发现它有一个叫" "<filename class=\"directory\">.hg</filename>的目录。" "这就是Mercurial为版本库保存所有元数据的地方。" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:173 msgid "" "The contents of the <filename class=\"directory\">.hg</filename> directory " "and its subdirectories are private to Mercurial. Every other file and " "directory in the repository is yours to do with as you please." msgstr "目录<filename class=\"directory\">.hg</filename>" "中的内容和其子目录是Mercurial私有的。版本库中的其他任何文件和目录你都可以随意操作。" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:179 msgid "" "To introduce a little terminology, the <filename class=\"directory\">.hg</" "filename> directory is the <quote>real</quote> repository, and all of the " "files and directories that coexist with it are said to live in the " "<emphasis>working directory</emphasis>. An easy way to remember the " "distinction is that the <emphasis>repository</emphasis> contains the " "<emphasis>history</emphasis> of your project, while the <emphasis>working " "directory</emphasis> contains a <emphasis>snapshot</emphasis> of your project " "at a particular point in history." msgstr "介绍一点术语, <filename class=\"directory\">.hg</filename>目录是" "<quote>真正的</quote>版本库,所有其他的文件和目录称为<emphasis>工作目录</emphasis>" "一个简单的区分的方法就是<emphasis>版本库</emphasis>中包含了项目的<emphasis>历史</emphasis>" ",而 <emphasis>工作目录</emphasis>则是项目组一个特定历史点上的<emphasis>快照</emphasis>。" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch02-tour-basic.xml:194 msgid "A tour through history" msgstr "回溯历史" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch02-tour-basic.xml:196 msgid "" "One of the first things we might want to do with a new, unfamiliar repository " "is understand its history. The <command role=\"hg-cmd\">hg log</command> " "command gives us a view of the history of changes in the repository." msgstr "对于一个新的,我们不熟悉的版本库,我们想做的第一件事就是了解它的历史。" "命令<command role=\"hg-cmd\">hg log</command>可以让我们浏览版本库中的历史变更。" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch02-tour-basic.xml:203 msgid "" "By default, this command prints a brief paragraph of output for each change " "to the project that was recorded. In Mercurial terminology, we call each of " "these recorded events a <emphasis>changeset</emphasis>, because it can " "contain a record of changes to several files." msgstr "缺省情况下,这个命令对项目中记录的每个变更都输出一段简介,在Mercurial" "的术语中,我们将这些记录的事件成为<emphasis>变更集</emphasis>,因为每个记录都" "可能包括几个文件的变更。" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch02-tour-basic.xml:209 msgid "" "The fields in a record of output from <command role=\"hg-cmd\">hg log</" "command> are as follows." msgstr " <command role=\"hg-cmd\">hg log</command>输出记录的各个字段的意义如下。" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch02-tour-basic.xml:213 msgid "" "<literal>changeset</literal>: This field has the format of a number, followed " "by a colon, followed by a hexadecimal (or <emphasis>hex</emphasis>) string. " "These are <emphasis>identifiers</emphasis> for the changeset. The hex string " "is a unique identifier: the same hex string will always refer to the same " "changeset in every copy of this repository. The number is shorter and easier " "to type than the hex string, but it isn't unique: the same number in two " "different clones of a repository may identify different changesets." msgstr "<literal>changeset</literal>:这个字段包括一个数字,接着一个冒号,然后是" "是一个十六进制字符串。这是这个变更的<emphasis>标识符</emphasis>。十六进制字符串" "是唯一标识符:在这个版本库的每个拷贝中,同一个字符串总是对应同一个变更集。数字更简单" "并且比十六进制字符串更容易书写,但它不是唯一的:一个版本库的两个不同的的克隆中的" "同一个数字可能对应不同的变更集。" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch02-tour-basic.xml:224 msgid "" "<literal>user</literal>: The identity of the person who created the " "changeset. This is a free-form field, but it most often contains a person's " "name and email address." msgstr "<literal>user</literal>:这个字段标识是谁创建了这个变更集。这个字段格式可以自由定义," "通常是一个人的姓名加上电子邮件地址。" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch02-tour-basic.xml:228 msgid "" "<literal>date</literal>: The date and time on which the changeset was " "created, and the timezone in which it was created. (The date and time are " "local to that timezone; they display what time and date it was for the person " "who created the changeset.)" msgstr "这个变更集创建的日期和时间,还有时区。(日期和时间是相对于时区的;" ""他们现实了创建变更的人的日期和时间。) #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch02-tour-basic.xml:233 msgid "" "<literal>summary</literal>: The first line of the text message that the " "creator of the changeset entered to describe the changeset." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch02-tour-basic.xml:237 msgid "" "Some changesets, such as the first in the list above, have a <literal>tag</" "literal> field. A tag is another way to identify a changeset, by giving it " "an easy-to-remember name. (The tag named <literal>tip</literal> is special: " "it always refers to the newest change in a repository.)" msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch02-tour-basic.xml:245 msgid "" "The default output printed by <command role=\"hg-cmd\">hg log</command> is " "purely a summary; it is missing a lot of detail." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch02-tour-basic.xml:249 msgid "" "<xref linkend=\"fig:tour-basic:history\"/> provides a graphical " "representation of the history of the <filename class=\"directory\">hello</" "filename> repository, to make it a little easier to see which direction " "history is <quote>flowing</quote> in. We'll be returning to this figure " "several times in this chapter and the chapter that follows." msgstr "" #. type: Content of: <book><chapter><sect1><figure><title> #: ../en/ch02-tour-basic.xml:258 msgid "" "Graphical history of the <filename class=\"directory\">hello</filename> " "repository" msgstr "版本库 <filename class=\"directory\">hello</filename> 的历史图" #. type: Content of: <book><chapter><sect1><figure> #: ../en/ch02-tour-basic.xml:260 ../en/ch03-tour-merge.xml:61 #: ../en/ch03-tour-merge.xml:207 ../en/ch04-concepts.xml:290 msgid "<placeholder type=\"mediaobject\" id=\"0\"/>" msgstr "" #. type: Content of: <book><chapter><sect1><figure><mediaobject> #: ../en/ch02-tour-basic.xml:261 msgid "" "<imageobject><imagedata fileref=\"figs/tour-history.png\"/></imageobject>" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><figure><mediaobject><textobject><phrase> #: ../en/ch02-tour-basic.xml:262 ../en/ch03-tour-merge.xml:63 #: ../en/ch03-tour-merge.xml:95 ../en/ch03-tour-merge.xml:182 #: ../en/ch03-tour-merge.xml:209 ../en/ch03-tour-merge.xml:279 #: ../en/ch04-concepts.xml:59 ../en/ch04-concepts.xml:108 #: ../en/ch04-concepts.xml:198 ../en/ch04-concepts.xml:292 #: ../en/ch04-concepts.xml:347 ../en/ch04-concepts.xml:362 #: ../en/ch04-concepts.xml:403 ../en/ch04-concepts.xml:423 #: ../en/ch04-concepts.xml:469 ../en/ch06-collab.xml:316 #: ../en/ch09-undo.xml:344 ../en/ch09-undo.xml:391 ../en/ch09-undo.xml:464 #: ../en/ch09-undo.xml:502 ../en/ch09-undo.xml:658 ../en/ch09-undo.xml:682 #: ../en/ch09-undo.xml:700 ../en/ch09-undo.xml:714 ../en/ch09-undo.xml:727 #: ../en/ch12-mq.xml:413 msgid "XXX add text" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch02-tour-basic.xml:267 msgid "Changesets, revisions, and talking to other people" msgstr "修改集,版本,与其它用户交互" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:270 msgid "" "As English is a notoriously sloppy language, and computer science has a " "hallowed history of terminological confusion (why use one term when four will " "do?), revision control has a variety of words and phrases that mean the same " "thing. If you are talking about Mercurial history with other people, you " "will find that the word <quote>changeset</quote> is often compressed to " "<quote>change</quote> or (when written) <quote>cset</quote>, and sometimes a " "changeset is referred to as a <quote>revision</quote> or a <quote>rev</quote>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:280 msgid "" "While it doesn't matter what <emphasis>word</emphasis> you use to refer to " "the concept of <quote>a changeset</quote>, the <emphasis>identifier</" "emphasis> that you use to refer to <quote>a <emphasis>specific</emphasis> " "changeset</quote> is of great importance. Recall that the <literal>changeset</" "literal> field in the output from <command role=\"hg-cmd\">hg log</command> " "identifies a changeset using both a number and a hexadecimal string." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch02-tour-basic.xml:289 msgid "" "The revision number is a handy notation that is <emphasis>only valid in that " "repository</emphasis>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch02-tour-basic.xml:292 msgid "" "The hexadecimal string is the <emphasis>permanent, unchanging identifier</" "emphasis> that will always identify that exact changeset in <emphasis>every</" "emphasis> copy of the repository." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:298 msgid "" "This distinction is important. If you send someone an email talking about " "<quote>revision 33</quote>, there's a high likelihood that their revision 33 " "will <emphasis>not be the same</emphasis> as yours. The reason for this is " "that a revision number depends on the order in which changes arrived in a " "repository, and there is no guarantee that the same changes will happen in " "the same order in different repositories. Three changes <literal>a,b,c</" "literal> can easily appear in one repository as <literal>0,1,2</literal>, " "while in another as <literal>0,2,1</literal>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:310 msgid "" "Mercurial uses revision numbers purely as a convenient shorthand. If you " "need to discuss a changeset with someone, or make a record of a changeset for " "some other reason (for example, in a bug report), use the hexadecimal " "identifier." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch02-tour-basic.xml:318 msgid "Viewing specific revisions" msgstr "察看指定版本" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:320 msgid "" "To narrow the output of <command role=\"hg-cmd\">hg log</command> down to a " "single revision, use the <option role=\"hg-opt-log\">-r</option> (or <option " "role=\"hg-opt-log\">--rev</option>) option. You can use either a revision " "number or a hexadecimal identifier, and you can provide as many revisions as " "you want." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:329 msgid "" "If you want to see the history of several revisions without having to list " "each one, you can use <emphasis>range notation</emphasis>; this lets you " "express the idea <quote>I want all revisions between <literal>abc</literal> " "and <literal>def</literal>, inclusive</quote>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:337 msgid "" "Mercurial also honours the order in which you specify revisions, so <command " "role=\"hg-cmd\">hg log -r 2:4</command> prints 2, 3, and 4. while <command " "role=\"hg-cmd\">hg log -r 4:2</command> prints 4, 3, and 2." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch02-tour-basic.xml:344 msgid "More detailed information" msgstr "更详细的信息" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:346 msgid "" "While the summary information printed by <command role=\"hg-cmd\">hg log</" "command> is useful if you already know what you're looking for, you may need " "to see a complete description of the change, or a list of the files changed, " "if you're trying to decide whether a changeset is the one you're looking for. " "The <command role=\"hg-cmd\">hg log</command> command's <option role=\"hg-opt-" "global\">-v</option> (or <option role=\"hg-opt-global\">--verbose</option>) " "option gives you this extra detail." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:358 msgid "" "If you want to see both the description and content of a change, add the " "<option role=\"hg-opt-log\">-p</option> (or <option role=\"hg-opt-log\">--" "patch</option>) option. This displays the content of a change as a " "<emphasis>unified diff</emphasis> (if you've never seen a unified diff " "before, see <xref linkend=\"sec:mq:patch\"/> for an overview)." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:368 msgid "" "The <option role=\"hg-opt-log\">-p</option> option is tremendously useful, so " "it's well worth remembering." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch02-tour-basic.xml:375 msgid "All about command options" msgstr "命令选项" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch02-tour-basic.xml:377 msgid "" "Let's take a brief break from exploring Mercurial commands to discuss a " "pattern in the way that they work; you may find this useful to keep in mind " "as we continue our tour." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch02-tour-basic.xml:381 msgid "" "Mercurial has a consistent and straightforward approach to dealing with the " "options that you can pass to commands. It follows the conventions for " "options that are common to modern Linux and Unix systems." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch02-tour-basic.xml:388 msgid "" "Every option has a long name. For example, as we've already seen, the " "<command role=\"hg-cmd\">hg log</command> command accepts a <option role=\"hg-" "opt-log\">--rev</option> option." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch02-tour-basic.xml:394 msgid "" "Most options have short names, too. Instead of <option role=\"hg-opt-log\">--" "rev</option>, we can use <option role=\"hg-opt-log\">-r</option>. (The " "reason that some options don't have short names is that the options in " "question are rarely used.)" msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch02-tour-basic.xml:401 msgid "" "Long options start with two dashes (e.g. <option role=\"hg-opt-log\">--rev</" "option>), while short options start with one (e.g. <option role=\"hg-opt-log" "\">-r</option>)." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch02-tour-basic.xml:407 msgid "" "Option naming and usage is consistent across commands. For example, every " "command that lets you specify a changeset ID or revision number accepts both " "<option role=\"hg-opt-log\">-r</option> and <option role=\"hg-opt-log\">--" "rev</option> arguments." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch02-tour-basic.xml:414 msgid "" "If you are using short options, you can save typing by running them together. " "For example, the command <command role=\"hg-cmd\">hg log -v -p -r 2</command> " "can be written as <command role=\"hg-cmd\">hg log -vpr2</command>." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch02-tour-basic.xml:421 msgid "" "In the examples throughout this book, I usually use short options instead of " "long. This simply reflects my own preference, so don't read anything " "significant into it." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch02-tour-basic.xml:425 msgid "" "Most commands that print output of some kind will print more output when " "passed a <option role=\"hg-opt-global\">-v</option> (or <option role=\"hg-opt-" "global\">--verbose</option>) option, and less when passed <option role=\"hg-" "opt-global\">-q</option> (or <option role=\"hg-opt-global\">--quiet</option>)." msgstr "" #. type: Content of: <book><chapter><sect1><note><title> #: ../en/ch02-tour-basic.xml:432 msgid "Option naming consistency" msgstr "" #. type: Content of: <book><chapter><sect1><note><para> #: ../en/ch02-tour-basic.xml:434 msgid "" "Almost always, Mercurial commands use consistent option names to refer to the " "same concepts. For instance, if a command deals with changesets, you'll " "always identify them with <option role=\"hg-opt-log\">--rev</option> or " "<option role=\"hg-opt-log\">-r</option>. This consistent use of option names " "makes it easier to remember what options a particular command takes." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch02-tour-basic.xml:445 msgid "Making and reviewing changes" msgstr "创建和复审修改" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch02-tour-basic.xml:447 msgid "" "Now that we have a grasp of viewing history in Mercurial, let's take a look " "at making some changes and examining them." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch02-tour-basic.xml:451 msgid "" "The first thing we'll do is isolate our experiment in a repository of its " "own. We use the <command role=\"hg-cmd\">hg clone</command> command, but we " "don't need to clone a copy of the remote repository. Since we already have a " "copy of it locally, we can just clone that instead. This is much faster than " "cloning over the network, and cloning a local repository uses less disk space " "in most cases, too<placeholder type=\"footnote\" id=\"0\"/>." msgstr "" #. type: Content of: <book><chapter><sect1><para><footnote><para> #: ../en/ch02-tour-basic.xml:458 msgid "" "The saving of space arises when source and destination repositories are on " "the same filesystem, in which case Mercurial will use hardlinks to do copy-on-" "write sharing of its internal metadata. If that explanation meant nothing to " "you, don't worry: everything happens transparently and automatically, and you " "don't need to understand it." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch02-tour-basic.xml:468 msgid "" "As an aside, it's often good practice to keep a <quote>pristine</quote> copy " "of a remote repository around, which you can then make temporary clones of to " "create sandboxes for each task you want to work on. This lets you work on " "multiple tasks in parallel, each isolated from the others until it's complete " "and you're ready to integrate it back. Because local clones are so cheap, " "there's almost no overhead to cloning and destroying repositories whenever " "you want." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch02-tour-basic.xml:477 msgid "" "In our <filename class=\"directory\">my-hello</filename> repository, we have " "a file <filename>hello.c</filename> that contains the classic <quote>hello, " "world</quote> program." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch02-tour-basic.xml:483 msgid "Let's edit this file so that it prints a second line of output." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch02-tour-basic.xml:488 msgid "" "Mercurial's <command role=\"hg-cmd\">hg status</command> command will tell us " "what Mercurial knows about the files in the repository." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch02-tour-basic.xml:494 msgid "" "The <command role=\"hg-cmd\">hg status</command> command prints no output for " "some files, but a line starting with <quote><literal>M</literal></quote> for " "<filename>hello.c</filename>. Unless you tell it to, <command role=\"hg-cmd" "\">hg status</command> will not print any output for files that have not been " "modified." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch02-tour-basic.xml:501 msgid "" "The <quote><literal>M</literal></quote> indicates that Mercurial has noticed " "that we modified <filename>hello.c</filename>. We didn't need to " "<emphasis>inform</emphasis> Mercurial that we were going to modify the file " "before we started, or that we had modified the file after we were done; it " "was able to figure this out itself." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch02-tour-basic.xml:509 msgid "" "It's somewhat helpful to know that we've modified <filename>hello.c</" "filename>, but we might prefer to know exactly <emphasis>what</emphasis> " "changes we've made to it. To do this, we use the <command role=\"hg-cmd\">hg " "diff</command> command." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch02-tour-basic.xml:518 ../en/ch12-mq.xml:187 msgid "Understanding patches" msgstr "理解补丁" #. type: Content of: <book><chapter><sect1><tip><para> #: ../en/ch02-tour-basic.xml:520 msgid "" "Remember to take a look at <xref linkend=\"sec:mq:patch\"/> if you don't know " "how to read output above." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch02-tour-basic.xml:526 msgid "Recording changes in a new changeset" msgstr "在新修改集中记录修改" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch02-tour-basic.xml:528 msgid "" "We can modify files, build and test our changes, and use <command role=\"hg-" "cmd\">hg status</command> and <command role=\"hg-cmd\">hg diff</command> to " "review our changes, until we're satisfied with what we've done and arrive at " "a natural stopping point where we want to record our work in a new changeset." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch02-tour-basic.xml:535 msgid "" "The <command role=\"hg-cmd\">hg commit</command> command lets us create a new " "changeset; we'll usually refer to this as <quote>making a commit</quote> or " "<quote>committing</quote>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch02-tour-basic.xml:541 msgid "Setting up a username" msgstr "配置用户名称" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:543 msgid "" "When you try to run <command role=\"hg-cmd\">hg commit</command> for the " "first time, it is not guaranteed to succeed. Mercurial records your name and " "address with each change that you commit, so that you and others will later " "be able to tell who made each change. Mercurial tries to automatically " "figure out a sensible username to commit the change with. It will attempt " "each of the following methods, in order:" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> #: ../en/ch02-tour-basic.xml:552 msgid "" "If you specify a <option role=\"hg-opt-commit\">-u</option> option to the " "<command role=\"hg-cmd\">hg commit</command> command on the command line, " "followed by a username, this is always given the highest precedence." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> #: ../en/ch02-tour-basic.xml:557 msgid "" "If you have set the <envar>HGUSER</envar> environment variable, this is " "checked next." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> #: ../en/ch02-tour-basic.xml:560 msgid "" "If you create a file in your home directory called <filename role=\"special" "\">.hgrc</filename>, with a <envar role=\"rc-item-ui\">username</envar> " "entry, that will be used next. To see what the contents of this file should " "look like, refer to <xref linkend=\"sec:tour-basic:username\"/> below." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> #: ../en/ch02-tour-basic.xml:568 msgid "" "If you have set the <envar>EMAIL</envar> environment variable, this will be " "used next." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> #: ../en/ch02-tour-basic.xml:571 msgid "" "Mercurial will query your system to find out your local user name and host " "name, and construct a username from these components. Since this often " "results in a username that is not very useful, it will print a warning if it " "has to do this." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:578 msgid "" "If all of these mechanisms fail, Mercurial will fail, printing an error " "message. In this case, it will not let you commit until you set up a " "username." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:582 msgid "" "You should think of the <envar>HGUSER</envar> environment variable and the " "<option role=\"hg-opt-commit\">-u</option> option to the <command role=\"hg-" "cmd\">hg commit</command> command as ways to <emphasis>override</emphasis> " "Mercurial's default selection of username. For normal use, the simplest and " "most robust way to set a username for yourself is by creating a <filename " "role=\"special\">.hgrc</filename> file; see below for details." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><title> #: ../en/ch02-tour-basic.xml:591 msgid "Creating a Mercurial configuration file" msgstr "创建 Mercurial 的配置文件" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch02-tour-basic.xml:593 msgid "" "To set a user name, use your favorite editor to create a file called " "<filename role=\"special\">.hgrc</filename> in your home directory. " "Mercurial will use this file to look up your personalised configuration " "settings. The initial contents of your <filename role=\"special\">.hgrc</" "filename> should look like this." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><tip><title> #: ../en/ch02-tour-basic.xml:602 msgid "<quote>Home directory</quote> on Windows" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><tip><para> #: ../en/ch02-tour-basic.xml:604 msgid "" "When we refer to your home directory, on an English language installation of " "Windows this will usually be a folder named after your user name in " "<filename>C:\\Documents and Settings</filename>. You can find out the exact " "name of your home directory by opening a command prompt window and running " "the following command." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><tip><screen><prompt> #: ../en/ch02-tour-basic.xml:612 msgid "C:\\>" msgstr "C:\\>" #. type: Content of: <book><chapter><sect1><sect2><sect3><tip><screen><userinput> #: ../en/ch02-tour-basic.xml:612 msgid "echo %UserProfile%" msgstr "echo %UserProfile%" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch02-tour-basic.xml:619 msgid "" "The <quote><literal>[ui]</literal></quote> line begins a <emphasis>section</" "emphasis> of the config file, so you can read the <quote><literal>username " "= ...</literal></quote> line as meaning <quote>set the value of the " "<literal>username</literal> item in the <literal>ui</literal> section</" "quote>. A section continues until a new section begins, or the end of the " "file. Mercurial ignores empty lines and treats any text from " "<quote><literal>#</literal></quote> to the end of a line as a comment." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><title> #: ../en/ch02-tour-basic.xml:632 msgid "Choosing a user name" msgstr "选择用户名称" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch02-tour-basic.xml:634 msgid "" "You can use any text you like as the value of the <literal>username</literal> " "config item, since this information is for reading by other people, but will " "not be interpreted by Mercurial. The convention that most people follow is " "to use their name and email address, as in the example above." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><note><para> #: ../en/ch02-tour-basic.xml:641 msgid "" "Mercurial's built-in web server obfuscates email addresses, to make it more " "difficult for the email harvesting tools that spammers use. This reduces the " "likelihood that you'll start receiving more junk email if you publish a " "Mercurial repository on the web." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch02-tour-basic.xml:650 msgid "Writing a commit message" msgstr "写提交日志" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:652 msgid "" "When we commit a change, Mercurial drops us into a text editor, to enter a " "message that will describe the modifications we've made in this changeset. " "This is called the <emphasis>commit message</emphasis>. It will be a record " "for readers of what we did and why, and it will be printed by <command role=" "\"hg-cmd\">hg log</command> after we've finished committing." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:662 msgid "" "The editor that the <command role=\"hg-cmd\">hg commit</command> command " "drops us into will contain an empty line or two, followed by a number of " "lines starting with <quote><literal>HG:</literal></quote>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:676 msgid "" "Mercurial ignores the lines that start with <quote><literal>HG:</literal></" "quote>; it uses them only to tell us which files it's recording changes to. " "Modifying or deleting these lines has no effect." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch02-tour-basic.xml:682 msgid "Writing a good commit message" msgstr "写好提交日志" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:684 msgid "" "Since <command role=\"hg-cmd\">hg log</command> only prints the first line of " "a commit message by default, it's best to write a commit message whose first " "line stands alone. Here's a real example of a commit message that " "<emphasis>doesn't</emphasis> follow this guideline, and hence has a summary " "that is not readable." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:697 msgid "" "As far as the remainder of the contents of the commit message are concerned, " "there are no hard-and-fast rules. Mercurial itself doesn't interpret or care " "about the contents of the commit message, though your project may have " "policies that dictate a certain kind of formatting." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:702 msgid "" "My personal preference is for short, but informative, commit messages that " "tell me something that I can't figure out with a quick glance at the output " "of <command role=\"hg-cmd\">hg log --patch</command>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:706 msgid "" "If we run the <command role=\"hg-cmd\">hg commit</command> command without " "any arguments, it records all of the changes we've made, as reported by " "<command role=\"hg-cmd\">hg status</command> and <command role=\"hg-cmd\">hg " "diff</command>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><note><title> #: ../en/ch02-tour-basic.xml:713 msgid "A surprise for Subversion users" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><note><para> #: ../en/ch02-tour-basic.xml:715 msgid "" "Like other Mercurial commands, if we don't supply explicit names to commit to " "the <command role=\"hg-cmd\">hg commit</command>, it will operate across a " "repository's entire working directory. Be wary of this if you're coming from " "the Subversion or CVS world, since you might expect it to operate only on the " "current directory that you happen to be visiting and its subdirectories." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch02-tour-basic.xml:726 msgid "Aborting a commit" msgstr "终止提交" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:728 msgid "" "If you decide that you don't want to commit while in the middle of editing a " "commit message, simply exit from your editor without saving the file that " "it's editing. This will cause nothing to happen to either the repository or " "the working directory." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch02-tour-basic.xml:736 msgid "Admiring our new handiwork" msgstr "欣赏我们的成果" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:738 msgid "" "Once we've finished the commit, we can use the <command role=\"hg-cmd\">hg " "tip</command> command to display the changeset we just created. This command " "produces output that is identical to <command role=\"hg-cmd\">hg log</" "command>, but it only displays the newest revision in the repository." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:746 msgid "" "We refer to the newest revision in the repository as the <emphasis>tip " "revision</emphasis>, or simply the <emphasis>tip</emphasis>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:750 msgid "" "By the way, the <command role=\"hg-cmd\">hg tip</command> command accepts " "many of the same options as <command role=\"hg-cmd\">hg log</command>, so " "<option role=\"hg-opt-global\">-v</option> above indicates <quote>be verbose</" "quote>, <option role=\"hg-opt-tip\">-p</option> specifies <quote>print a " "patch</quote>. The use of <option role=\"hg-opt-tip\">-p</option> to print " "patches is another example of the consistent naming we mentioned earlier." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch02-tour-basic.xml:762 msgid "Sharing changes" msgstr "共享修改" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch02-tour-basic.xml:764 msgid "" "We mentioned earlier that repositories in Mercurial are self-contained. This " "means that the changeset we just created exists only in our <filename class=" "\"directory\">my-hello</filename> repository. Let's look at a few ways that " "we can propagate this change into other repositories." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch02-tour-basic.xml:772 msgid "Pulling changes from another repository" msgstr "从其它版本库取得修改" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:774 msgid "" "To get started, let's clone our original <filename class=\"directory\">hello</" "filename> repository, which does not contain the change we just committed. " "We'll call our temporary repository <filename class=\"directory\">hello-pull</" "filename>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:782 msgid "" "We'll use the <command role=\"hg-cmd\">hg pull</command> command to bring " "changes from <filename class=\"directory\">my-hello</filename> into <filename " "class=\"directory\">hello-pull</filename>. However, blindly pulling unknown " "changes into a repository is a somewhat scary prospect. Mercurial provides " "the <command role=\"hg-cmd\">hg incoming</command> command to tell us what " "changes the <command role=\"hg-cmd\">hg pull</command> command " "<emphasis>would</emphasis> pull into the repository, without actually pulling " "the changes in." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:795 msgid "" "Bringing changes into a repository is a simple matter of running the <command " "role=\"hg-cmd\">hg pull</command> command, and optionally telling it which " "repository to pull from." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:801 msgid "" "As you can see from the before-and-after output of <command role=\"hg-cmd" "\">hg tip</command>, we have successfully pulled changes into our " "repository. However, Mercurial separates pulling changes in from updating " "the working directory. There remains one step before we will see the changes " "that we just pulled appear in the working directory." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><tip><title> #: ../en/ch02-tour-basic.xml:810 msgid "Pulling specific changes" msgstr "提取指定的修改" #. type: Content of: <book><chapter><sect1><sect2><tip><para> #: ../en/ch02-tour-basic.xml:812 msgid "" "It is possible that due to the delay between running <command role=\"hg-cmd" "\">hg incoming</command> and <command role=\"hg-cmd\">hg pull</command>, you " "may not see all changesets that will be brought from the other repository. " "Suppose you're pulling changes from a repository on the network somewhere. " "While you are looking at the <command role=\"hg-cmd\">hg incoming</command> " "output, and before you pull those changes, someone might have committed " "something in the remote repository. This means that it's possible to pull " "more changes than you saw when using <command role=\"hg-cmd\">hg incoming</" "command>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><tip><para> #: ../en/ch02-tour-basic.xml:824 msgid "" "If you only want to pull precisely the changes that were listed by <command " "role=\"hg-cmd\">hg incoming</command>, or you have some other reason to pull " "a subset of changes, simply identify the change that you want to pull by its " "changeset ID, e.g. <command>hg pull -r7e95bb</command>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch02-tour-basic.xml:834 msgid "Updating the working directory" msgstr "更新工作目录" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:836 msgid "" "We have so far glossed over the relationship between a repository and its " "working directory. The <command role=\"hg-cmd\">hg pull</command> command " "that we ran in <xref linkend=\"sec:tour:pull\"/> brought changes into the " "repository, but if we check, there's no sign of those changes in the working " "directory. This is because <command role=\"hg-cmd\">hg pull</command> does " "not (by default) touch the working directory. Instead, we use the <command " "role=\"hg-cmd\">hg update</command> command to do this." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:848 msgid "" "It might seem a bit strange that <command role=\"hg-cmd\">hg pull</command> " "doesn't update the working directory automatically. There's actually a good " "reason for this: you can use <command role=\"hg-cmd\">hg update</command> to " "update the working directory to the state it was in at <emphasis>any " "revision</emphasis> in the history of the repository. If you had the working " "directory updated to an old revision&emdash;to hunt down the origin of a bug, " "say&emdash;and ran a <command role=\"hg-cmd\">hg pull</command> which " "automatically updated the working directory to a new revision, you might not " "be terribly happy." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:860 msgid "" "Since pull-then-update is such a common sequence of operations, Mercurial " "lets you combine the two by passing the <option role=\"hg-opt-pull\">-u</" "option> option to <command role=\"hg-cmd\">hg pull</command>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:865 msgid "" "If you look back at the output of <command role=\"hg-cmd\">hg pull</command> " "in <xref linkend=\"sec:tour:pull\"/> when we ran it without <option role=\"hg-" "opt-pull\">-u</option>, you can see that it printed a helpful reminder that " "we'd have to take an explicit step to update the working directory." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:872 msgid "" "To find out what revision the working directory is at, use the <command role=" "\"hg-cmd\">hg parents</command> command." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:878 msgid "" "If you look back at <xref linkend=\"fig:tour-basic:history\"/>, you'll see " "arrows connecting each changeset. The node that the arrow leads " "<emphasis>from</emphasis> in each case is a parent, and the node that the " "arrow leads <emphasis>to</emphasis> is its child. The working directory has " "a parent in just the same way; this is the changeset that the working " "directory currently contains." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:887 msgid "" "To update the working directory to a particular revision, give a revision " "number or changeset ID to the <command role=\"hg-cmd\">hg update</command> " "command." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:893 msgid "" "If you omit an explicit revision, <command role=\"hg-cmd\">hg update</" "command> will update to the tip revision, as shown by the second call to " "<command role=\"hg-cmd\">hg update</command> in the example above." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch02-tour-basic.xml:901 msgid "Pushing changes to another repository" msgstr "发布修改到其它版本库" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:903 msgid "" "Mercurial lets us push changes to another repository, from the repository " "we're currently visiting. As with the example of <command role=\"hg-cmd\">hg " "pull</command> above, we'll create a temporary repository to push our changes " "into." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:911 msgid "" "The <command role=\"hg-cmd\">hg outgoing</command> command tells us what " "changes would be pushed into another repository." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:917 msgid "" "And the <command role=\"hg-cmd\">hg push</command> command does the actual " "push." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:922 msgid "" "As with <command role=\"hg-cmd\">hg pull</command>, the <command role=\"hg-cmd" "\">hg push</command> command does not update the working directory in the " "repository that it's pushing changes into. Unlike <command role=\"hg-cmd\">hg " "pull</command>, <command role=\"hg-cmd\">hg push</command> does not provide a " "<literal>-u</literal> option that updates the other repository's working " "directory. This asymmetry is deliberate: the repository we're pushing to " "might be on a remote server and shared between several people. If we were to " "update its working directory while someone was working in it, their work " "would be disrupted." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:934 msgid "" "What happens if we try to pull or push changes and the receiving repository " "already has those changes? Nothing too exciting." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch02-tour-basic.xml:942 msgid "Default locations" msgstr "默认位置" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:944 msgid "" "When we clone a repository, Mercurial records the location of the repository " "we cloned in the <filename>.hg/hgrc</filename> file of the new repository. " "If we don't supply a location to <command>hg pull</command> from or " "<command>hg push</command> to, those commands will use this location as a " "default. The <command>hg incoming</command> and <command>hg outgoing</" "command> commands do so too." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:952 msgid "" "If you open a repository's <filename>.hg/hgrc</filename> file in a text " "editor, you will see contents like the following." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:959 msgid "" "It is possible&emdash;and often useful&emdash;to have the default location " "for <command>hg push</command> and <command>hg outgoing</command> be " "different from those for <command>hg pull</command> and <command>hg incoming</" "command>. We can do this by adding a <literal>default-push</literal> entry " "to the <literal>[paths]</literal> section of the <filename>.hg/hgrc</" "filename> file, as follows." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch02-tour-basic.xml:973 msgid "Sharing changes over a network" msgstr "通过网络共享修改" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:975 msgid "" "The commands we have covered in the previous few sections are not limited to " "working with local repositories. Each works in exactly the same fashion over " "a network connection; simply pass in a URL instead of a local path." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch02-tour-basic.xml:983 msgid "" "In this example, we can see what changes we could push to the remote " "repository, but the repository is understandably not set up to let anonymous " "users push to it." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch02-tour-basic.xml:993 msgid "Starting a new project" msgstr "开始新项目" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch02-tour-basic.xml:995 msgid "" "It is just as easy to begin a new project as to work on one that already " "exists. The <command>hg init</command> command creates a new, empty " "Mercurial repository." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch02-tour-basic.xml:1001 msgid "" "This simply creates a repository named <filename>myproject</filename> in the " "current directory." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch02-tour-basic.xml:1006 msgid "" "We can tell that <filename>myproject</filename> is a Mercurial repository, " "because it contains a <filename>.hg</filename> directory." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch02-tour-basic.xml:1012 msgid "" "If we want to add some pre-existing files to the repository, we copy them " "into place, and tell Mercurial to start tracking them using the <command>hg " "add</command> command." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch02-tour-basic.xml:1018 msgid "" "Once we are satisfied that our project looks right, we commit our changes." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch02-tour-basic.xml:1023 msgid "" "It takes just a few moments to start using Mercurial on a new project, which " "is part of its appeal. Revision control is now so easy to work with, we can " "use it on the smallest of projects that we might not have considered with a " "more complicated tool." msgstr "" #. type: Content of: <book><chapter><title> #: ../en/ch03-tour-merge.xml:5 msgid "A tour of Mercurial: merging work" msgstr "Mercurial 教程: 合并工作" #. type: Content of: <book><chapter><para> #: ../en/ch03-tour-merge.xml:7 msgid "" "We've now covered cloning a repository, making changes in a repository, and " "pulling or pushing changes from one repository into another. Our next step " "is <emphasis>merging</emphasis> changes from separate repositories." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch03-tour-merge.xml:13 msgid "Merging streams of work" msgstr "合并的流程" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch03-tour-merge.xml:15 msgid "" "Merging is a fundamental part of working with a distributed revision control " "tool. Here are a few cases in which the need to merge work arises." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch03-tour-merge.xml:20 msgid "" "Alice and Bob each have a personal copy of a repository for a project they're " "collaborating on. Alice fixes a bug in her repository; Bob adds a new " "feature in his. They want the shared repository to contain both the bug fix " "and the new feature." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch03-tour-merge.xml:27 msgid "" "Cynthia frequently works on several different tasks for a single project at " "once, each safely isolated in its own repository. Working this way means that " "she often needs to merge one piece of her own work with another." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch03-tour-merge.xml:35 msgid "" "Because we need to merge often, Mercurial makes the process easy. Let's walk " "through a merge. We'll begin by cloning yet another repository (see how " "often they spring up?) and making a change in it." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch03-tour-merge.xml:42 msgid "" "We should now have two copies of <filename>hello.c</filename> with different " "contents. The histories of the two repositories have also diverged, as " "illustrated in <xref linkend=\"fig:tour-merge:sep-repos\"/>. Here is a copy " "of our file from one repository." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch03-tour-merge.xml:51 msgid "And here is our slightly different version from the other repository." msgstr "" #. type: Content of: <book><chapter><sect1><figure><title> #: ../en/ch03-tour-merge.xml:57 msgid "" "Divergent recent histories of the <filename class=\"directory\">my-hello</" "filename> and <filename class=\"directory\">my-new-hello</filename> " "repositories" msgstr "" "<filename class=\"directory\">my-hello</filename> 与 <filename class=" "\"directory\">my-new-hello</filename> 最新的历史分叉" #. type: Content of: <book><chapter><sect1><figure><mediaobject> #: ../en/ch03-tour-merge.xml:62 msgid "" "<imageobject><imagedata fileref=\"figs/tour-merge-sep-repos.png\"/></" "imageobject>" msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch03-tour-merge.xml:67 msgid "" "We already know that pulling changes from our <filename class=\"directory" "\">my-hello</filename> repository will have no effect on the working " "directory." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch03-tour-merge.xml:73 msgid "" "However, the <command role=\"hg-cmd\">hg pull</command> command says " "something about <quote>heads</quote>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch03-tour-merge.xml:77 msgid "Head changesets" msgstr "顶点修改集" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch03-tour-merge.xml:79 msgid "" "Remember that Mercurial records what the parent of each change is. If a " "change has a parent, we call it a child or descendant of the parent. A head " "is a change that has no children. The tip revision is thus a head, because " "the newest revision in a repository doesn't have any children. There are " "times when a repository can contain more than one head." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><figure><title> #: ../en/ch03-tour-merge.xml:88 msgid "" "Repository contents after pulling from <filename class=\"directory\">my-" "hello</filename> into <filename class=\"directory\">my-new-hello</filename>" msgstr "" "从 <filename class=\"directory\">my-hello</filename> 拉到 <filename class=" "\"directory\">my-new-hello</filename> 之后版本库的内容" #. type: Content of: <book><chapter><sect1><sect2><figure> #: ../en/ch03-tour-merge.xml:91 ../en/ch03-tour-merge.xml:178 #: ../en/ch03-tour-merge.xml:275 ../en/ch04-concepts.xml:57 #: ../en/ch04-concepts.xml:106 ../en/ch04-concepts.xml:196 #: ../en/ch04-concepts.xml:345 ../en/ch04-concepts.xml:360 #: ../en/ch04-concepts.xml:401 ../en/ch04-concepts.xml:421 #: ../en/ch04-concepts.xml:465 ../en/ch06-collab.xml:314 #: ../en/ch09-undo.xml:342 ../en/ch09-undo.xml:389 ../en/ch09-undo.xml:462 #: ../en/ch09-undo.xml:500 ../en/ch09-undo.xml:656 ../en/ch09-undo.xml:680 #: ../en/ch09-undo.xml:698 ../en/ch09-undo.xml:712 ../en/ch09-undo.xml:725 #: ../en/ch12-mq.xml:411 msgid " <placeholder type=\"mediaobject\" id=\"0\"/>" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><figure><mediaobject> #: ../en/ch03-tour-merge.xml:92 msgid "" "<imageobject> <imagedata fileref=\"figs/tour-merge-pull.png\"/> </imageobject>" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch03-tour-merge.xml:99 msgid "" "In <xref linkend=\"fig:tour-merge:pull\"/>, you can see the effect of the " "pull from <filename class=\"directory\">my-hello</filename> into <filename " "class=\"directory\">my-new-hello</filename>. The history that was already " "present in <filename class=\"directory\">my-new-hello</filename> is " "untouched, but a new revision has been added. By referring to <xref linkend=" "\"fig:tour-merge:sep-repos\"/>, we can see that the <emphasis>changeset ID</" "emphasis> remains the same in the new repository, but the <emphasis>revision " "number</emphasis> has changed. (This, incidentally, is a fine example of why " "it's not safe to use revision numbers when discussing changesets.) We can " "view the heads in a repository using the <command role=\"hg-cmd\">hg heads</" "command> command." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch03-tour-merge.xml:118 msgid "Performing the merge" msgstr "执行合并" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch03-tour-merge.xml:120 msgid "" "What happens if we try to use the normal <command role=\"hg-cmd\">hg update</" "command> command to update to the new tip?" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch03-tour-merge.xml:126 msgid "" "Mercurial is telling us that the <command role=\"hg-cmd\">hg update</command> " "command won't do a merge; it won't update the working directory when it " "thinks we might want to do a merge, unless we force it to do so. " "(Incidentally, forcing the update with <command>hg update -C</command> would " "revert any uncommitted changes in the working directory.)" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch03-tour-merge.xml:134 msgid "" "To start a merge between the two heads, we use the <command role=\"hg-cmd" "\">hg merge</command> command." msgstr "" "我们使用 <command role=\"hg-cmd\">hg merge</command> 命令来合并两个顶点。" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch03-tour-merge.xml:139 msgid "" "We resolve the contents of <filename>hello.c</filename> This updates the " "working directory so that it contains changes from <emphasis>both</emphasis> " "heads, which is reflected in both the output of <command role=\"hg-cmd\">hg " "parents</command> and the contents of <filename>hello.c</filename>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch03-tour-merge.xml:151 msgid "Committing the results of the merge" msgstr "提交合并结果" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch03-tour-merge.xml:153 msgid "" "Whenever we've done a merge, <command role=\"hg-cmd\">hg parents</command> " "will display two parents until we <command role=\"hg-cmd\">hg commit</" "command> the results of the merge." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch03-tour-merge.xml:160 msgid "" "We now have a new tip revision; notice that it has <emphasis>both</emphasis> " "of our former heads as its parents. These are the same revisions that were " "previously displayed by <command role=\"hg-cmd\">hg parents</command>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch03-tour-merge.xml:167 msgid "" "In <xref linkend=\"fig:tour-merge:merge\"/>, you can see a representation of " "what happens to the working directory during the merge, and how this affects " "the repository when the commit happens. During the merge, the working " "directory has two parent changesets, and these become the parents of the new " "changeset." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><figure><title> #: ../en/ch03-tour-merge.xml:176 msgid "Working directory and repository during merge, and following commit" msgstr "在合并期间,以及提交之后的工作目录与版本库" #. type: Content of: <book><chapter><sect1><sect2><figure><mediaobject> #: ../en/ch03-tour-merge.xml:179 msgid "" "<imageobject> <imagedata fileref=\"figs/tour-merge-merge.png\"/> </" "imageobject>" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch03-tour-merge.xml:186 msgid "" "We sometimes talk about a merge having <emphasis>sides</emphasis>: the left " "side is the first parent in the output of <command role=\"hg-cmd\">hg " "parents</command>, and the right side is the second. If the working " "directory was at e.g. revision 5 before we began a merge, that revision will " "become the left side of the merge." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch03-tour-merge.xml:196 msgid "Merging conflicting changes" msgstr "合并有冲突的改变" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch03-tour-merge.xml:198 msgid "" "Most merges are simple affairs, but sometimes you'll find yourself merging " "changes where each side modifies the same portions of the same files. Unless " "both modifications are identical, this results in a <emphasis>conflict</" "emphasis>, where you have to decide how to reconcile the different changes " "into something coherent." msgstr "" #. type: Content of: <book><chapter><sect1><figure><title> #: ../en/ch03-tour-merge.xml:206 msgid "Conflicting changes to a document" msgstr "冲突的修改" #. type: Content of: <book><chapter><sect1><figure><mediaobject> #: ../en/ch03-tour-merge.xml:208 msgid "" "<imageobject><imagedata fileref=\"figs/tour-merge-conflict.png\"/></" "imageobject>" msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch03-tour-merge.xml:213 msgid "" "<xref linkend=\"fig:tour-merge:conflict\"/> illustrates an instance of two " "conflicting changes to a document. We started with a single version of the " "file; then we made some changes; while someone else made different changes to " "the same text. Our task in resolving the conflicting changes is to decide " "what the file should look like." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch03-tour-merge.xml:220 msgid "" "Mercurial doesn't have a built-in facility for handling conflicts. Instead, " "it runs an external program, usually one that displays some kind of graphical " "conflict resolution interface. By default, Mercurial tries to find one of " "several different merging tools that are likely to be installed on your " "system. It first tries a few fully automatic merging tools; if these don't " "succeed (because the resolution process requires human guidance) or aren't " "present, it tries a few different graphical merging tools." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch03-tour-merge.xml:230 msgid "" "It's also possible to get Mercurial to run a specific program or script, by " "setting the <envar>HGMERGE</envar> environment variable to the name of your " "preferred program." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch03-tour-merge.xml:236 msgid "Using a graphical merge tool" msgstr "使用图形合并工具" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch03-tour-merge.xml:238 msgid "" "My preferred graphical merge tool is <command>kdiff3</command>, which I'll " "use to describe the features that are common to graphical file merging " "tools. You can see a screenshot of <command>kdiff3</command> in action in " "<xref linkend=\"fig:tour-merge:kdiff3\"/>. The kind of merge it is " "performing is called a <emphasis>three-way merge</emphasis>, because there " "are three different versions of the file of interest to us. The tool thus " "splits the upper portion of the window into three panes:" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch03-tour-merge.xml:248 msgid "" "At the left is the <emphasis>base</emphasis> version of the file, i.e. the " "most recent version from which the two versions we're trying to merge are " "descended." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch03-tour-merge.xml:253 msgid "" "In the middle is <quote>our</quote> version of the file, with the contents " "that we modified." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch03-tour-merge.xml:256 msgid "" "On the right is <quote>their</quote> version of the file, the one that from " "the changeset that we're trying to merge with." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch03-tour-merge.xml:260 msgid "" "In the pane below these is the current <emphasis>result</emphasis> of the " "merge. Our task is to replace all of the red text, which indicates unresolved " "conflicts, with some sensible merger of the <quote>ours</quote> and " "<quote>theirs</quote> versions of the file." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch03-tour-merge.xml:267 msgid "" "All four of these panes are <emphasis>locked together</emphasis>; if we " "scroll vertically or horizontally in any of them, the others are updated to " "display the corresponding sections of their respective files." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><figure><title> #: ../en/ch03-tour-merge.xml:273 msgid "Using <command>kdiff3</command> to merge versions of a file" msgstr "使用 <command>kdiff3</command> 合并文件的不同版本" #. type: Content of: <book><chapter><sect1><sect2><figure><mediaobject> #: ../en/ch03-tour-merge.xml:276 msgid "" "<imageobject> <imagedata width=\"100%\" fileref=\"figs/kdiff3.png\"/></" "imageobject>" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch03-tour-merge.xml:284 msgid "" "For each conflicting portion of the file, we can choose to resolve the " "conflict using some combination of text from the base version, ours, or " "theirs. We can also manually edit the merged file at any time, in case we " "need to make further modifications." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch03-tour-merge.xml:290 msgid "" "There are <emphasis>many</emphasis> file merging tools available, too many to " "cover here. They vary in which platforms they are available for, and in " "their particular strengths and weaknesses. Most are tuned for merging files " "containing plain text, while a few are aimed at specialised file formats " "(generally XML)." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch03-tour-merge.xml:299 msgid "A worked example" msgstr "合并实例" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch03-tour-merge.xml:301 msgid "" "In this example, we will reproduce the file modification history of <xref " "linkend=\"fig:tour-merge:conflict\"/> above. Let's begin by creating a " "repository with a base version of our document." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch03-tour-merge.xml:308 msgid "We'll clone the repository and make a change to the file." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch03-tour-merge.xml:313 msgid "" "And another clone, to simulate someone else making a change to the file. " "(This hints at the idea that it's not all that unusual to merge with yourself " "when you isolate tasks in separate repositories, and indeed to find and " "resolve conflicts while doing so.)" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch03-tour-merge.xml:321 msgid "" "Having created two different versions of the file, we'll set up an " "environment suitable for running our merge." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch03-tour-merge.xml:327 msgid "" "In this example, I'll set <envar>HGMERGE</envar> to tell Mercurial to use the " "non-interactive <command>merge</command> command. This is bundled with many " "Unix-like systems. (If you're following this example on your computer, don't " "bother setting <envar>HGMERGE</envar>. You'll get dropped into a GUI file " "merge tool instead, which is much preferable.)" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch03-tour-merge.xml:337 msgid "" "Because <command>merge</command> can't resolve the conflicting changes, it " "leaves <emphasis>merge markers</emphasis> inside the file that has conflicts, " "indicating which lines have conflicts, and whether they came from our version " "of the file or theirs." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch03-tour-merge.xml:343 msgid "" "Mercurial can tell from the way <command>merge</command> exits that it wasn't " "able to merge successfully, so it tells us what commands we'll need to run if " "we want to redo the merging operation. This could be useful if, for example, " "we were running a graphical merge tool and quit because we were confused or " "realised we had made a mistake." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch03-tour-merge.xml:350 msgid "" "If automatic or manual merges fail, there's nothing to prevent us from " "<quote>fixing up</quote> the affected files ourselves, and committing the " "results of our merge:" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><note><title> #: ../en/ch03-tour-merge.xml:357 msgid "Where is the <command>hg resolve</command> command?" msgstr "在哪里能找到 <command role=\"hg-cmd\">hg resolve</command> 命令?" #. type: Content of: <book><chapter><sect1><sect2><note><para> #: ../en/ch03-tour-merge.xml:359 msgid "" "The <command>hg resolve</command> command was introduced in Mercurial 1.1, " "which was released in December 2008. If you are using an older version of " "Mercurial (run <command>hg version</command> to see), this command will not " "be present. If your version of Mercurial is older than 1.1, you should " "strongly consider upgrading to a newer version before trying to tackle " "complicated merges." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch03-tour-merge.xml:371 msgid "Simplifying the pull-merge-commit sequence" msgstr "简化拉-合并-提交程序" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch03-tour-merge.xml:373 msgid "" "The process of merging changes as outlined above is straightforward, but " "requires running three commands in sequence." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch03-tour-merge.xml:379 msgid "" "In the case of the final commit, you also need to enter a commit message, " "which is almost always going to be a piece of uninteresting " "<quote>boilerplate</quote> text." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch03-tour-merge.xml:383 msgid "" "It would be nice to reduce the number of steps needed, if this were " "possible. Indeed, Mercurial is distributed with an extension called <literal " "role=\"hg-ext\">fetch</literal> that does just this." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch03-tour-merge.xml:388 msgid "" "Mercurial provides a flexible extension mechanism that lets people extend its " "functionality, while keeping the core of Mercurial small and easy to deal " "with. Some extensions add new commands that you can use from the command " "line, while others work <quote>behind the scenes,</quote> for example adding " "capabilities to Mercurial's built-in server mode." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch03-tour-merge.xml:395 msgid "" "The <literal role=\"hg-ext\">fetch</literal> extension adds a new command " "called, not surprisingly, <command role=\"hg-cmd\">hg fetch</command>. This " "extension acts as a combination of <command role=\"hg-cmd\">hg pull -u</" "command>, <command role=\"hg-cmd\">hg merge</command> and <command role=\"hg-" "cmd\">hg commit</command>. It begins by pulling changes from another " "repository into the current repository. If it finds that the changes added a " "new head to the repository, it updates to the new head, begins a merge, then " "(if the merge succeeded) commits the result of the merge with an " "automatically-generated commit message. If no new heads were added, it " "updates the working directory to the new tip changeset." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch03-tour-merge.xml:409 msgid "" "Enabling the <literal role=\"hg-ext\">fetch</literal> extension is easy. " "Edit the <filename role=\"special\">.hgrc</filename> file in your home " "directory, and either go to the <literal role=\"rc-extensions\">extensions</" "literal> section or create an <literal role=\"rc-extensions\">extensions</" "literal> section. Then add a line that simply reads <quote><literal>fetch=</" "literal></quote>." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch03-tour-merge.xml:421 msgid "" "(Normally, the right-hand side of the <quote><literal>=</literal></quote> " "would indicate where to find the extension, but since the <literal role=\"hg-" "ext\">fetch</literal> extension is in the standard distribution, Mercurial " "knows where to search for it.)" msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch03-tour-merge.xml:429 msgid "Renaming, copying, and merging" msgstr "改名,复制与合并" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch03-tour-merge.xml:431 msgid "" "During the life of a project, we will often want to change the layout of its " "files and directories. This can be as simple as renaming a single file, or as " "complex as restructuring the entire hierarchy of files within the project." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch03-tour-merge.xml:436 msgid "" "Mercurial supports these kinds of complex changes fluently, provided we tell " "it what we're doing. If we want to rename a file, we should use the " "<command>hg rename</command><placeholder type=\"footnote\" id=\"0\"/> command " "to rename it, so that Mercurial can do the right thing later when we merge." msgstr "" #. type: Content of: <book><chapter><sect1><para><footnote><para> #: ../en/ch03-tour-merge.xml:439 msgid "" "If you're a Unix user, you'll be glad to know that the <command>hg rename</" "command> command can be abbreviated as <command>hg mv</command>." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch03-tour-merge.xml:445 msgid "" "We will cover the use of these commands in more detail in <xref linkend=" "\"chap:daily.copy\"/>." msgstr "" #. type: Content of: <book><chapter><title> #: ../en/ch04-concepts.xml:5 msgid "Behind the scenes" msgstr "Mercurial 内幕" #. type: Content of: <book><chapter><para> #: ../en/ch04-concepts.xml:7 msgid "" "Unlike many revision control systems, the concepts upon which Mercurial is " "built are simple enough that it's easy to understand how the software really " "works. Knowing these details certainly isn't necessary, so it is certainly " "safe to skip this chapter. However, I think you will get more out of the " "software with a <quote>mental model</quote> of what's going on." msgstr "" #. type: Content of: <book><chapter><para> #: ../en/ch04-concepts.xml:14 msgid "" "Being able to understand what's going on behind the scenes gives me " "confidence that Mercurial has been carefully designed to be both " "<emphasis>safe</emphasis> and <emphasis>efficient</emphasis>. And just as " "importantly, if it's easy for me to retain a good idea of what the software " "is doing when I perform a revision control task, I'm less likely to be " "surprised by its behavior." msgstr "" #. type: Content of: <book><chapter><para> #: ../en/ch04-concepts.xml:22 msgid "" "In this chapter, we'll initially cover the core concepts behind Mercurial's " "design, then continue to discuss some of the interesting details of its " "implementation." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch04-concepts.xml:27 msgid "Mercurial's historical record" msgstr "Mercurial 的历史记录" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch04-concepts.xml:30 msgid "Tracking the history of a single file" msgstr "跟踪单一文件的历史" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:32 msgid "" "When Mercurial tracks modifications to a file, it stores the history of that " "file in a metadata object called a <emphasis>filelog</emphasis>. Each entry " "in the filelog contains enough information to reconstruct one revision of the " "file that is being tracked. Filelogs are stored as files in the <filename " "role=\"special\" class=\"directory\">.hg/store/data</filename> directory. A " "filelog contains two kinds of information: revision data, and an index to " "help Mercurial to find a revision efficiently." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:43 msgid "" "A file that is large, or has a lot of history, has its filelog stored in " "separate data (<quote><literal>.d</literal></quote> suffix) and index " "(<quote><literal>.i</literal></quote> suffix) files. For small files without " "much history, the revision data and index are combined in a single " "<quote><literal>.i</literal></quote> file. The correspondence between a file " "in the working directory and the filelog that tracks its history in the " "repository is illustrated in <xref linkend=\"fig:concepts:filelog\"/>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><figure><title> #: ../en/ch04-concepts.xml:55 msgid "" "Relationships between files in working directory and filelogs in repository" msgstr "工作目录中的文件与版本库中的文件日志之间的关系" #. type: Content of: <book><chapter><sect1><sect2><figure><mediaobject> #: ../en/ch04-concepts.xml:58 msgid "<imageobject><imagedata fileref=\"figs/filelog.png\"/></imageobject>" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch04-concepts.xml:65 msgid "Managing tracked files" msgstr "管理跟踪的文件" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:67 msgid "" "Mercurial uses a structure called a <emphasis>manifest</emphasis> to collect " "together information about the files that it tracks. Each entry in the " "manifest contains information about the files present in a single changeset. " "An entry records which files are present in the changeset, the revision of " "each file, and a few other pieces of file metadata." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch04-concepts.xml:77 msgid "Recording changeset information" msgstr "记录修改集信息" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:79 msgid "" "The <emphasis>changelog</emphasis> contains information about each " "changeset. Each revision records who committed a change, the changeset " "comment, other pieces of changeset-related information, and the revision of " "the manifest to use." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch04-concepts.xml:87 msgid "Relationships between revisions" msgstr "版本之间的关系" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:89 msgid "" "Within a changelog, a manifest, or a filelog, each revision stores a pointer " "to its immediate parent (or to its two parents, if it's a merge revision). " "As I mentioned above, there are also relationships between revisions " "<emphasis>across</emphasis> these structures, and they are hierarchical in " "nature." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:96 msgid "" "For every changeset in a repository, there is exactly one revision stored in " "the changelog. Each revision of the changelog contains a pointer to a single " "revision of the manifest. A revision of the manifest stores a pointer to a " "single revision of each filelog tracked when that changeset was created. " "These relationships are illustrated in <xref linkend=\"fig:concepts:metadata" "\"/>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><figure><title> #: ../en/ch04-concepts.xml:105 msgid "Metadata relationships" msgstr "元数据之间的关系" #. type: Content of: <book><chapter><sect1><sect2><figure><mediaobject> #: ../en/ch04-concepts.xml:107 msgid "<imageobject><imagedata fileref=\"figs/metadata.png\"/></imageobject>" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:112 msgid "" "As the illustration shows, there is <emphasis>not</emphasis> a <quote>one to " "one</quote> relationship between revisions in the changelog, manifest, or " "filelog. If a file that Mercurial tracks hasn't changed between two " "changesets, the entry for that file in the two revisions of the manifest will " "point to the same revision of its filelog<placeholder type=\"footnote\" id=\"0" "\"/>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para><footnote><para> #: ../en/ch04-concepts.xml:119 msgid "" "It is possible (though unusual) for the manifest to remain the same between " "two changesets, in which case the changelog entries for those changesets will " "point to the same revision of the manifest." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch04-concepts.xml:128 msgid "Safe, efficient storage" msgstr "安全,高效的存储" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch04-concepts.xml:130 msgid "" "The underpinnings of changelogs, manifests, and filelogs are provided by a " "single structure called the <emphasis>revlog</emphasis>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch04-concepts.xml:135 msgid "Efficient storage" msgstr "高效存储" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:137 msgid "" "The revlog provides efficient storage of revisions using a <emphasis>delta</" "emphasis> mechanism. Instead of storing a complete copy of a file for each " "revision, it stores the changes needed to transform an older revision into " "the new revision. For many kinds of file data, these deltas are typically a " "fraction of a percent of the size of a full copy of a file." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:145 msgid "" "Some obsolete revision control systems can only work with deltas of text " "files. They must either store binary files as complete snapshots or encoded " "into a text representation, both of which are wasteful approaches. Mercurial " "can efficiently handle deltas of files with arbitrary binary contents; it " "doesn't need to treat text as special." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch04-concepts.xml:154 msgid "Safe operation" msgstr "安全操作" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:156 msgid "" "Mercurial only ever <emphasis>appends</emphasis> data to the end of a revlog " "file. It never modifies a section of a file after it has written it. This is " "both more robust and efficient than schemes that need to modify or rewrite " "data." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:162 msgid "" "In addition, Mercurial treats every write as part of a <emphasis>transaction</" "emphasis> that can span a number of files. A transaction is " "<emphasis>atomic</emphasis>: either the entire transaction succeeds and its " "effects are all visible to readers in one go, or the whole thing is undone. " "This guarantee of atomicity means that if you're running two copies of " "Mercurial, where one is reading data and one is writing it, the reader will " "never see a partially written result that might confuse it." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:172 msgid "" "The fact that Mercurial only appends to files makes it easier to provide this " "transactional guarantee. The easier it is to do stuff like this, the more " "confident you should be that it's done correctly." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch04-concepts.xml:179 msgid "Fast retrieval" msgstr "快速检索" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:181 msgid "" "Mercurial cleverly avoids a pitfall common to all earlier revision control " "systems: the problem of <emphasis>inefficient retrieval</emphasis>. Most " "revision control systems store the contents of a revision as an incremental " "series of modifications against a <quote>snapshot</quote>. (Some base the " "snapshot on the oldest revision, others on the newest.) To reconstruct a " "specific revision, you must first read the snapshot, and then every one of " "the revisions between the snapshot and your target revision. The more " "history that a file accumulates, the more revisions you must read, hence the " "longer it takes to reconstruct a particular revision." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><figure><title> #: ../en/ch04-concepts.xml:195 msgid "Snapshot of a revlog, with incremental deltas" msgstr "版本日志的快照,以及增量差异" #. type: Content of: <book><chapter><sect1><sect2><figure><mediaobject> #: ../en/ch04-concepts.xml:197 msgid "<imageobject><imagedata fileref=\"figs/snapshot.png\"/></imageobject>" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:202 msgid "" "The innovation that Mercurial applies to this problem is simple but " "effective. Once the cumulative amount of delta information stored since the " "last snapshot exceeds a fixed threshold, it stores a new snapshot " "(compressed, of course), instead of another delta. This makes it possible to " "reconstruct <emphasis>any</emphasis> revision of a file quickly. This " "approach works so well that it has since been copied by several other " "revision control systems." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:211 msgid "" "<xref linkend=\"fig:concepts:snapshot\"/> illustrates the idea. In an entry " "in a revlog's index file, Mercurial stores the range of entries from the data " "file that it must read to reconstruct a particular revision." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><title> #: ../en/ch04-concepts.xml:217 msgid "Aside: the influence of video compression" msgstr "旁白: 视频压缩的影响" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch04-concepts.xml:219 msgid "" "If you're familiar with video compression or have ever watched a TV feed " "through a digital cable or satellite service, you may know that most video " "compression schemes store each frame of video as a delta against its " "predecessor frame." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch04-concepts.xml:225 msgid "" "Mercurial borrows this idea to make it possible to reconstruct a revision " "from a snapshot and a small number of deltas." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch04-concepts.xml:232 msgid "Identification and strong integrity" msgstr "鉴别和强完整性" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:234 msgid "" "Along with delta or snapshot information, a revlog entry contains a " "cryptographic hash of the data that it represents. This makes it difficult " "to forge the contents of a revision, and easy to detect accidental corruption." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:239 msgid "" "Hashes provide more than a mere check against corruption; they are used as " "the identifiers for revisions. The changeset identification hashes that you " "see as an end user are from revisions of the changelog. Although filelogs " "and the manifest also use hashes, Mercurial only uses these behind the scenes." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:246 msgid "" "Mercurial verifies that hashes are correct when it retrieves file revisions " "and when it pulls changes from another repository. If it encounters an " "integrity problem, it will complain and stop whatever it's doing." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:251 msgid "" "In addition to the effect it has on retrieval efficiency, Mercurial's use of " "periodic snapshots makes it more robust against partial data corruption. If " "a revlog becomes partly corrupted due to a hardware error or system bug, it's " "often possible to reconstruct some or most revisions from the uncorrupted " "sections of the revlog, both before and after the corrupted section. This " "would not be possible with a delta-only storage model." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch04-concepts.xml:263 msgid "Revision history, branching, and merging" msgstr "修订历史,分支与合并" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch04-concepts.xml:265 msgid "" "Every entry in a Mercurial revlog knows the identity of its immediate " "ancestor revision, usually referred to as its <emphasis>parent</emphasis>. " "In fact, a revision contains room for not one parent, but two. Mercurial " "uses a special hash, called the <quote>null ID</quote>, to represent the idea " "<quote>there is no parent here</quote>. This hash is simply a string of " "zeroes." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch04-concepts.xml:273 msgid "" "In <xref linkend=\"fig:concepts:revlog\"/>, you can see an example of the " "conceptual structure of a revlog. Filelogs, manifests, and changelogs all " "have this same structure; they differ only in the kind of data stored in each " "delta or snapshot." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch04-concepts.xml:279 msgid "" "The first revision in a revlog (at the bottom of the image) has the null ID " "in both of its parent slots. For a <quote>normal</quote> revision, its first " "parent slot contains the ID of its parent revision, and its second contains " "the null ID, indicating that the revision has only one real parent. Any two " "revisions that have the same parent ID are branches. A revision that " "represents a merge between branches has two normal revision IDs in its parent " "slots." msgstr "" #. type: Content of: <book><chapter><sect1><figure><title> #: ../en/ch04-concepts.xml:289 msgid "The conceptual structure of a revlog" msgstr "版本日志的设计结构" #. type: Content of: <book><chapter><sect1><figure><mediaobject> #: ../en/ch04-concepts.xml:291 msgid "<imageobject><imagedata fileref=\"figs/revlog.png\"/></imageobject>" msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch04-concepts.xml:298 msgid "The working directory" msgstr "工作目录" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch04-concepts.xml:300 msgid "" "In the working directory, Mercurial stores a snapshot of the files from the " "repository as of a particular changeset." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch04-concepts.xml:303 msgid "" "The working directory <quote>knows</quote> which changeset it contains. When " "you update the working directory to contain a particular changeset, Mercurial " "looks up the appropriate revision of the manifest to find out which files it " "was tracking at the time that changeset was committed, and which revision of " "each file was then current. It then recreates a copy of each of those files, " "with the same contents it had when the changeset was committed." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch04-concepts.xml:312 msgid "" "The <emphasis>dirstate</emphasis> is a special structure that contains " "Mercurial's knowledge of the working directory. It is maintained as a file " "named <filename>.hg/dirstate</filename> inside a repository. The dirstate " "details which changeset the working directory is updated to, and all of the " "files that Mercurial is tracking in the working directory. It also lets " "Mercurial quickly notice changed files, by recording their checkout times and " "sizes." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch04-concepts.xml:322 msgid "" "Just as a revision of a revlog has room for two parents, so that it can " "represent either a normal revision (with one parent) or a merge of two " "earlier revisions, the dirstate has slots for two parents. When you use the " "<command role=\"hg-cmd\">hg update</command> command, the changeset that you " "update to is stored in the <quote>first parent</quote> slot, and the null ID " "in the second. When you <command role=\"hg-cmd\">hg merge</command> with " "another changeset, the first parent remains unchanged, and the second parent " "is filled in with the changeset you're merging with. The <command role=\"hg-" "cmd\">hg parents</command> command tells you what the parents of the dirstate " "are." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch04-concepts.xml:336 msgid "What happens when you commit" msgstr "当你提交时发生的事情" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:338 msgid "" "The dirstate stores parent information for more than just book-keeping " "purposes. Mercurial uses the parents of the dirstate as <emphasis>the " "parents of a new changeset</emphasis> when you perform a commit." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><figure><title> #: ../en/ch04-concepts.xml:344 msgid "The working directory can have two parents" msgstr "工作目录可以有两个父亲" #. type: Content of: <book><chapter><sect1><sect2><figure><mediaobject> #: ../en/ch04-concepts.xml:346 msgid "<imageobject><imagedata fileref=\"figs/wdir.png\"/></imageobject>" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:351 msgid "" "<xref linkend=\"fig:concepts:wdir\"/> shows the normal state of the working " "directory, where it has a single changeset as parent. That changeset is the " "<emphasis>tip</emphasis>, the newest changeset in the repository that has no " "children." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><figure><title> #: ../en/ch04-concepts.xml:358 msgid "The working directory gains new parents after a commit" msgstr "提交之后,工作目录的父亲就改变了" #. type: Content of: <book><chapter><sect1><sect2><figure><mediaobject> #: ../en/ch04-concepts.xml:361 msgid "" "<imageobject><imagedata fileref=\"figs/wdir-after-commit.png\"/></imageobject>" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:366 msgid "" "It's useful to think of the working directory as <quote>the changeset I'm " "about to commit</quote>. Any files that you tell Mercurial that you've " "added, removed, renamed, or copied will be reflected in that changeset, as " "will modifications to any files that Mercurial is already tracking; the new " "changeset will have the parents of the working directory as its parents." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:374 msgid "" "After a commit, Mercurial will update the parents of the working directory, " "so that the first parent is the ID of the new changeset, and the second is " "the null ID. This is shown in <xref linkend=\"fig:concepts:wdir-after-commit" "\"/>. Mercurial doesn't touch any of the files in the working directory when " "you commit; it just modifies the dirstate to note its new parents." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch04-concepts.xml:385 msgid "Creating a new head" msgstr "创建新顶点" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:387 msgid "" "It's perfectly normal to update the working directory to a changeset other " "than the current tip. For example, you might want to know what your project " "looked like last Tuesday, or you could be looking through changesets to see " "which one introduced a bug. In cases like this, the natural thing to do is " "update the working directory to the changeset you're interested in, and then " "examine the files in the working directory directly to see their contents as " "they were when you committed that changeset. The effect of this is shown in " "<xref linkend=\"fig:concepts:wdir-pre-branch\"/>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><figure><title> #: ../en/ch04-concepts.xml:399 msgid "The working directory, updated to an older changeset" msgstr "同步到旧修改集的工作目录" #. type: Content of: <book><chapter><sect1><sect2><figure><mediaobject> #: ../en/ch04-concepts.xml:402 msgid "" "<imageobject><imagedata fileref=\"figs/wdir-pre-branch.png\"/></imageobject>" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:407 msgid "" "Having updated the working directory to an older changeset, what happens if " "you make some changes, and then commit? Mercurial behaves in the same way as " "I outlined above. The parents of the working directory become the parents of " "the new changeset. This new changeset has no children, so it becomes the new " "tip. And the repository now contains two changesets that have no children; " "we call these <emphasis>heads</emphasis>. You can see the structure that " "this creates in <xref linkend=\"fig:concepts:wdir-branch\"/>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><figure><title> #: ../en/ch04-concepts.xml:419 msgid "After a commit made while synced to an older changeset" msgstr "对同步到旧修改集的工作目录提交之后" #. type: Content of: <book><chapter><sect1><sect2><figure><mediaobject> #: ../en/ch04-concepts.xml:422 msgid "<imageobject><imagedata fileref=\"figs/wdir-branch.png\"/></imageobject>" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><note><para> #: ../en/ch04-concepts.xml:428 msgid "" "If you're new to Mercurial, you should keep in mind a common <quote>error</" "quote>, which is to use the <command role=\"hg-cmd\">hg pull</command> " "command without any options. By default, the <command role=\"hg-cmd\">hg " "pull</command> command <emphasis>does not</emphasis> update the working " "directory, so you'll bring new changesets into your repository, but the " "working directory will stay synced at the same changeset as before the pull. " "If you make some changes and commit afterwards, you'll thus create a new " "head, because your working directory isn't synced to whatever the current tip " "is. To combine the operation of a pull, followed by an update, run " "<command>hg pull -u</command>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><note><para> #: ../en/ch04-concepts.xml:442 msgid "" "I put the word <quote>error</quote> in quotes because all that you need to do " "to rectify the situation where you created a new head by accident is <command " "role=\"hg-cmd\">hg merge</command>, then <command role=\"hg-cmd\">hg commit</" "command>. In other words, this almost never has negative consequences; it's " "just something of a surprise for newcomers. I'll discuss other ways to avoid " "this behavior, and why Mercurial behaves in this initially surprising way, " "later on." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch04-concepts.xml:455 msgid "Merging changes" msgstr "合并修改" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:457 msgid "" "When you run the <command role=\"hg-cmd\">hg merge</command> command, " "Mercurial leaves the first parent of the working directory unchanged, and " "sets the second parent to the changeset you're merging with, as shown in " "<xref linkend=\"fig:concepts:wdir-merge\"/>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><figure><title> #: ../en/ch04-concepts.xml:464 msgid "Merging two heads" msgstr "合并两个顶点" #. type: Content of: <book><chapter><sect1><sect2><figure><mediaobject> #: ../en/ch04-concepts.xml:466 msgid "" "<imageobject> <imagedata fileref=\"figs/wdir-merge.png\"/> </imageobject>" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:473 msgid "" "Mercurial also has to modify the working directory, to merge the files " "managed in the two changesets. Simplified a little, the merging process goes " "like this, for every file in the manifests of both changesets." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch04-concepts.xml:478 msgid "If neither changeset has modified a file, do nothing with that file." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch04-concepts.xml:481 msgid "" "If one changeset has modified a file, and the other hasn't, create the " "modified copy of the file in the working directory." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch04-concepts.xml:485 msgid "" "If one changeset has removed a file, and the other hasn't (or has also " "deleted it), delete the file from the working directory." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch04-concepts.xml:489 msgid "" "If one changeset has removed a file, but the other has modified the file, ask " "the user what to do: keep the modified file, or remove it?" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch04-concepts.xml:493 msgid "" "If both changesets have modified a file, invoke an external merge program to " "choose the new contents for the merged file. This may require input from the " "user." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch04-concepts.xml:498 msgid "" "If one changeset has modified a file, and the other has renamed or copied the " "file, make sure that the changes follow the new name of the file." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:502 msgid "" "There are more details&emdash;merging has plenty of corner cases&emdash;but " "these are the most common choices that are involved in a merge. As you can " "see, most cases are completely automatic, and indeed most merges finish " "automatically, without requiring your input to resolve any conflicts." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:509 msgid "" "When you're thinking about what happens when you commit after a merge, once " "again the working directory is <quote>the changeset I'm about to commit</" "quote>. After the <command role=\"hg-cmd\">hg merge</command> command " "completes, the working directory has two parents; these will become the " "parents of the new changeset." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:516 msgid "" "Mercurial lets you perform multiple merges, but you must commit the results " "of each individual merge as you go. This is necessary because Mercurial only " "tracks two parents for both revisions and the working directory. While it " "would be technically feasible to merge multiple changesets at once, Mercurial " "avoids this for simplicity. With multi-way merges, the risks of user " "confusion, nasty conflict resolution, and making a terrible mess of a merge " "would grow intolerable." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch04-concepts.xml:529 msgid "Merging and renames" msgstr "合并与改名" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:531 msgid "" "A surprising number of revision control systems pay little or no attention to " "a file's <emphasis>name</emphasis> over time. For instance, it used to be " "common that if a file got renamed on one side of a merge, the changes from " "the other side would be silently dropped." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:537 msgid "" "Mercurial records metadata when you tell it to perform a rename or copy. It " "uses this metadata during a merge to do the right thing in the case of a " "merge. For instance, if I rename a file, and you edit it without renaming " "it, when we merge our work the file will be renamed and have your edits " "applied." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch04-concepts.xml:547 msgid "Other interesting design features" msgstr "其它有趣的设计特性" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch04-concepts.xml:549 msgid "" "In the sections above, I've tried to highlight some of the most important " "aspects of Mercurial's design, to illustrate that it pays careful attention " "to reliability and performance. However, the attention to detail doesn't " "stop there. There are a number of other aspects of Mercurial's construction " "that I personally find interesting. I'll detail a few of them here, separate " "from the <quote>big ticket</quote> items above, so that if you're interested, " "you can gain a better idea of the amount of thinking that goes into a well-" "designed system." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch04-concepts.xml:560 msgid "Clever compression" msgstr "智能压缩" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:562 msgid "" "When appropriate, Mercurial will store both snapshots and deltas in " "compressed form. It does this by always <emphasis>trying to</emphasis> " "compress a snapshot or delta, but only storing the compressed version if it's " "smaller than the uncompressed version." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:568 msgid "" "This means that Mercurial does <quote>the right thing</quote> when storing a " "file whose native form is compressed, such as a <literal>zip</literal> " "archive or a JPEG image. When these types of files are compressed a second " "time, the resulting file is usually bigger than the once-compressed form, and " "so Mercurial will store the plain <literal>zip</literal> or JPEG." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:576 msgid "" "Deltas between revisions of a compressed file are usually larger than " "snapshots of the file, and Mercurial again does <quote>the right thing</" "quote> in these cases. It finds that such a delta exceeds the threshold at " "which it should store a complete snapshot of the file, so it stores the " "snapshot, again saving space compared to a naive delta-only approach." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><title> #: ../en/ch04-concepts.xml:585 msgid "Network recompression" msgstr "网络重新压缩" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch04-concepts.xml:587 msgid "" "When storing revisions on disk, Mercurial uses the <quote>deflate</quote> " "compression algorithm (the same one used by the popular <literal>zip</" "literal> archive format), which balances good speed with a respectable " "compression ratio. However, when transmitting revision data over a network " "connection, Mercurial uncompresses the compressed revision data." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch04-concepts.xml:595 msgid "" "If the connection is over HTTP, Mercurial recompresses the entire stream of " "data using a compression algorithm that gives a better compression ratio (the " "Burrows-Wheeler algorithm from the widely used <literal>bzip2</literal> " "compression package). This combination of algorithm and compression of the " "entire stream (instead of a revision at a time) substantially reduces the " "number of bytes to be transferred, yielding better network performance over " "most kinds of network." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch04-concepts.xml:605 msgid "" "If the connection is over <command>ssh</command>, Mercurial " "<emphasis>doesn't</emphasis> recompress the stream, because <command>ssh</" "command> can already do this itself. You can tell Mercurial to always use " "<command>ssh</command>'s compression feature by editing the <filename>.hgrc</" "filename> file in your home directory as follows." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch04-concepts.xml:620 msgid "Read/write ordering and atomicity" msgstr "读写顺序与原子性" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:622 msgid "" "Appending to files isn't the whole story when it comes to guaranteeing that a " "reader won't see a partial write. If you recall <xref linkend=\"fig:concepts:" "metadata\"/>, revisions in the changelog point to revisions in the manifest, " "and revisions in the manifest point to revisions in filelogs. This hierarchy " "is deliberate." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:629 msgid "" "A writer starts a transaction by writing filelog and manifest data, and " "doesn't write any changelog data until those are finished. A reader starts " "by reading changelog data, then manifest data, followed by filelog data." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:634 msgid "" "Since the writer has always finished writing filelog and manifest data before " "it writes to the changelog, a reader will never read a pointer to a partially " "written manifest revision from the changelog, and it will never read a " "pointer to a partially written filelog revision from the manifest." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch04-concepts.xml:642 msgid "Concurrent access" msgstr "并发访问" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:644 msgid "" "The read/write ordering and atomicity guarantees mean that Mercurial never " "needs to <emphasis>lock</emphasis> a repository when it's reading data, even " "if the repository is being written to while the read is occurring. This has a " "big effect on scalability; you can have an arbitrary number of Mercurial " "processes safely reading data from a repository all at once, no matter " "whether it's being written to or not." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:653 msgid "" "The lockless nature of reading means that if you're sharing a repository on a " "multi-user system, you don't need to grant other local users permission to " "<emphasis>write</emphasis> to your repository in order for them to be able to " "clone it or pull changes from it; they only need <emphasis>read</emphasis> " "permission. (This is <emphasis>not</emphasis> a common feature among " "revision control systems, so don't take it for granted! Most require readers " "to be able to lock a repository to access it safely, and this requires write " "permission on at least one directory, which of course makes for all kinds of " "nasty and annoying security and administrative problems.)" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:666 msgid "" "Mercurial uses locks to ensure that only one process can write to a " "repository at a time (the locking mechanism is safe even over filesystems " "that are notoriously hostile to locking, such as NFS). If a repository is " "locked, a writer will wait for a while to retry if the repository becomes " "unlocked, but if the repository remains locked for too long, the process " "attempting to write will time out after a while. This means that your daily " "automated scripts won't get stuck forever and pile up if a system crashes " "unnoticed, for example. (Yes, the timeout is configurable, from zero to " "infinity.)" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><title> #: ../en/ch04-concepts.xml:678 msgid "Safe dirstate access" msgstr "安全的目录状态访问" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch04-concepts.xml:680 msgid "" "As with revision data, Mercurial doesn't take a lock to read the dirstate " "file; it does acquire a lock to write it. To avoid the possibility of " "reading a partially written copy of the dirstate file, Mercurial writes to a " "file with a unique name in the same directory as the dirstate file, then " "renames the temporary file atomically to <filename>dirstate</filename>. The " "file named <filename>dirstate</filename> is thus guaranteed to be complete, " "not partially written." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch04-concepts.xml:693 msgid "Avoiding seeks" msgstr "避免查找" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:695 msgid "" "Critical to Mercurial's performance is the avoidance of seeks of the disk " "head, since any seek is far more expensive than even a comparatively large " "read operation." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:699 msgid "" "This is why, for example, the dirstate is stored in a single file. If there " "were a dirstate file per directory that Mercurial tracked, the disk would " "seek once per directory. Instead, Mercurial reads the entire single dirstate " "file in one step." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:705 msgid "" "Mercurial also uses a <quote>copy on write</quote> scheme when cloning a " "repository on local storage. Instead of copying every revlog file from the " "old repository into the new repository, it makes a <quote>hard link</quote>, " "which is a shorthand way to say <quote>these two names point to the same " "file</quote>. When Mercurial is about to write to one of a revlog's files, " "it checks to see if the number of names pointing at the file is greater than " "one. If it is, more than one repository is using the file, so Mercurial " "makes a new copy of the file that is private to this repository." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:716 msgid "" "A few revision control developers have pointed out that this idea of making a " "complete private copy of a file is not very efficient in its use of storage. " "While this is true, storage is cheap, and this method gives the highest " "performance while deferring most book-keeping to the operating system. An " "alternative scheme would most likely reduce performance and increase the " "complexity of the software, but speed and simplicity are key to the " "<quote>feel</quote> of day-to-day use." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch04-concepts.xml:728 msgid "Other contents of the dirstate" msgstr "目录状态的其它内容" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:730 msgid "" "Because Mercurial doesn't force you to tell it when you're modifying a file, " "it uses the dirstate to store some extra information so it can determine " "efficiently whether you have modified a file. For each file in the working " "directory, it stores the time that it last modified the file itself, and the " "size of the file at that time." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:737 msgid "" "When you explicitly <command role=\"hg-cmd\">hg add</command>, <command role=" "\"hg-cmd\">hg remove</command>, <command role=\"hg-cmd\">hg rename</command> " "or <command role=\"hg-cmd\">hg copy</command> files, Mercurial updates the " "dirstate so that it knows what to do with those files when you commit." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:744 msgid "" "The dirstate helps Mercurial to efficiently check the status of files in a " "repository." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch04-concepts.xml:749 msgid "" "When Mercurial checks the state of a file in the working directory, it first " "checks a file's modification time against the time in the dirstate that " "records when Mercurial last wrote the file. If the last modified time is the " "same as the time when Mercurial wrote the file, the file must not have been " "modified, so Mercurial does not need to check any further." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch04-concepts.xml:758 msgid "" "If the file's size has changed, the file must have been modified. If the " "modification time has changed, but the size has not, only then does Mercurial " "need to actually read the contents of the file to see if it has changed." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch04-concepts.xml:766 msgid "" "Storing the modification time and size dramatically reduces the number of " "read operations that Mercurial needs to perform when we run commands like " "<command>hg status</command>. This results in large performance improvements." msgstr "" #. type: Content of: <book><chapter><title> #: ../en/ch05-daily.xml:5 msgid "Mercurial in daily use" msgstr "Mercurial 的日常使用" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch05-daily.xml:8 msgid "Telling Mercurial which files to track" msgstr "告诉 Mercurial 要跟踪哪些文件" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:10 msgid "" "Mercurial does not work with files in your repository unless you tell it to " "manage them. The <command role=\"hg-cmd\">hg status</command> command will " "tell you which files Mercurial doesn't know about; it uses a <quote><literal>?" "</literal></quote> to display such files." msgstr "" # #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:17 msgid "" "To tell Mercurial to track a file, use the <command role=\"hg-cmd\">hg add</" "command> command. Once you have added a file, the entry in the output of " "<command role=\"hg-cmd\">hg status</command> for that file changes from " "<quote><literal>?</literal></quote> to <quote><literal>A</literal></quote>." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:26 msgid "" "After you run a <command role=\"hg-cmd\">hg commit</command>, the files that " "you added before the commit will no longer be listed in the output of " "<command role=\"hg-cmd\">hg status</command>. The reason for this is that by " "default, <command role=\"hg-cmd\">hg status</command> only tells you about " "<quote>interesting</quote> files&emdash;those that you have (for example) " "modified, removed, or renamed. If you have a repository that contains " "thousands of files, you will rarely want to know about files that Mercurial " "is tracking, but that have not changed. (You can still get this information; " "we'll return to this later.)" msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:38 msgid "" "Once you add a file, Mercurial doesn't do anything with it immediately. " "Instead, it will take a snapshot of the file's state the next time you " "perform a commit. It will then continue to track the changes you make to the " "file every time you commit, until you remove the file." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch05-daily.xml:45 msgid "Explicit versus implicit file naming" msgstr "明确与隐含文件命名" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:47 msgid "" "A useful behavior that Mercurial has is that if you pass the name of a " "directory to a command, every Mercurial command will treat this as <quote>I " "want to operate on every file in this directory and its subdirectories</" "quote>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:54 msgid "" "Notice in this example that Mercurial printed the names of the files it " "added, whereas it didn't do so when we added the file named <filename>myfile." "txt</filename> in the earlier example." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:59 msgid "" "What's going on is that in the former case, we explicitly named the file to " "add on the command line. The assumption that Mercurial makes in such cases " "is that we know what we are doing, and it doesn't print any output." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:64 msgid "" "However, when we <emphasis>imply</emphasis> the names of files by giving the " "name of a directory, Mercurial takes the extra step of printing the name of " "each file that it does something with. This makes it more clear what is " "happening, and reduces the likelihood of a silent and nasty surprise. This " "behavior is common to most Mercurial commands." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch05-daily.xml:73 msgid "Mercurial tracks files, not directories" msgstr "Mercurial 只跟踪文件,不跟踪目录" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:75 msgid "" "Mercurial does not track directory information. Instead, it tracks the path " "to a file. Before creating a file, it first creates any missing directory " "components of the path. After it deletes a file, it then deletes any empty " "directories that were in the deleted file's path. This sounds like a trivial " "distinction, but it has one minor practical consequence: it is not possible " "to represent a completely empty directory in Mercurial." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:84 msgid "" "Empty directories are rarely useful, and there are unintrusive workarounds " "that you can use to achieve an appropriate effect. The developers of " "Mercurial thus felt that the complexity that would be required to manage " "empty directories was not worth the limited benefit this feature would bring." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:91 msgid "" "If you need an empty directory in your repository, there are a few ways to " "achieve this. One is to create a directory, then <command role=\"hg-cmd\">hg " "add</command> a <quote>hidden</quote> file to that directory. On Unix-like " "systems, any file name that begins with a period (<quote><literal>.</" "literal></quote>) is treated as hidden by most commands and GUI tools. This " "approach is illustrated below." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:102 msgid "" "Another way to tackle a need for an empty directory is to simply create one " "in your automated build scripts before they will need it." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch05-daily.xml:109 msgid "How to stop tracking a file" msgstr "如何停止跟踪文件" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:111 msgid "" "Once you decide that a file no longer belongs in your repository, use the " "<command role=\"hg-cmd\">hg remove</command> command. This deletes the file, " "and tells Mercurial to stop tracking it (which will occur at the next " "commit). A removed file is represented in the output of <command role=\"hg-" "cmd\">hg status</command> with a <quote><literal>R</literal></quote>." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:121 msgid "" "After you <command role=\"hg-cmd\">hg remove</command> a file, Mercurial will " "no longer track changes to that file, even if you recreate a file with the " "same name in your working directory. If you do recreate a file with the same " "name and want Mercurial to track the new file, simply <command role=\"hg-cmd" "\">hg add</command> it. Mercurial will know that the newly added file is not " "related to the old file of the same name." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch05-daily.xml:130 msgid "Removing a file does not affect its history" msgstr "删除文件不影响历史" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:132 msgid "It is important to understand that removing a file has only two effects." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch05-daily.xml:135 msgid "It removes the current version of the file from the working directory." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch05-daily.xml:138 msgid "" "It stops Mercurial from tracking changes to the file, from the time of the " "next commit." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:141 msgid "" "Removing a file <emphasis>does not</emphasis> in any way alter the " "<emphasis>history</emphasis> of the file." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:144 msgid "" "If you update the working directory to a changeset that was committed when it " "was still tracking a file that you later removed, the file will reappear in " "the working directory, with the contents it had when you committed that " "changeset. If you then update the working directory to a later changeset, in " "which the file had been removed, Mercurial will once again remove the file " "from the working directory." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch05-daily.xml:155 msgid "Missing files" msgstr "丢失的文件" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:157 msgid "" "Mercurial considers a file that you have deleted, but not used <command role=" "\"hg-cmd\">hg remove</command> to delete, to be <emphasis>missing</" "emphasis>. A missing file is represented with <quote><literal>!</literal></" "quote> in the output of <command role=\"hg-cmd\">hg status</command>. " "Mercurial commands will not generally do anything with missing files." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:167 msgid "" "If your repository contains a file that <command role=\"hg-cmd\">hg status</" "command> reports as missing, and you want the file to stay gone, you can run " "<command role=\"hg-cmd\">hg remove <option role=\"hg-opt-remove\">--after</" "option></command> at any time later on, to tell Mercurial that you really did " "mean to remove the file." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:177 msgid "" "On the other hand, if you deleted the missing file by accident, give <command " "role=\"hg-cmd\">hg revert</command> the name of the file to recover. It will " "reappear, in unmodified form." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch05-daily.xml:186 msgid "Aside: why tell Mercurial explicitly to remove a file?" msgstr "旁白: 为什么要明确告诉 Mercurial 删除文件?" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:189 msgid "" "You might wonder why Mercurial requires you to explicitly tell it that you " "are deleting a file. Early during the development of Mercurial, it let you " "delete a file however you pleased; Mercurial would notice the absence of the " "file automatically when you next ran a <command role=\"hg-cmd\">hg commit</" "command>, and stop tracking the file. In practice, this made it too easy to " "accidentally remove a file without noticing." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch05-daily.xml:200 msgid "Useful shorthand&emdash;adding and removing files in one step" msgstr "有用的速记—一个步骤添加和删除文件" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:203 msgid "" "Mercurial offers a combination command, <command role=\"hg-cmd\">hg " "addremove</command>, that adds untracked files and marks missing files as " "removed." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:209 msgid "" "The <command role=\"hg-cmd\">hg commit</command> command also provides a " "<option role=\"hg-opt-commit\">-A</option> option that performs this same add-" "and-remove, immediately followed by a commit." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch05-daily.xml:219 msgid "Copying files" msgstr "复制文件" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:221 msgid "" "Mercurial provides a <command role=\"hg-cmd\">hg copy</command> command that " "lets you make a new copy of a file. When you copy a file using this command, " "Mercurial makes a record of the fact that the new file is a copy of the " "original file. It treats these copied files specially when you merge your " "work with someone else's." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch05-daily.xml:229 msgid "The results of copying during a merge" msgstr "合并期间的复制结果" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:231 msgid "" "What happens during a merge is that changes <quote>follow</quote> a copy. To " "best illustrate what this means, let's create an example. We'll start with " "the usual tiny repository that contains a single file." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:238 msgid "" "We need to do some work in parallel, so that we'll have something to merge. " "So let's clone our repository." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:244 msgid "" "Back in our initial repository, let's use the <command role=\"hg-cmd\">hg " "copy</command> command to make a copy of the first file we created." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:250 msgid "" "If we look at the output of the <command role=\"hg-cmd\">hg status</command> " "command afterwards, the copied file looks just like a normal added file." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:256 msgid "" "But if we pass the <option role=\"hg-opt-status\">-C</option> option to " "<command role=\"hg-cmd\">hg status</command>, it prints another line of " "output: this is the file that our newly-added file was copied <emphasis>from</" "emphasis>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:264 msgid "" "Now, back in the repository we cloned, let's make a change in parallel. " "We'll add a line of content to the original file that we created." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:270 msgid "" "Now we have a modified <filename>file</filename> in this repository. When we " "pull the changes from the first repository, and merge the two heads, " "Mercurial will propagate the changes that we made locally to <filename>file</" "filename> into its copy, <filename>new-file</filename>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch05-daily.xml:280 msgid "Why should changes follow copies?" msgstr "为什么复制后需要后续修改?" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:282 msgid "" "This behavior&emdash;of changes to a file propagating out to copies of the " "file&emdash;might seem esoteric, but in most cases it's highly desirable." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:286 msgid "" "First of all, remember that this propagation <emphasis>only</emphasis> " "happens when you merge. So if you <command role=\"hg-cmd\">hg copy</command> " "a file, and subsequently modify the original file during the normal course of " "your work, nothing will happen." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:292 msgid "" "The second thing to know is that modifications will only propagate across a " "copy as long as the changeset that you're merging changes from " "<emphasis>hasn't yet seen</emphasis> the copy." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:297 msgid "" "The reason that Mercurial does this is as follows. Let's say I make an " "important bug fix in a source file, and commit my changes. Meanwhile, you've " "decided to <command role=\"hg-cmd\">hg copy</command> the file in your " "repository, without knowing about the bug or having seen the fix, and you " "have started hacking on your copy of the file." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:304 msgid "" "If you pulled and merged my changes, and Mercurial <emphasis>didn't</" "emphasis> propagate changes across copies, your new source file would now " "contain the bug, and unless you knew to propagate the bug fix by hand, the " "bug would <emphasis>remain</emphasis> in your copy of the file." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:310 msgid "" "By automatically propagating the change that fixed the bug from the original " "file to the copy, Mercurial prevents this class of problem. To my knowledge, " "Mercurial is the <emphasis>only</emphasis> revision control system that " "propagates changes across copies like this." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:316 msgid "" "Once your change history has a record that the copy and subsequent merge " "occurred, there's usually no further need to propagate changes from the " "original file to the copied file, and that's why Mercurial only propagates " "changes across copies at the first merge, and not afterwards." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch05-daily.xml:324 msgid "How to make changes <emphasis>not</emphasis> follow a copy" msgstr "如何让复制后<emphasis>不</emphasis>修改?" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:327 msgid "" "If, for some reason, you decide that this business of automatically " "propagating changes across copies is not for you, simply use your system's " "normal file copy command (on Unix-like systems, that's <command>cp</command>) " "to make a copy of a file, then <command role=\"hg-cmd\">hg add</command> the " "new copy by hand. Before you do so, though, please do reread <xref linkend=" "\"sec:daily:why-copy\"/>, and make an informed decision that this behavior is " "not appropriate to your specific case." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch05-daily.xml:340 msgid "Behavior of the <command role=\"hg-cmd\">hg copy</command> command" msgstr "命令 <command role=\"hg-cmd\">hg copy</command> 的特性" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:343 msgid "" "When you use the <command role=\"hg-cmd\">hg copy</command> command, " "Mercurial makes a copy of each source file as it currently stands in the " "working directory. This means that if you make some modifications to a file, " "then <command role=\"hg-cmd\">hg copy</command> it without first having " "committed those changes, the new copy will also contain the modifications you " "have made up until that point. (I find this behavior a little " "counterintuitive, which is why I mention it here.)" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:353 msgid "" "The <command role=\"hg-cmd\">hg copy</command> command acts similarly to the " "Unix <command>cp</command> command (you can use the <command role=\"hg-cmd" "\">hg cp</command> alias if you prefer). We must supply two or more " "arguments, of which the last is treated as the <emphasis>destination</" "emphasis>, and all others are <emphasis>sources</emphasis>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:361 msgid "" "If you pass <command role=\"hg-cmd\">hg copy</command> a single file as the " "source, and the destination does not exist, it creates a new file with that " "name." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:367 msgid "" "If the destination is a directory, Mercurial copies its sources into that " "directory." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:372 msgid "" "Copying a directory is recursive, and preserves the directory structure of " "the source." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:378 msgid "" "If the source and destination are both directories, the source tree is " "recreated in the destination directory." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:383 msgid "" "As with the <command role=\"hg-cmd\">hg remove</command> command, if you copy " "a file manually and then want Mercurial to know that you've copied the file, " "simply use the <option role=\"hg-opt-copy\">--after</option> option to " "<command role=\"hg-cmd\">hg copy</command>." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch05-daily.xml:394 msgid "Renaming files" msgstr "改名文件" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:396 msgid "" "It's rather more common to need to rename a file than to make a copy of it. " "The reason I discussed the <command role=\"hg-cmd\">hg copy</command> command " "before talking about renaming files is that Mercurial treats a rename in " "essentially the same way as a copy. Therefore, knowing what Mercurial does " "when you copy a file tells you what to expect when you rename a file." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:404 msgid "" "When you use the <command role=\"hg-cmd\">hg rename</command> command, " "Mercurial makes a copy of each source file, then deletes it and marks the " "file as removed." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:410 msgid "" "The <command role=\"hg-cmd\">hg status</command> command shows the newly " "copied file as added, and the copied-from file as removed." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:416 msgid "" "As with the results of a <command role=\"hg-cmd\">hg copy</command>, we must " "use the <option role=\"hg-opt-status\">-C</option> option to <command role=" "\"hg-cmd\">hg status</command> to see that the added file is really being " "tracked by Mercurial as a copy of the original, now removed, file." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:425 msgid "" "As with <command role=\"hg-cmd\">hg remove</command> and <command role=\"hg-" "cmd\">hg copy</command>, you can tell Mercurial about a rename after the fact " "using the <option role=\"hg-opt-rename\">--after</option> option. In most " "other respects, the behavior of the <command role=\"hg-cmd\">hg rename</" "command> command, and the options it accepts, are similar to the <command " "role=\"hg-cmd\">hg copy</command> command." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:434 msgid "" "If you're familiar with the Unix command line, you'll be glad to know that " "<command role=\"hg-cmd\">hg rename</command> command can be invoked as " "<command role=\"hg-cmd\">hg mv</command>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch05-daily.xml:440 msgid "Renaming files and merging changes" msgstr "改名文件与合并修改" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:442 msgid "" "Since Mercurial's rename is implemented as copy-and-remove, the same " "propagation of changes happens when you merge after a rename as after a copy." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:446 msgid "" "If I modify a file, and you rename it to a new name, and then we merge our " "respective changes, my modifications to the file under its original name will " "be propagated into the file under its new name. (This is something you might " "expect to <quote>simply work,</quote> but not all revision control systems " "actually do this.)" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:453 msgid "" "Whereas having changes follow a copy is a feature where you can perhaps nod " "and say <quote>yes, that might be useful,</quote> it should be clear that " "having them follow a rename is definitely important. Without this facility, " "it would simply be too easy for changes to become orphaned when files are " "renamed." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch05-daily.xml:462 msgid "Divergent renames and merging" msgstr "改名与合并的分歧" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:464 msgid "" "The case of diverging names occurs when two developers start with a " "file&emdash;let's call it <filename>foo</filename>&emdash;in their respective " "repositories." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:471 msgid "Anne renames the file to <filename>bar</filename>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:475 msgid "" "Meanwhile, Bob renames it to <filename>quux</filename>. (Remember that " "<command role=\"hg-cmd\">hg mv</command> is an alias for <command role=\"hg-" "cmd\">hg rename</command>.)" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:482 msgid "" "I like to think of this as a conflict because each developer has expressed " "different intentions about what the file ought to be named." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:486 msgid "" "What do you think should happen when they merge their work? Mercurial's " "actual behavior is that it always preserves <emphasis>both</emphasis> names " "when it merges changesets that contain divergent renames." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:493 msgid "" "Notice that while Mercurial warns about the divergent renames, it leaves it " "up to you to do something about the divergence after the merge." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch05-daily.xml:499 msgid "Convergent renames and merging" msgstr "收敛改名与合并" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:501 msgid "" "Another kind of rename conflict occurs when two people choose to rename " "different <emphasis>source</emphasis> files to the same " "<emphasis>destination</emphasis>. In this case, Mercurial runs its normal " "merge machinery, and lets you guide it to a suitable resolution." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch05-daily.xml:509 msgid "Other name-related corner cases" msgstr "其它名称相关的角落" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:511 msgid "" "Mercurial has a longstanding bug in which it fails to handle a merge where " "one side has a file with a given name, while another has a directory with the " "same name. This is documented as <ulink role=\"hg-bug\" url=\"http://www." "selenic.com/mercurial/bts/issue29\">issue 29</ulink>." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch05-daily.xml:524 msgid "Recovering from mistakes" msgstr "从错误恢复" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:526 msgid "" "Mercurial has some useful commands that will help you to recover from some " "common mistakes." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:529 msgid "" "The <command role=\"hg-cmd\">hg revert</command> command lets you undo " "changes that you have made to your working directory. For example, if you " "<command role=\"hg-cmd\">hg add</command> a file by accident, just run " "<command role=\"hg-cmd\">hg revert</command> with the name of the file you " "added, and while the file won't be touched in any way, it won't be tracked " "for adding by Mercurial any longer, either. You can also use <command role=" "\"hg-cmd\">hg revert</command> to get rid of erroneous changes to a file." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:539 msgid "" "It is helpful to remember that the <command role=\"hg-cmd\">hg revert</" "command> command is useful for changes that you have not yet committed. Once " "you've committed a change, if you decide it was a mistake, you can still do " "something about it, though your options may be more limited." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:546 msgid "" "For more information about the <command role=\"hg-cmd\">hg revert</command> " "command, and details about how to deal with changes you have already " "committed, see <xref linkend=\"chap:undo\"/>." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch05-daily.xml:553 msgid "Dealing with tricky merges" msgstr "合并的技巧" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:555 msgid "" "In a complicated or large project, it's not unusual for a merge of two " "changesets to result in some headaches. Suppose there's a big source file " "that's been extensively edited by each side of a merge: this is almost " "inevitably going to result in conflicts, some of which can take a few tries " "to sort out." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:562 msgid "" "Let's develop a simple case of this and see how to deal with it. We'll start " "off with a repository containing one file, and clone it twice." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:568 msgid "In one clone, we'll modify the file in one way." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:572 msgid "In another, we'll modify the file differently." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:576 msgid "Next, we'll pull each set of changes into our original repo." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:581 msgid "We expect our repository to now contain two heads." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:585 msgid "" "Normally, if we run <command role=\"hg-cmd\">hg merge</command> at this " "point, it will drop us into a GUI that will let us manually resolve the " "conflicting edits to <filename>myfile.txt</filename>. However, to simplify " "things for presentation here, we'd like the merge to fail immediately " "instead. Here's one way we can do so." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:594 msgid "" "We've told Mercurial's merge machinery to run the command <command>false</" "command> (which, as we desire, fails immediately) if it detects a merge that " "it can't sort out automatically." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:599 msgid "" "If we now fire up <command role=\"hg-cmd\">hg merge</command>, it should " "grind to a halt and report a failure." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:605 msgid "" "Even if we don't notice that the merge failed, Mercurial will prevent us from " "accidentally committing the result of a failed merge." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:611 msgid "" "When <command role=\"hg-cmd\">hg commit</command> fails in this case, it " "suggests that we use the unfamiliar <command role=\"hg-cmd\">hg resolve</" "command> command. As usual, <command role=\"hg-cmd\">hg help resolve</" "command> will print a helpful synopsis." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch05-daily.xml:618 msgid "File resolution states" msgstr "文件的解决状态" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:620 msgid "" "When a merge occurs, most files will usually remain unmodified. For each " "file where Mercurial has to do something, it tracks the state of the file." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch05-daily.xml:626 msgid "" "A <emphasis>resolved</emphasis> file has been successfully merged, either " "automatically by Mercurial or manually with human intervention." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch05-daily.xml:631 msgid "" "An <emphasis>unresolved</emphasis> file was not merged successfully, and " "needs more attention." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:636 msgid "" "If Mercurial sees <emphasis>any</emphasis> file in the unresolved state after " "a merge, it considers the merge to have failed. Fortunately, we do not need " "to restart the entire merge from scratch." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:641 msgid "" "The <option role=\"hg-opt-resolve\">--list</option> or <option role=\"hg-opt-" "resolve\">-l</option> option to <command role=\"hg-cmd\">hg resolve</command> " "prints out the state of each merged file." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:648 msgid "" "In the output from <command role=\"hg-cmd\">hg resolve</command>, a resolved " "file is marked with <literal>R</literal>, while an unresolved file is marked " "with <literal>U</literal>. If any files are listed with <literal>U</" "literal>, we know that an attempt to commit the results of the merge will " "fail." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch05-daily.xml:657 msgid "Resolving a file merge" msgstr "合并文件" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:659 msgid "" "We have several options to move a file from the unresolved into the resolved " "state. By far the most common is to rerun <command role=\"hg-cmd\">hg " "resolve</command>. If we pass the names of individual files or directories, " "it will retry the merges of any unresolved files present in those locations. " "We can also pass the <option role=\"hg-opt-resolve\">--all</option> or " "<option role=\"hg-opt-resolve\">-a</option> option, which will retry the " "merges of <emphasis>all</emphasis> unresolved files." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch05-daily.xml:669 msgid "" "Mercurial also lets us modify the resolution state of a file directly. We " "can manually mark a file as resolved using the <option role=\"hg-opt-resolve" "\">--mark</option> option, or as unresolved using the <option role=\"hg-opt-" "resolve\">--unmark</option> option. This allows us to clean up a " "particularly messy merge by hand, and to keep track of our progress with each " "file as we go." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch05-daily.xml:680 msgid "More useful diffs" msgstr "更有用的差异" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:682 msgid "" "The default output of the <command role=\"hg-cmd\">hg diff</command> command " "is backwards compatible with the regular <command>diff</command> command, but " "this has some drawbacks." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:687 msgid "" "Consider the case where we use <command role=\"hg-cmd\">hg rename</command> " "to rename a file." msgstr "" "设想我们使用 <command role=\"hg-cmd\">hg rename</command> 命令来改名文件。" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:692 msgid "" "The output of <command role=\"hg-cmd\">hg diff</command> above obscures the " "fact that we simply renamed a file. The <command role=\"hg-cmd\">hg diff</" "command> command accepts an option, <option>--git</option> or <option>-g</" "option>, to use a newer diff format that displays such information in a more " "readable form." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:701 msgid "" "This option also helps with a case that can otherwise be confusing: a file " "that appears to be modified according to <command role=\"hg-cmd\">hg status</" "command>, but for which <command role=\"hg-cmd\">hg diff</command> prints " "nothing. This situation can arise if we change the file's execute permissions." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:710 msgid "" "The normal <command>diff</command> command pays no attention to file " "permissions, which is why <command role=\"hg-cmd\">hg diff</command> prints " "nothing by default. If we supply it with the <option>-g</option> option, it " "tells us what really happened." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch05-daily.xml:720 msgid "Which files to manage, and which to avoid" msgstr "需要管理哪些文件,应该避免的事情" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:722 msgid "" "Revision control systems are generally best at managing text files that are " "written by humans, such as source code, where the files do not change much " "from one revision to the next. Some centralized revision control systems can " "also deal tolerably well with binary files, such as bitmap images." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:728 msgid "" "For instance, a game development team will typically manage both its source " "code and all of its binary assets (e.g. geometry data, textures, map layouts) " "in a revision control system." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:733 msgid "" "Because it is usually impossible to merge two conflicting modifications to a " "binary file, centralized systems often provide a file locking mechanism that " "allow a user to say <quote>I am the only person who can edit this file</" "quote>." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:739 msgid "" "Compared to a centralized system, a distributed revision control system " "changes some of the factors that guide decisions over which files to manage " "and how." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:743 msgid "" "For instance, a distributed revision control system cannot, by its nature, " "offer a file locking facility. There is thus no built-in mechanism to " "prevent two people from making conflicting changes to a binary file. If you " "have a team where several people may be editing binary files frequently, it " "may not be a good idea to use Mercurial&emdash;or any other distributed " "revision control system&emdash;to manage those files." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:751 msgid "" "When storing modifications to a file, Mercurial usually saves only the " "differences between the previous and current versions of the file. For most " "text files, this is extremely efficient. However, some files (particularly " "binary files) are laid out in such a way that even a small change to a file's " "logical content results in many or most of the bytes inside the file " "changing. For instance, compressed files are particularly susceptible to " "this. If the differences between each successive version of a file are always " "large, Mercurial will not be able to store the file's revision history very " "efficiently. This can affect both local storage needs and the amount of time " "it takes to clone a repository." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:764 msgid "" "To get an idea of how this could affect you in practice, suppose you want to " "use Mercurial to manage an OpenOffice document. OpenOffice stores documents " "on disk as compressed zip files. Edit even a single letter of your document " "in OpenOffice, and almost every byte in the entire file will change when you " "save it. Now suppose that file is 2MB in size. Because most of the file " "changes every time you save, Mercurial will have to store all 2MB of the file " "every time you commit, even though from your perspective, perhaps only a few " "words are changing each time. A single frequently-edited file that is not " "friendly to Mercurial's storage assumptions can easily have an outsized " "effect on the size of the repository." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:777 msgid "" "Even worse, if both you and someone else edit the OpenOffice document you're " "working on, there is no useful way to merge your work. In fact, there isn't " "even a good way to tell what the differences are between your respective " "changes." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:782 msgid "" "There are thus a few clear recommendations about specific kinds of files to " "be very careful with." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch05-daily.xml:787 msgid "" "Files that are very large and incompressible, e.g. ISO CD-ROM images, will by " "virtue of sheer size make clones over a network very slow." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch05-daily.xml:792 msgid "" "Files that change a lot from one revision to the next may be expensive to " "store if you edit them frequently, and conflicts due to concurrent edits may " "be difficult to resolve." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch05-daily.xml:801 msgid "Backups and mirroring" msgstr "备份与镜像" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:803 msgid "" "Since Mercurial maintains a complete copy of history in each clone, everyone " "who uses Mercurial to collaborate on a project can potentially act as a " "source of backups in the event of a catastrophe. If a central repository " "becomes unavailable, you can construct a replacement simply by cloning a copy " "of the repository from one contributor, and pulling any changes they may not " "have seen from others." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:811 msgid "" "It is simple to use Mercurial to perform off-site backups and remote " "mirrors. Set up a periodic job (e.g. via the <command>cron</command> " "command) on a remote server to pull changes from your master repositories " "every hour. This will only be tricky in the unlikely case that the number of " "master repositories you maintain changes frequently, in which case you'll " "need to do a little scripting to refresh the list of repositories to back up." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:820 msgid "" "If you perform traditional backups of your master repositories to tape or " "disk, and you want to back up a repository named <filename>myrepo</filename>, " "use <command>hg clone -U myrepo myrepo.bak</command> to create a clone of " "<filename>myrepo</filename> before you start your backups. The <option>-U</" "option> option doesn't check out a working directory after the clone " "completes, since that would be superfluous and make the backup take longer." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch05-daily.xml:829 msgid "" "If you then back up <filename>myrepo.bak</filename> instead of " "<filename>myrepo</filename>, you will be guaranteed to have a consistent " "snapshot of your repository that won't be pushed to by an insomniac developer " "in mid-backup." msgstr "" #. type: Content of: <book><chapter><title> #: ../en/ch06-collab.xml:5 msgid "Collaborating with other people" msgstr "团体协作" #. type: Content of: <book><chapter><para> #: ../en/ch06-collab.xml:7 msgid "" "As a completely decentralised tool, Mercurial doesn't impose any policy on " "how people ought to work with each other. However, if you're new to " "distributed revision control, it helps to have some tools and examples in " "mind when you're thinking about possible workflow models." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch06-collab.xml:14 msgid "Mercurial's web interface" msgstr "Mercurial 的 web 接口" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch06-collab.xml:16 msgid "" "Mercurial has a powerful web interface that provides several useful " "capabilities." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch06-collab.xml:19 msgid "" "For interactive use, the web interface lets you browse a single repository or " "a collection of repositories. You can view the history of a repository, " "examine each change (comments and diffs), and view the contents of each " "directory and file. You can even get a view of history that gives a " "graphical view of the relationships between individual changes and merges." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch06-collab.xml:26 msgid "" "Also for human consumption, the web interface provides Atom and RSS feeds of " "the changes in a repository. This lets you <quote>subscribe</quote> to a " "repository using your favorite feed reader, and be automatically notified of " "activity in that repository as soon as it happens. I find this capability " "much more convenient than the model of subscribing to a mailing list to which " "notifications are sent, as it requires no additional configuration on the " "part of whoever is serving the repository." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch06-collab.xml:36 msgid "" "The web interface also lets remote users clone a repository, pull changes " "from it, and (when the server is configured to permit it) push changes back " "to it. Mercurial's HTTP tunneling protocol aggressively compresses data, so " "that it works efficiently even over low-bandwidth network connections." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch06-collab.xml:42 msgid "" "The easiest way to get started with the web interface is to use your web " "browser to visit an existing repository, such as the master Mercurial " "repository at <ulink url=\"http://www.selenic.com/repo/hg\">http://www." "selenic.com/repo/hg</ulink>." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch06-collab.xml:47 msgid "" "If you're interested in providing a web interface to your own repositories, " "there are several good ways to do this." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch06-collab.xml:51 msgid "" "The easiest and fastest way to get started in an informal environment is to " "use the <command role=\"hg-cmd\">hg serve</command> command, which is best " "suited to short-term <quote>lightweight</quote> serving. See <xref linkend=" "\"sec:collab:serve\"/> below for details of how to use this command." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch06-collab.xml:58 msgid "" "For longer-lived repositories that you'd like to have permanently available, " "there are several public hosting services available. Some are free to open " "source projects, while others offer paid commercial hosting. An up-to-date " "list is available at <ulink url=\"http://www.selenic.com/mercurial/wiki/index." "cgi/MercurialHosting\">http://www.selenic.com/mercurial/wiki/index.cgi/" "MercurialHosting</ulink>." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch06-collab.xml:65 msgid "" "If you would prefer to host your own repositories, Mercurial has built-in " "support for several popular hosting technologies, most notably CGI (Common " "Gateway Interface), and WSGI (Web Services Gateway Interface). See <xref " "linkend=\"sec:collab:cgi\"/> for details of CGI and WSGI configuration." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch06-collab.xml:74 msgid "Collaboration models" msgstr "协作模型" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch06-collab.xml:76 msgid "" "With a suitably flexible tool, making decisions about workflow is much more " "of a social engineering challenge than a technical one. Mercurial imposes few " "limitations on how you can structure the flow of work in a project, so it's " "up to you and your group to set up and live with a model that matches your " "own particular needs." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch06-collab.xml:84 msgid "Factors to keep in mind" msgstr "要牢记的因素" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:86 msgid "" "The most important aspect of any model that you must keep in mind is how well " "it matches the needs and capabilities of the people who will be using it. " "This might seem self-evident; even so, you still can't afford to forget it " "for a moment." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:92 msgid "" "I once put together a workflow model that seemed to make perfect sense to me, " "but that caused a considerable amount of consternation and strife within my " "development team. In spite of my attempts to explain why we needed a complex " "set of branches, and how changes ought to flow between them, a few team " "members revolted. Even though they were smart people, they didn't want to " "pay attention to the constraints we were operating under, or face the " "consequences of those constraints in the details of the model that I was " "advocating." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:102 msgid "" "Don't sweep foreseeable social or technical problems under the rug. Whatever " "scheme you put into effect, you should plan for mistakes and problem " "scenarios. Consider adding automated machinery to prevent, or quickly " "recover from, trouble that you can anticipate. As an example, if you intend " "to have a branch with not-for-release changes in it, you'd do well to think " "early about the possibility that someone might accidentally merge those " "changes into a release branch. You could avoid this particular problem by " "writing a hook that prevents changes from being merged from an inappropriate " "branch." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch06-collab.xml:116 msgid "Informal anarchy" msgstr "无政府状态" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:118 msgid "" "I wouldn't suggest an <quote>anything goes</quote> approach as something " "sustainable, but it's a model that's easy to grasp, and it works perfectly " "well in a few unusual situations." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:123 msgid "" "As one example, many projects have a loose-knit group of collaborators who " "rarely physically meet each other. Some groups like to overcome the " "isolation of working at a distance by organizing occasional <quote>sprints</" "quote>. In a sprint, a number of people get together in a single location (a " "company's conference room, a hotel meeting room, that kind of place) and " "spend several days more or less locked in there, hacking intensely on a " "handful of projects." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:132 msgid "" "A sprint or a hacking session in a coffee shop are the perfect places to use " "the <command role=\"hg-cmd\">hg serve</command> command, since <command role=" "\"hg-cmd\">hg serve</command> does not require any fancy server " "infrastructure. You can get started with <command role=\"hg-cmd\">hg serve</" "command> in moments, by reading <xref linkend=\"sec:collab:serve\"/> below. " "Then simply tell the person next to you that you're running a server, send " "the URL to them in an instant message, and you immediately have a quick-" "turnaround way to work together. They can type your URL into their web " "browser and quickly review your changes; or they can pull a bugfix from you " "and verify it; or they can clone a branch containing a new feature and try it " "out." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:146 msgid "" "The charm, and the problem, with doing things in an ad hoc fashion like this " "is that only people who know about your changes, and where they are, can see " "them. Such an informal approach simply doesn't scale beyond a handful " "people, because each individual needs to know about <emphasis>n</emphasis> " "different repositories to pull from." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch06-collab.xml:156 msgid "A single central repository" msgstr "单一中央版本库" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:158 msgid "" "For smaller projects migrating from a centralised revision control tool, " "perhaps the easiest way to get started is to have changes flow through a " "single shared central repository. This is also the most common " "<quote>building block</quote> for more ambitious workflow schemes." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:164 msgid "" "Contributors start by cloning a copy of this repository. They can pull " "changes from it whenever they need to, and some (perhaps all) developers have " "permission to push a change back when they're ready for other people to see " "it." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:169 msgid "" "Under this model, it can still often make sense for people to pull changes " "directly from each other, without going through the central repository. " "Consider a case in which I have a tentative bug fix, but I am worried that if " "I were to publish it to the central repository, it might subsequently break " "everyone else's trees as they pull it. To reduce the potential for damage, I " "can ask you to clone my repository into a temporary repository of your own " "and test it. This lets us put off publishing the potentially unsafe change " "until it has had a little testing." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:180 msgid "" "If a team is hosting its own repository in this kind of scenario, people will " "usually use the <command>ssh</command> protocol to securely push changes to " "the central repository, as documented in <xref linkend=\"sec:collab:ssh\"/>. " "It's also usual to publish a read-only copy of the repository over HTTP, as " "in <xref linkend=\"sec:collab:cgi\"/>. Publishing over HTTP satisfies the " "needs of people who don't have push access, and those who want to use web " "browsers to browse the repository's history." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch06-collab.xml:193 msgid "A hosted central repository" msgstr "托管的中央版本库" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:195 msgid "" "A wonderful thing about public hosting services like <ulink url=\"http://" "bitbucket.org/\">Bitbucket</ulink> is that not only do they handle the fiddly " "server configuration details, such as user accounts, authentication, and " "secure wire protocols, they provide additional infrastructure to make this " "model work well." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:202 msgid "" "For instance, a well-engineered hosting service will let people clone their " "own copies of a repository with a single click. This lets people work in " "separate spaces and share their changes when they're ready." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:207 msgid "" "In addition, a good hosting service will let people communicate with each " "other, for instance to say <quote>there are changes ready for you to review " "in this tree</quote>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch06-collab.xml:214 msgid "Working with multiple branches" msgstr "使用多个分支工作" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:216 msgid "" "Projects of any significant size naturally tend to make progress on several " "fronts simultaneously. In the case of software, it's common for a project to " "go through periodic official releases. A release might then go into " "<quote>maintenance mode</quote> for a while after its first publication; " "maintenance releases tend to contain only bug fixes, not new features. In " "parallel with these maintenance releases, one or more future releases may be " "under development. People normally use the word <quote>branch</quote> to " "refer to one of these many slightly different directions in which development " "is proceeding." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:229 msgid "" "Mercurial is particularly well suited to managing a number of simultaneous, " "but not identical, branches. Each <quote>development direction</quote> can " "live in its own central repository, and you can merge changes from one to " "another as the need arises. Because repositories are independent of each " "other, unstable changes in a development branch will never affect a stable " "branch unless someone explicitly merges those changes into the stable branch." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:238 msgid "" "Here's an example of how this can work in practice. Let's say you have one " "<quote>main branch</quote> on a central server." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:244 msgid "People clone it, make changes locally, test them, and push them back." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:247 msgid "" "Once the main branch reaches a release milestone, you can use the <command " "role=\"hg-cmd\">hg tag</command> command to give a permanent name to the " "milestone revision." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:253 msgid "Let's say some ongoing development occurs on the main branch." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:258 msgid "" "Using the tag that was recorded at the milestone, people who clone that " "repository at any time in the future can use <command role=\"hg-cmd\">hg " "update</command> to get a copy of the working directory exactly as it was " "when that tagged revision was committed." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:266 msgid "" "In addition, immediately after the main branch is tagged, we can then clone " "the main branch on the server to a new <quote>stable</quote> branch, also on " "the server." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:272 msgid "" "If we need to make a change to the stable branch, we can then clone " "<emphasis>that</emphasis> repository, make our changes, commit, and push our " "changes back there." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:279 msgid "" "Because Mercurial repositories are independent, and Mercurial doesn't move " "changes around automatically, the stable and main branches are " "<emphasis>isolated</emphasis> from each other. The changes that we made on " "the main branch don't <quote>leak</quote> to the stable branch, and vice " "versa." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:286 msgid "" "We'll often want all of our bugfixes on the stable branch to show up on the " "main branch, too. Rather than rewrite a bugfix on the main branch, we can " "simply pull and merge changes from the stable to the main branch, and " "Mercurial will bring those bugfixes in for us." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:294 msgid "" "The main branch will still contain changes that are not on the stable branch, " "but it will also contain all of the bugfixes from the stable branch. The " "stable branch remains unaffected by these changes, since changes are only " "flowing from the stable to the main branch, and not the other way." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><figure><title> #: ../en/ch06-collab.xml:303 ../en/ch06-collab.xml:313 msgid "Feature branches" msgstr "特性分支" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:305 msgid "" "For larger projects, an effective way to manage change is to break up a team " "into smaller groups. Each group has a shared branch of its own, cloned from " "a single <quote>master</quote> branch used by the entire project. People " "working on an individual branch are typically quite isolated from " "developments on other branches." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><figure><mediaobject> #: ../en/ch06-collab.xml:315 msgid "" "<imageobject><imagedata width=\"100%\" fileref=\"figs/feature-branches.png\"/" "></imageobject>" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:320 msgid "" "When a particular feature is deemed to be in suitable shape, someone on that " "feature team pulls and merges from the master branch into the feature branch, " "then pushes back up to the master branch." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch06-collab.xml:327 msgid "The release train" msgstr "发布列车" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:329 msgid "" "Some projects are organized on a <quote>train</quote> basis: a release is " "scheduled to happen every few months, and whatever features are ready when " "the <quote>train</quote> is ready to leave are allowed in." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:334 msgid "" "This model resembles working with feature branches. The difference is that " "when a feature branch misses a train, someone on the feature team pulls and " "merges the changes that went out on that train release into the feature " "branch, and the team continues its work on top of that release so that their " "feature can make the next release." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch06-collab.xml:343 msgid "The Linux kernel model" msgstr "Linux 内核模型" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:345 msgid "" "The development of the Linux kernel has a shallow hierarchical structure, " "surrounded by a cloud of apparent chaos. Because most Linux developers use " "<command>git</command>, a distributed revision control tool with capabilities " "similar to Mercurial, it's useful to describe the way work flows in that " "environment; if you like the ideas, the approach translates well across tools." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:353 msgid "" "At the center of the community sits Linus Torvalds, the creator of Linux. He " "publishes a single source repository that is considered the " "<quote>authoritative</quote> current tree by the entire developer community. " "Anyone can clone Linus's tree, but he is very choosy about whose trees he " "pulls from." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:360 msgid "" "Linus has a number of <quote>trusted lieutenants</quote>. As a general rule, " "he pulls whatever changes they publish, in most cases without even reviewing " "those changes. Some of those lieutenants are generally agreed to be " "<quote>maintainers</quote>, responsible for specific subsystems within the " "kernel. If a random kernel hacker wants to make a change to a subsystem that " "they want to end up in Linus's tree, they must find out who the subsystem's " "maintainer is, and ask that maintainer to take their change. If the " "maintainer reviews their changes and agrees to take them, they'll pass them " "along to Linus in due course." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:372 msgid "" "Individual lieutenants have their own approaches to reviewing, accepting, and " "publishing changes; and for deciding when to feed them to Linus. In " "addition, there are several well known branches that people use for different " "purposes. For example, a few people maintain <quote>stable</quote> " "repositories of older versions of the kernel, to which they apply critical " "fixes as needed. Some maintainers publish multiple trees: one for " "experimental changes; one for changes that they are about to feed upstream; " "and so on. Others just publish a single tree." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:383 msgid "" "This model has two notable features. The first is that it's <quote>pull " "only</quote>. You have to ask, convince, or beg another developer to take a " "change from you, because there are almost no trees to which more than one " "person can push, and there's no way to push changes into a tree that someone " "else controls." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:390 msgid "" "The second is that it's based on reputation and acclaim. If you're an " "unknown, Linus will probably ignore changes from you without even " "responding. But a subsystem maintainer will probably review them, and will " "likely take them if they pass their criteria for suitability. The more " "<quote>good</quote> changes you contribute to a maintainer, the more likely " "they are to trust your judgment and accept your changes. If you're well-" "known and maintain a long-lived branch for something Linus hasn't yet " "accepted, people with similar interests may pull your changes regularly to " "keep up with your work." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:401 msgid "" "Reputation and acclaim don't necessarily cross subsystem or <quote>people</" "quote> boundaries. If you're a respected but specialised storage hacker, and " "you try to fix a networking bug, that change will receive a level of scrutiny " "from a network maintainer comparable to a change from a complete stranger." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:408 msgid "" "To people who come from more orderly project backgrounds, the comparatively " "chaotic Linux kernel development process often seems completely insane. It's " "subject to the whims of individuals; people make sweeping changes whenever " "they deem it appropriate; and the pace of development is astounding. And yet " "Linux is a highly successful, well-regarded piece of software." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch06-collab.xml:418 msgid "Pull-only versus shared-push collaboration" msgstr "只读与共享写协作" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:420 msgid "" "A perpetual source of heat in the open source community is whether a " "development model in which people only ever pull changes from others is " "<quote>better than</quote> one in which multiple people can push changes to a " "shared repository." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:426 msgid "" "Typically, the backers of the shared-push model use tools that actively " "enforce this approach. If you're using a centralised revision control tool " "such as Subversion, there's no way to make a choice over which model you'll " "use: the tool gives you shared-push, and if you want to do anything else, " "you'll have to roll your own approach on top (such as applying a patch by " "hand)." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:434 msgid "" "A good distributed revision control tool will support both models. You and " "your collaborators can then structure how you work together based on your own " "needs and preferences, not on what contortions your tools force you into." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch06-collab.xml:441 msgid "Where collaboration meets branch management" msgstr "协作与分支管理" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:443 msgid "" "Once you and your team set up some shared repositories and start propagating " "changes back and forth between local and shared repos, you begin to face a " "related, but slightly different challenge: that of managing the multiple " "directions in which your team may be moving at once. Even though this " "subject is intimately related to how your team collaborates, it's dense " "enough to merit treatment of its own, in <xref linkend=\"chap:branch\"/>." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch06-collab.xml:455 msgid "The technical side of sharing" msgstr "共享的技术因素" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch06-collab.xml:457 msgid "" "The remainder of this chapter is devoted to the question of sharing changes " "with your collaborators." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch06-collab.xml:462 msgid "Informal sharing with <command role=\"hg-cmd\">hg serve</command>" msgstr "使用 <command role=\"hg-cmd\">hg serve</command> 进行非正式共享" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch06-collab.xml:465 msgid "" "Mercurial's <command role=\"hg-cmd\">hg serve</command> command is " "wonderfully suited to small, tight-knit, and fast-paced group environments. " "It also provides a great way to get a feel for using Mercurial commands over " "a network." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch06-collab.xml:470 msgid "" "Run <command role=\"hg-cmd\">hg serve</command> inside a repository, and in " "under a second it will bring up a specialised HTTP server; this will accept " "connections from any client, and serve up data for that repository until you " "terminate it. Anyone who knows the URL of the server you just started, and " "can talk to your computer over the network, can then use a web browser or " "Mercurial to read data from that repository. A URL for a <command role=\"hg-" "cmd\">hg serve</command> instance running on a laptop is likely to look " "something like <literal>http://my-laptop.local:8000/</literal>." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch06-collab.xml:481 msgid "" "The <command role=\"hg-cmd\">hg serve</command> command is <emphasis>not</" "emphasis> a general-purpose web server. It can do only two things:" msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:485 msgid "" "Allow people to browse the history of the repository it's serving, from their " "normal web browsers." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:489 msgid "" "Speak Mercurial's wire protocol, so that people can <command role=\"hg-cmd" "\">hg clone</command> or <command role=\"hg-cmd\">hg pull</command> changes " "from that repository." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch06-collab.xml:494 msgid "" "In particular, <command role=\"hg-cmd\">hg serve</command> won't allow remote " "users to <emphasis>modify</emphasis> your repository. It's intended for read-" "only use." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch06-collab.xml:498 msgid "" "If you're getting started with Mercurial, there's nothing to prevent you from " "using <command role=\"hg-cmd\">hg serve</command> to serve up a repository on " "your own computer, then use commands like <command role=\"hg-cmd\">hg clone</" "command>, <command role=\"hg-cmd\">hg incoming</command>, and so on to talk " "to that server as if the repository was hosted remotely. This can help you to " "quickly get acquainted with using commands on network-hosted repositories." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch06-collab.xml:508 msgid "A few things to keep in mind" msgstr "要牢记的几件事" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:510 msgid "" "Because it provides unauthenticated read access to all clients, you should " "only use <command role=\"hg-cmd\">hg serve</command> in an environment where " "you either don't care, or have complete control over, who can access your " "network and pull data from your repository." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:516 msgid "" "The <command role=\"hg-cmd\">hg serve</command> command knows nothing about " "any firewall software you might have installed on your system or network. It " "cannot detect or control your firewall software. If other people are unable " "to talk to a running <command role=\"hg-cmd\">hg serve</command> instance, " "the second thing you should do (<emphasis>after</emphasis> you make sure that " "they're using the correct URL) is check your firewall configuration." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:525 msgid "" "By default, <command role=\"hg-cmd\">hg serve</command> listens for incoming " "connections on port 8000. If another process is already listening on the " "port you want to use, you can specify a different port to listen on using the " "<option role=\"hg-opt-serve\">-p</option> option." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:531 msgid "" "Normally, when <command role=\"hg-cmd\">hg serve</command> starts, it prints " "no output, which can be a bit unnerving. If you'd like to confirm that it is " "indeed running correctly, and find out what URL you should send to your " "collaborators, start it with the <option role=\"hg-opt-global\">-v</option> " "option." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch06-collab.xml:541 msgid "Using the Secure Shell (ssh) protocol" msgstr "使用 ssh 协议" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch06-collab.xml:543 msgid "" "You can pull and push changes securely over a network connection using the " "Secure Shell (<literal>ssh</literal>) protocol. To use this successfully, " "you may have to do a little bit of configuration on the client or server " "sides." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch06-collab.xml:548 msgid "" "If you're not familiar with ssh, it's the name of both a command and a " "network protocol that let you securely communicate with another computer. To " "use it with Mercurial, you'll be setting up one or more user accounts on a " "server so that remote users can log in and execute commands." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch06-collab.xml:554 msgid "" "(If you <emphasis>are</emphasis> familiar with ssh, you'll probably find some " "of the material that follows to be elementary in nature.)" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch06-collab.xml:559 msgid "How to read and write ssh URLs" msgstr "如何读写 ssh 路径" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:561 msgid "An ssh URL tends to look like this:" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> #: ../en/ch06-collab.xml:564 msgid "" "The <quote><literal>ssh://</literal></quote> part tells Mercurial to use the " "ssh protocol." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> #: ../en/ch06-collab.xml:567 msgid "" "The <quote><literal>bos@</literal></quote> component indicates what username " "to log into the server as. You can leave this out if the remote username is " "the same as your local username." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> #: ../en/ch06-collab.xml:572 msgid "" "The <quote><literal>hg.serpentine.com</literal></quote> gives the hostname of " "the server to log into." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> #: ../en/ch06-collab.xml:576 msgid "" "The <quote>:22</quote> identifies the port number to connect to the server " "on. The default port is 22, so you only need to specify a colon and port " "number if you're <emphasis>not</emphasis> using port 22." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> #: ../en/ch06-collab.xml:581 msgid "" "The remainder of the URL is the local path to the repository on the server." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:585 msgid "" "There's plenty of scope for confusion with the path component of ssh URLs, as " "there is no standard way for tools to interpret it. Some programs behave " "differently than others when dealing with these paths. This isn't an ideal " "situation, but it's unlikely to change. Please read the following paragraphs " "carefully." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:592 msgid "" "Mercurial treats the path to a repository on the server as relative to the " "remote user's home directory. For example, if user <literal>foo</literal> on " "the server has a home directory of <filename class=\"directory\">/home/foo</" "filename>, then an ssh URL that contains a path component of <filename class=" "\"directory\">bar</filename> <emphasis>really</emphasis> refers to the " "directory <filename class=\"directory\">/home/foo/bar</filename>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:601 msgid "" "If you want to specify a path relative to another user's home directory, you " "can use a path that starts with a tilde character followed by the user's name " "(let's call them <literal>otheruser</literal>), like this." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:607 msgid "" "And if you really want to specify an <emphasis>absolute</emphasis> path on " "the server, begin the path component with two slashes, as in this example." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch06-collab.xml:614 msgid "Finding an ssh client for your system" msgstr "为你的系统寻找 ssh 客户端" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:616 msgid "" "Almost every Unix-like system comes with OpenSSH preinstalled. If you're " "using such a system, run <literal>which ssh</literal> to find out if the " "<command>ssh</command> command is installed (it's usually in <filename class=" "\"directory\">/usr/bin</filename>). In the unlikely event that it isn't " "present, take a look at your system documentation to figure out how to " "install it." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:624 msgid "" "On Windows, the TortoiseHg package is bundled with a version of Simon " "Tatham's excellent <command>plink</command> command, and you should not need " "to do any further configuration." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch06-collab.xml:631 msgid "Generating a key pair" msgstr "产生密钥对" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:633 msgid "" "To avoid the need to repetitively type a password every time you need to use " "your ssh client, I recommend generating a key pair." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><tip><title> #: ../en/ch06-collab.xml:638 msgid "Key pairs are not mandatory" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><tip><para> #: ../en/ch06-collab.xml:640 msgid "" "Mercurial knows nothing about ssh authentication or key pairs. You can, if " "you like, safely ignore this section and the one that follows until you grow " "tired of repeatedly typing ssh passwords." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:648 msgid "" "On a Unix-like system, the <command>ssh-keygen</command> command will do the " "trick." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:651 msgid "" "On Windows, if you're using TortoiseHg, you may need to download a command " "named <command>puttygen</command> from <ulink url=\"http://www.chiark." "greenend.org.uk/~sgtatham/putty\">the PuTTY web site</ulink> to generate a " "key pair. See <ulink url=\"http://the.earth.li/~sgtatham/putty/0.60/htmldoc/" "Chapter8.html#pubkey-puttygen\">the <command>puttygen</command> " "documentation</ulink> for details of how use the command." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:663 msgid "" "When you generate a key pair, it's usually <emphasis>highly</emphasis> " "advisable to protect it with a passphrase. (The only time that you might not " "want to do this is when you're using the ssh protocol for automated tasks on " "a secure network.)" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:669 msgid "" "Simply generating a key pair isn't enough, however. You'll need to add the " "public key to the set of authorised keys for whatever user you're logging in " "remotely as. For servers using OpenSSH (the vast majority), this will mean " "adding the public key to a list in a file called <filename role=\"special" "\">authorized_keys</filename> in their <filename role=\"special\" class=" "\"directory\">.ssh</filename> directory." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:678 msgid "" "On a Unix-like system, your public key will have a <filename>.pub</filename> " "extension. If you're using <command>puttygen</command> on Windows, you can " "save the public key to a file of your choosing, or paste it from the window " "it's displayed in straight into the <filename role=\"special" "\">authorized_keys</filename> file." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch06-collab.xml:686 msgid "Using an authentication agent" msgstr "使用认证代理" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:688 msgid "" "An authentication agent is a daemon that stores passphrases in memory (so it " "will forget passphrases if you log out and log back in again). An ssh client " "will notice if it's running, and query it for a passphrase. If there's no " "authentication agent running, or the agent doesn't store the necessary " "passphrase, you'll have to type your passphrase every time Mercurial tries to " "communicate with a server on your behalf (e.g. whenever you pull or push " "changes)." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:697 msgid "" "The downside of storing passphrases in an agent is that it's possible for a " "well-prepared attacker to recover the plain text of your passphrases, in some " "cases even if your system has been power-cycled. You should make your own " "judgment as to whether this is an acceptable risk. It certainly saves a lot " "of repeated typing." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:706 msgid "" "On Unix-like systems, the agent is called <command>ssh-agent</command>, and " "it's often run automatically for you when you log in. You'll need to use the " "<command>ssh-add</command> command to add passphrases to the agent's store." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:713 msgid "" "On Windows, if you're using TortoiseHg, the <command>pageant</command> " "command acts as the agent. As with <command>puttygen</command>, you'll need " "to <ulink url=\"http://www.chiark.greenend.org.uk/%7Esgtatham/putty/download." "html\">download <command>pageant</command></ulink> from the PuTTY web site " "and read <ulink url=\"http://the.earth.li/~sgtatham/putty/0.60/htmldoc/" "Chapter9.html#pageant\">its documentation</ulink>. The <command>pageant</" "command> command adds an icon to your system tray that will let you manage " "stored passphrases." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch06-collab.xml:728 msgid "Configuring the server side properly" msgstr "正确配置服务器端" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:730 msgid "" "Because ssh can be fiddly to set up if you're new to it, a variety of things " "can go wrong. Add Mercurial on top, and there's plenty more scope for head-" "scratching. Most of these potential problems occur on the server side, not " "the client side. The good news is that once you've gotten a configuration " "working, it will usually continue to work indefinitely." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:738 msgid "" "Before you try using Mercurial to talk to an ssh server, it's best to make " "sure that you can use the normal <command>ssh</command> or <command>putty</" "command> command to talk to the server first. If you run into problems with " "using these commands directly, Mercurial surely won't work. Worse, it will " "obscure the underlying problem. Any time you want to debug ssh-related " "Mercurial problems, you should drop back to making sure that plain ssh client " "commands work first, <emphasis>before</emphasis> you worry about whether " "there's a problem with Mercurial." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:749 msgid "" "The first thing to be sure of on the server side is that you can actually log " "in from another machine at all. If you can't use <command>ssh</command> or " "<command>putty</command> to log in, the error message you get may give you a " "few hints as to what's wrong. The most common problems are as follows." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:756 msgid "" "If you get a <quote>connection refused</quote> error, either there isn't an " "SSH daemon running on the server at all, or it's inaccessible due to firewall " "configuration." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:761 msgid "" "If you get a <quote>no route to host</quote> error, you either have an " "incorrect address for the server or a seriously locked down firewall that " "won't admit its existence at all." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:766 msgid "" "If you get a <quote>permission denied</quote> error, you may have mistyped " "the username on the server, or you could have mistyped your key's passphrase " "or the remote user's password." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:771 msgid "" "In summary, if you're having trouble talking to the server's ssh daemon, " "first make sure that one is running at all. On many systems it will be " "installed, but disabled, by default. Once you're done with this step, you " "should then check that the server's firewall is configured to allow incoming " "connections on the port the ssh daemon is listening on (usually 22). Don't " "worry about more exotic possibilities for misconfiguration until you've " "checked these two first." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:781 msgid "" "If you're using an authentication agent on the client side to store " "passphrases for your keys, you ought to be able to log into the server " "without being prompted for a passphrase or a password. If you're prompted " "for a passphrase, there are a few possible culprits." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:787 msgid "" "You might have forgotten to use <command>ssh-add</command> or " "<command>pageant</command> to store the passphrase." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:791 msgid "You might have stored the passphrase for the wrong key." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:794 msgid "" "If you're being prompted for the remote user's password, there are another " "few possible problems to check." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:797 msgid "" "Either the user's home directory or their <filename role=\"special\" class=" "\"directory\">.ssh</filename> directory might have excessively liberal " "permissions. As a result, the ssh daemon will not trust or read their " "<filename role=\"special\">authorized_keys</filename> file. For example, a " "group-writable home or <filename role=\"special\" class=\"directory\">.ssh</" "filename> directory will often cause this symptom." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:806 msgid "" "The user's <filename role=\"special\">authorized_keys</filename> file may " "have a problem. If anyone other than the user owns or can write to that file, " "the ssh daemon will not trust or read it." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:813 msgid "" "In the ideal world, you should be able to run the following command " "successfully, and it should print exactly one line of output, the current " "date and time." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:818 msgid "" "If, on your server, you have login scripts that print banners or other junk " "even when running non-interactive commands like this, you should fix them " "before you continue, so that they only print output if they're run " "interactively. Otherwise these banners will at least clutter up Mercurial's " "output. Worse, they could potentially cause problems with running Mercurial " "commands remotely. Mercurial tries to detect and ignore banners in non-" "interactive <command>ssh</command> sessions, but it is not foolproof. (If " "you're editing your login scripts on your server, the usual way to see if a " "login script is running in an interactive shell is to check the return code " "from the command <literal>tty -s</literal>.)" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:832 msgid "" "Once you've verified that plain old ssh is working with your server, the next " "step is to ensure that Mercurial runs on the server. The following command " "should run successfully:" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:839 msgid "" "If you see an error message instead of normal <command role=\"hg-cmd\">hg " "version</command> output, this is usually because you haven't installed " "Mercurial to <filename class=\"directory\">/usr/bin</filename>. Don't worry " "if this is the case; you don't need to do that. But you should check for a " "few possible problems." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:846 msgid "" "Is Mercurial really installed on the server at all? I know this sounds " "trivial, but it's worth checking!" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:850 msgid "" "Maybe your shell's search path (usually set via the <envar>PATH</envar> " "environment variable) is simply misconfigured." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:854 msgid "" "Perhaps your <envar>PATH</envar> environment variable is only being set to " "point to the location of the <command>hg</command> executable if the login " "session is interactive. This can happen if you're setting the path in the " "wrong shell login script. See your shell's documentation for details." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:861 msgid "" "The <envar>PYTHONPATH</envar> environment variable may need to contain the " "path to the Mercurial Python modules. It might not be set at all; it could " "be incorrect; or it may be set only if the login is interactive." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:868 msgid "" "If you can run <command role=\"hg-cmd\">hg version</command> over an ssh " "connection, well done! You've got the server and client sorted out. You " "should now be able to use Mercurial to access repositories hosted by that " "username on that server. If you run into problems with Mercurial and ssh at " "this point, try using the <option role=\"hg-opt-global\">--debug</option> " "option to get a clearer picture of what's going on." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch06-collab.xml:877 msgid "Using compression with ssh" msgstr "通过 ssh 使用压缩" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:879 msgid "" "Mercurial does not compress data when it uses the ssh protocol, because the " "ssh protocol can transparently compress data. However, the default behavior " "of ssh clients is <emphasis>not</emphasis> to request compression." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:884 msgid "" "Over any network other than a fast LAN (even a wireless network), using " "compression is likely to significantly speed up Mercurial's network " "operations. For example, over a WAN, someone measured compression as " "reducing the amount of time required to clone a particularly large repository " "from 51 minutes to 17 minutes." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:891 msgid "" "Both <command>ssh</command> and <command>plink</command> accept a <option " "role=\"cmd-opt-ssh\">-C</option> option which turns on compression. You can " "easily edit your <filename role=\"special\">~/.hgrc</filename> to enable " "compression for all of Mercurial's uses of the ssh protocol. Here is how to " "do so for regular <command>ssh</command> on Unix-like systems, for example." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:901 msgid "" "If you use <command>ssh</command> on a Unix-like system, you can configure it " "to always use compression when talking to your server. To do this, edit your " "<filename role=\"special\">.ssh/config</filename> file (which may not yet " "exist), as follows." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:911 msgid "" "This defines a hostname alias, <literal>hg</literal>. When you use that " "hostname on the <command>ssh</command> command line or in a Mercurial " "<literal>ssh</literal>-protocol URL, it will cause <command>ssh</command> to " "connect to <literal>hg.example.com</literal> and use compression. This gives " "you both a shorter name to type and compression, each of which is a good " "thing in its own right." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch06-collab.xml:923 msgid "Serving over HTTP using CGI" msgstr "使用 CGI 通过 HTTP 提供服务" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch06-collab.xml:925 msgid "" "The simplest way to host one or more repositories in a permanent way is to " "use a web server and Mercurial's CGI support." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch06-collab.xml:929 msgid "" "Depending on how ambitious you are, configuring Mercurial's CGI interface can " "take anything from a few moments to several hours." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch06-collab.xml:933 msgid "" "We'll begin with the simplest of examples, and work our way towards a more " "complex configuration. Even for the most basic case, you're almost certainly " "going to need to read and modify your web server's configuration." msgstr "" #. type: Content of: <book><chapter><sect1><note><title> #: ../en/ch06-collab.xml:939 msgid "High pain tolerance required" msgstr "" #. type: Content of: <book><chapter><sect1><note><para> #: ../en/ch06-collab.xml:941 msgid "" "Configuring a web server is a complex, fiddly, and highly system-dependent " "activity. I can't possibly give you instructions that will cover anything " "like all of the cases you will encounter. Please use your discretion and " "judgment in following the sections below. Be prepared to make plenty of " "mistakes, and to spend a lot of time reading your server's error logs." msgstr "" #. type: Content of: <book><chapter><sect1><note><para> #: ../en/ch06-collab.xml:949 msgid "" "If you don't have a strong stomach for tweaking configurations over and over, " "or a compelling need to host your own services, you might want to try one of " "the public hosting services that I mentioned earlier." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch06-collab.xml:956 msgid "Web server configuration checklist" msgstr "Web 服务器配置检查表" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:958 msgid "" "Before you continue, do take a few moments to check a few aspects of your " "system's setup." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> #: ../en/ch06-collab.xml:962 msgid "" "Do you have a web server installed at all? Mac OS X and some Linux " "distributions ship with Apache, but many other systems may not have a web " "server installed." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> #: ../en/ch06-collab.xml:967 msgid "" "If you have a web server installed, is it actually running? On most systems, " "even if one is present, it will be disabled by default." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> #: ../en/ch06-collab.xml:971 msgid "" "Is your server configured to allow you to run CGI programs in the directory " "where you plan to do so? Most servers default to explicitly disabling the " "ability to run CGI programs." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:977 msgid "" "If you don't have a web server installed, and don't have substantial " "experience configuring Apache, you should consider using the " "<literal>lighttpd</literal> web server instead of Apache. Apache has a well-" "deserved reputation for baroque and confusing configuration. While " "<literal>lighttpd</literal> is less capable in some ways than Apache, most of " "these capabilities are not relevant to serving Mercurial repositories. And " "<literal>lighttpd</literal> is undeniably <emphasis>much</emphasis> easier to " "get started with than Apache." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch06-collab.xml:990 msgid "Basic CGI configuration" msgstr "基本 CGI 配置" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:992 msgid "" "On Unix-like systems, it's common for users to have a subdirectory named " "something like <filename class=\"directory\">public_html</filename> in their " "home directory, from which they can serve up web pages. A file named " "<filename>foo</filename> in this directory will be accessible at a URL of the " "form <literal>http://www.example.com/username/foo</literal>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:1000 msgid "" "To get started, find the <filename role=\"special\">hgweb.cgi</filename> " "script that should be present in your Mercurial installation. If you can't " "quickly find a local copy on your system, simply download one from the master " "Mercurial repository at <ulink url=\"http://www.selenic.com/repo/hg/raw-file/" "tip/hgweb.cgi\">http://www.selenic.com/repo/hg/raw-file/tip/hgweb.cgi</ulink>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:1007 ../en/ch06-collab.xml:1175 msgid "" "You'll need to copy this script into your <filename class=\"directory" "\">public_html</filename> directory, and ensure that it's executable." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:1012 msgid "" "The <literal>755</literal> argument to <command>chmod</command> is a little " "more general than just making the script executable: it ensures that the " "script is executable by anyone, and that <quote>group</quote> and " "<quote>other</quote> write permissions are <emphasis>not</emphasis> set. If " "you were to leave those write permissions enabled, Apache's <literal>suexec</" "literal> subsystem would likely refuse to execute the script. In fact, " "<literal>suexec</literal> also insists that the <emphasis>directory</" "emphasis> in which the script resides must not be writable by others." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><title> #: ../en/ch06-collab.xml:1026 msgid "What could <emphasis>possibly</emphasis> go wrong?" msgstr "什么<emphasis>可能</emphasis>会出错?" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch06-collab.xml:1029 msgid "" "Once you've copied the CGI script into place, go into a web browser, and try " "to open the URL <literal>http://myhostname/~myuser/hgweb.cgi</literal>, " "<emphasis>but</emphasis> brace yourself for instant failure. There's a high " "probability that trying to visit this URL will fail, and there are many " "possible reasons for this. In fact, you're likely to stumble over almost " "every one of the possible errors below, so please read carefully. The " "following are all of the problems I ran into on a system running Fedora 7, " "with a fresh installation of Apache, and a user account that I created " "specially to perform this exercise." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch06-collab.xml:1042 msgid "" "Your web server may have per-user directories disabled. If you're using " "Apache, search your config file for a <literal>UserDir</literal> directive. " "If there's none present, per-user directories will be disabled. If one " "exists, but its value is <literal>disabled</literal>, then per-user " "directories will be disabled. Otherwise, the string after <literal>UserDir</" "literal> gives the name of the subdirectory that Apache will look in under " "your home directory, for example <filename class=\"directory\">public_html</" "filename>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch06-collab.xml:1053 msgid "" "Your file access permissions may be too restrictive. The web server must be " "able to traverse your home directory and directories under your <filename " "class=\"directory\">public_html</filename> directory, and read files under " "the latter too. Here's a quick recipe to help you to make your permissions " "more appropriate." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch06-collab.xml:1063 msgid "" "The other possibility with permissions is that you might get a completely " "empty window when you try to load the script. In this case, it's likely that " "your access permissions are <emphasis>too permissive</emphasis>. Apache's " "<literal>suexec</literal> subsystem won't execute a script that's group- or " "world-writable, for example." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch06-collab.xml:1070 msgid "" "Your web server may be configured to disallow execution of CGI programs in " "your per-user web directory. Here's Apache's default per-user configuration " "from my Fedora system." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch06-collab.xml:1077 msgid "" "If you find a similar-looking <literal>Directory</literal> group in your " "Apache configuration, the directive to look at inside it is <literal>Options</" "literal>. Add <literal>ExecCGI</literal> to the end of this list if it's " "missing, and restart the web server." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch06-collab.xml:1084 msgid "" "If you find that Apache serves you the text of the CGI script instead of " "executing it, you may need to either uncomment (if already present) or add a " "directive like this." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch06-collab.xml:1090 msgid "" "The next possibility is that you might be served with a colourful Python " "backtrace claiming that it can't import a <literal>mercurial</literal>-" "related module. This is actually progress! The server is now capable of " "executing your CGI script. This error is only likely to occur if you're " "running a private installation of Mercurial, instead of a system-wide " "version. Remember that the web server runs the CGI program without any of " "the environment variables that you take for granted in an interactive " "session. If this error happens to you, edit your copy of <filename role=" "\"special\">hgweb.cgi</filename> and follow the directions inside it to " "correctly set your <envar>PYTHONPATH</envar> environment variable." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch06-collab.xml:1104 msgid "" "Finally, you are <emphasis>certain</emphasis> to be served with another " "colourful Python backtrace: this one will complain that it can't find " "<filename class=\"directory\">/path/to/repository</filename>. Edit your " "<filename role=\"special\">hgweb.cgi</filename> script and replace the " "<filename class=\"directory\">/path/to/repository</filename> string with the " "complete path to the repository you want to serve up." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch06-collab.xml:1114 msgid "" "At this point, when you try to reload the page, you should be presented with " "a nice HTML view of your repository's history. Whew!" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><title> #: ../en/ch06-collab.xml:1120 msgid "Configuring lighttpd" msgstr "配置 lighttpd" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch06-collab.xml:1122 msgid "" "To be exhaustive in my experiments, I tried configuring the increasingly " "popular <literal>lighttpd</literal> web server to serve the same repository " "as I described with Apache above. I had already overcome all of the problems " "I outlined with Apache, many of which are not server-specific. As a result, " "I was fairly sure that my file and directory permissions were good, and that " "my <filename role=\"special\">hgweb.cgi</filename> script was properly edited." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch06-collab.xml:1132 msgid "" "Once I had Apache running, getting <literal>lighttpd</literal> to serve the " "repository was a snap (in other words, even if you're trying to use " "<literal>lighttpd</literal>, you should read the Apache section). I first " "had to edit the <literal>mod_access</literal> section of its config file to " "enable <literal>mod_cgi</literal> and <literal>mod_userdir</literal>, both of " "which were disabled by default on my system. I then added a few lines to the " "end of the config file, to configure these modules." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch06-collab.xml:1144 msgid "" "With this done, <literal>lighttpd</literal> ran immediately for me. If I had " "configured <literal>lighttpd</literal> before Apache, I'd almost certainly " "have run into many of the same system-level configuration problems as I did " "with Apache. However, I found <literal>lighttpd</literal> to be noticeably " "easier to configure than Apache, even though I've used Apache for over a " "decade, and this was my first exposure to <literal>lighttpd</literal>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch06-collab.xml:1157 msgid "Sharing multiple repositories with one CGI script" msgstr "使用一个 CGI 脚本共享多个版本库" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:1159 msgid "" "The <filename role=\"special\">hgweb.cgi</filename> script only lets you " "publish a single repository, which is an annoying restriction. If you want " "to publish more than one without wracking yourself with multiple copies of " "the same script, each with different names, a better choice is to use the " "<filename role=\"special\">hgwebdir.cgi</filename> script." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:1167 msgid "" "The procedure to configure <filename role=\"special\">hgwebdir.cgi</filename> " "is only a little more involved than for <filename role=\"special\">hgweb.cgi</" "filename>. First, you must obtain a copy of the script. If you don't have " "one handy, you can download a copy from the master Mercurial repository at " "<ulink url=\"http://www.selenic.com/repo/hg/raw-file/tip/hgwebdir.cgi" "\">http://www.selenic.com/repo/hg/raw-file/tip/hgwebdir.cgi</ulink>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:1182 msgid "" "With basic configuration out of the way, try to visit <literal>http://" "myhostname/~myuser/hgwebdir.cgi</literal> in your\tbrowser. It should " "display an empty list of repositories. If you get a blank window or error " "message, try walking through the list of potential problems in <xref linkend=" "\"sec:collab:wtf\"/>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:1190 msgid "" "The <filename role=\"special\">hgwebdir.cgi</filename> script relies on an " "external configuration file. By default, it searches for a file named " "<filename role=\"special\">hgweb.config</filename> in the same directory as " "itself. You'll need to create this file, and make it world-readable. The " "format of the file is similar to a Windows <quote>ini</quote> file, as " "understood by Python's <literal>ConfigParser</literal> <citation>web:" "configparser</citation> module." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:1200 msgid "" "The easiest way to configure <filename role=\"special\">hgwebdir.cgi</" "filename> is with a section named <literal>collections</literal>. This will " "automatically publish <emphasis>every</emphasis> repository under the " "directories you name. The section should look like this:" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:1208 msgid "" "Mercurial interprets this by looking at the directory name on the " "<emphasis>right</emphasis> hand side of the <quote><literal>=</literal></" "quote> sign; finding repositories in that directory hierarchy; and using the " "text on the <emphasis>left</emphasis> to strip off matching text from the " "names it will actually list in the web interface. The remaining component of " "a path after this stripping has occurred is called a <quote>virtual path</" "quote>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:1217 msgid "" "Given the example above, if we have a repository whose local path is " "<filename class=\"directory\">/my/root/this/repo</filename>, the CGI script " "will strip the leading <filename class=\"directory\">/my/root</filename> from " "the name, and publish the repository with a virtual path of <filename class=" "\"directory\">this/repo</filename>. If the base URL for our CGI script is " "<literal>http://myhostname/~myuser/hgwebdir.cgi</literal>, the complete URL " "for that repository will be <literal>http://myhostname/~myuser/hgwebdir.cgi/" "this/repo</literal>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:1229 msgid "" "If we replace <filename class=\"directory\">/my/root</filename> on the left " "hand side of this example with <filename class=\"directory\">/my</filename>, " "then <filename role=\"special\">hgwebdir.cgi</filename> will only strip off " "<filename class=\"directory\">/my</filename> from the repository name, and " "will give us a virtual path of <filename class=\"directory\">root/this/repo</" "filename> instead of <filename class=\"directory\">this/repo</filename>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:1239 msgid "" "The <filename role=\"special\">hgwebdir.cgi</filename> script will " "recursively search each directory listed in the <literal>collections</" "literal> section of its configuration file, but it will <literal>not</" "literal> recurse into the repositories it finds." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:1245 msgid "" "The <literal>collections</literal> mechanism makes it easy to publish many " "repositories in a <quote>fire and forget</quote> manner. You only need to " "set up the CGI script and configuration file one time. Afterwards, you can " "publish or unpublish a repository at any time by simply moving it into, or " "out of, the directory hierarchy in which you've configured <filename role=" "\"special\">hgwebdir.cgi</filename> to look." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><title> #: ../en/ch06-collab.xml:1255 msgid "Explicitly specifying which repositories to publish" msgstr "明确指出要发布的版本库" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch06-collab.xml:1258 msgid "" "In addition to the <literal>collections</literal> mechanism, the <filename " "role=\"special\">hgwebdir.cgi</filename> script allows you to publish a " "specific list of repositories. To do so, create a <literal>paths</literal> " "section, with contents of the following form." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch06-collab.xml:1267 msgid "" "In this case, the virtual path (the component that will appear in a URL) is " "on the left hand side of each definition, while the path to the repository is " "on the right. Notice that there does not need to be any relationship between " "the virtual path you choose and the location of a repository in your " "filesystem." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch06-collab.xml:1274 msgid "" "If you wish, you can use both the <literal>collections</literal> and " "<literal>paths</literal> mechanisms simultaneously in a single configuration " "file." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><note><title> #: ../en/ch06-collab.xml:1280 msgid "Beware duplicate virtual paths" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><note><para> #: ../en/ch06-collab.xml:1282 msgid "" "If several repositories have the same virtual path, <filename role=\"special" "\">hgwebdir.cgi</filename> will not report an error. Instead, it will behave " "unpredictably." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch06-collab.xml:1291 msgid "Downloading source archives" msgstr "下载源代码档案包" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:1293 msgid "" "Mercurial's web interface lets users download an archive of any revision. " "This archive will contain a snapshot of the working directory as of that " "revision, but it will not contain a copy of the repository data." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:1298 msgid "" "By default, this feature is not enabled. To enable it, you'll need to add an " "<envar role=\"rc-item-web\">allow_archive</envar> item to the <literal role=" "\"rc-web\">web</literal> section of your <filename role=\"special\">~/.hgrc</" "filename>; see below for details." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch06-collab.xml:1305 msgid "Web configuration options" msgstr "Web 配置选项" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:1307 msgid "" "Mercurial's web interfaces (the <command role=\"hg-cmd\">hg serve</command> " "command, and the <filename role=\"special\">hgweb.cgi</filename> and " "<filename role=\"special\">hgwebdir.cgi</filename> scripts) have a number of " "configuration options that you can set. These belong in a section named " "<literal role=\"rc-web\">web</literal>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:1315 msgid "" "<envar role=\"rc-item-web\">allow_archive</envar>: Determines which (if any) " "archive download mechanisms Mercurial supports. If you enable this feature, " "users of the web interface will be able to download an archive of whatever " "revision of a repository they are viewing. To enable the archive feature, " "this item must take the form of a sequence of words drawn from the list below." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:1324 msgid "" "<literal>bz2</literal>: A <command>tar</command> archive, compressed using " "<literal>bzip2</literal> compression. This has the best compression ratio, " "but uses the most CPU time on the server." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:1330 msgid "" "<literal>gz</literal>: A <command>tar</command> archive, compressed using " "<literal>gzip</literal> compression." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:1334 msgid "" "<literal>zip</literal>: A <command>zip</command> archive, compressed using " "LZW compression. This format has the worst compression ratio, but is widely " "used in the Windows world." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:1340 msgid "" "If you provide an empty list, or don't have an <envar role=\"rc-item-web" "\">allow_archive</envar> entry at all, this feature will be disabled. Here " "is an example of how to enable all three supported formats." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:1347 msgid "" "<envar role=\"rc-item-web\">allowpull</envar>: Boolean. Determines whether " "the web interface allows remote users to <command role=\"hg-cmd\">hg pull</" "command> and <command role=\"hg-cmd\">hg clone</command> this repository over " "HTTP. If set to <literal>no</literal> or <literal>false</literal>, only the " "<quote>human-oriented</quote> portion of the web interface is available." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:1356 msgid "" "<envar role=\"rc-item-web\">contact</envar>: String. A free-form (but " "preferably brief) string identifying the person or group in charge of the " "repository. This often contains the name and email address of a person or " "mailing list. It often makes sense to place this entry in a repository's own " "<filename role=\"special\">.hg/hgrc</filename> file, but it can make sense to " "use in a global <filename role=\"special\">~/.hgrc</filename> if every " "repository has a single maintainer." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:1367 msgid "" "<envar role=\"rc-item-web\">maxchanges</envar>: Integer. The default maximum " "number of changesets to display in a single page of output." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:1371 msgid "" "<envar role=\"rc-item-web\">maxfiles</envar>: Integer. The default maximum " "number of modified files to display in a single page of output." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:1375 msgid "" "<envar role=\"rc-item-web\">stripes</envar>: Integer. If the web interface " "displays alternating <quote>stripes</quote> to make it easier to visually " "align rows when you are looking at a table, this number controls the number " "of rows in each stripe." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:1381 msgid "" "<envar role=\"rc-item-web\">style</envar>: Controls the template Mercurial " "uses to display the web interface. Mercurial ships with several web " "templates." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:1387 msgid "<literal>coal</literal> is monochromatic." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:1390 msgid "" "<literal>gitweb</literal> emulates the visual style of git's web interface." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:1394 msgid "<literal>monoblue</literal> uses solid blues and greys." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:1398 msgid "<literal>paper</literal> is the default." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:1401 msgid "<literal>spartan</literal> was the default for a long time." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:1405 msgid "" "You can also specify a custom template of your own; see <xref linkend=\"chap:" "template\"/> for details. Here, you can see how to enable the " "<literal>gitweb</literal> style." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:1413 msgid "" "<envar role=\"rc-item-web\">templates</envar>: Path. The directory in which " "to search for template files. By default, Mercurial searches in the " "directory in which it was installed." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:1418 msgid "" "If you are using <filename role=\"special\">hgwebdir.cgi</filename>, you can " "place a few configuration items in a <literal role=\"rc-web\">web</literal> " "section of the <filename role=\"special\">hgweb.config</filename> file " "instead of a <filename role=\"special\">~/.hgrc</filename> file, for " "convenience. These items are <envar role=\"rc-item-web\">motd</envar> and " "<envar role=\"rc-item-web\">style</envar>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><title> #: ../en/ch06-collab.xml:1429 msgid "Options specific to an individual repository" msgstr "针对单个版本库的选项" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch06-collab.xml:1431 msgid "" "A few <literal role=\"rc-web\">web</literal> configuration items ought to be " "placed in a repository's local <filename role=\"special\">.hg/hgrc</" "filename>, rather than a user's or global <filename role=\"special\">~/.hgrc</" "filename>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:1436 msgid "" "<envar role=\"rc-item-web\">description</envar>: String. A free-form (but " "preferably brief) string that describes the contents or purpose of the " "repository." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:1441 msgid "" "<envar role=\"rc-item-web\">name</envar>: String. The name to use for the " "repository in the web interface. This overrides the default name, which is " "the last component of the repository's path." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><title> #: ../en/ch06-collab.xml:1449 msgid "" "Options specific to the <command role=\"hg-cmd\">hg serve</command> command" msgstr "命令 <command role=\"hg-cmd\">hg serve</command> 的选项" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch06-collab.xml:1452 msgid "" "Some of the items in the <literal role=\"rc-web\">web</literal> section of a " "<filename role=\"special\">~/.hgrc</filename> file are only for use with the " "<command role=\"hg-cmd\">hg serve</command> command." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:1458 msgid "" "<envar role=\"rc-item-web\">accesslog</envar>: Path. The name of a file into " "which to write an access log. By default, the <command role=\"hg-cmd\">hg " "serve</command> command writes this information to standard output, not to a " "file. Log entries are written in the standard <quote>combined</quote> file " "format used by almost all web servers." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:1466 msgid "" "<envar role=\"rc-item-web\">address</envar>: String. The local address on " "which the server should listen for incoming connections. By default, the " "server listens on all addresses." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:1471 msgid "" "<envar role=\"rc-item-web\">errorlog</envar>: Path. The name of a file into " "which to write an error log. By default, the <command role=\"hg-cmd\">hg " "serve</command> command writes this information to standard error, not to a " "file." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:1477 msgid "" "<envar role=\"rc-item-web\">ipv6</envar>: Boolean. Whether to use the IPv6 " "protocol. By default, IPv6 is not used." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> #: ../en/ch06-collab.xml:1481 msgid "" "<envar role=\"rc-item-web\">port</envar>: Integer. The TCP port number on " "which the server should listen. The default port number used is 8000." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><title> #: ../en/ch06-collab.xml:1488 msgid "" "Choosing the right <filename role=\"special\">~/.hgrc</filename> file to add " "<literal role=\"rc-web\">web</literal> items to" msgstr "" "选择正确的 <filename role=\"special\"> ~/.hgrc</filename> 文件增加到 <literal " "role=\"rc-web\">web</literal> 条目" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch06-collab.xml:1492 msgid "" "It is important to remember that a web server like Apache or " "<literal>lighttpd</literal> will run under a user ID that is different to " "yours. CGI scripts run by your server, such as <filename role=\"special" "\">hgweb.cgi</filename>, will usually also run under that user ID." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch06-collab.xml:1499 msgid "" "If you add <literal role=\"rc-web\">web</literal> items to your own personal " "<filename role=\"special\">~/.hgrc</filename> file, CGI scripts won't read " "that <filename role=\"special\">~/.hgrc</filename> file. Those settings will " "thus only affect the behavior of the <command role=\"hg-cmd\">hg serve</" "command> command when you run it. To cause CGI scripts to see your settings, " "either create a <filename role=\"special\">~/.hgrc</filename> file in the " "home directory of the user ID that runs your web server, or add those " "settings to a system-wide <filename role=\"special\">hgrc</filename> file." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch06-collab.xml:1514 msgid "System-wide configuration" msgstr "全局配置" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch06-collab.xml:1516 msgid "" "On Unix-like systems shared by multiple users (such as a server to which " "people publish changes), it often makes sense to set up some global default " "behaviors, such as what theme to use in web interfaces." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch06-collab.xml:1521 msgid "" "If a file named <filename>/etc/mercurial/hgrc</filename> exists, Mercurial " "will read it at startup time and apply any configuration settings it finds in " "that file. It will also look for files ending in a <literal>.rc</literal> " "extension in a directory named <filename>/etc/mercurial/hgrc.d</filename>, " "and apply any configuration settings it finds in each of those files." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch06-collab.xml:1530 msgid "Making Mercurial more trusting" msgstr "让 Mercurial 更可信" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:1532 msgid "" "One situation in which a global <filename>hgrc</filename> can be useful is if " "users are pulling changes owned by other users. By default, Mercurial will " "not trust most of the configuration items in a <filename>.hg/hgrc</filename> " "file inside a repository that is owned by a different user. If we clone or " "pull changes from such a repository, Mercurial will print a warning stating " "that it does not trust their <filename>.hg/hgrc</filename>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch06-collab.xml:1541 msgid "" "If everyone in a particular Unix group is on the same team and " "<emphasis>should</emphasis> trust each other's configuration settings, or we " "want to trust particular users, we can override Mercurial's skeptical " "defaults by creating a system-wide <filename>hgrc</filename> file such as the " "following:" msgstr "" #. type: Content of: <book><chapter><title> #: ../en/ch07-filenames.xml:5 msgid "File names and pattern matching" msgstr "文件名称与模式匹配" #. type: Content of: <book><chapter><para> #: ../en/ch07-filenames.xml:7 msgid "" "Mercurial provides mechanisms that let you work with file names in a " "consistent and expressive way." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch07-filenames.xml:11 msgid "Simple file naming" msgstr "简单文件名称" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch07-filenames.xml:13 msgid "" "Mercurial uses a unified piece of machinery <quote>under the hood</quote> to " "handle file names. Every command behaves uniformly with respect to file " "names. The way in which commands work with file names is as follows." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch07-filenames.xml:18 msgid "" "If you explicitly name real files on the command line, Mercurial works with " "exactly those files, as you would expect. &interaction.filenames.files;" msgstr "" # #. type: Content of: <book><chapter><sect1><para> #: ../en/ch07-filenames.xml:22 msgid "" "When you provide a directory name, Mercurial will interpret this as " "<quote>operate on every file in this directory and its subdirectories</" "quote>. Mercurial traverses the files and subdirectories in a directory in " "alphabetical order. When it encounters a subdirectory, it will traverse that " "subdirectory before continuing with the current directory." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch07-filenames.xml:33 msgid "Running commands without any file names" msgstr "不提供文件名称的执行命令" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch07-filenames.xml:35 msgid "" "Mercurial's commands that work with file names have useful default behaviors " "when you invoke them without providing any file names or patterns. What kind " "of behavior you should expect depends on what the command does. Here are a " "few rules of thumb you can use to predict what a command is likely to do if " "you don't give it any names to work with." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch07-filenames.xml:42 msgid "" "Most commands will operate on the entire working directory. This is what the " "<command role=\"hg-cmd\">hg add</command> command does, for example." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch07-filenames.xml:46 msgid "" "If the command has effects that are difficult or impossible to reverse, it " "will force you to explicitly provide at least one name or pattern (see " "below). This protects you from accidentally deleting files by running " "<command role=\"hg-cmd\">hg remove</command> with no arguments, for example." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch07-filenames.xml:54 msgid "" "It's easy to work around these default behaviors if they don't suit you. If " "a command normally operates on the whole working directory, you can invoke it " "on just the current directory and its subdirectories by giving it the name " "<quote><filename class=\"directory\">.</filename></quote>." msgstr "" # #. type: Content of: <book><chapter><sect1><para> #: ../en/ch07-filenames.xml:62 msgid "" "Along the same lines, some commands normally print file names relative to the " "root of the repository, even if you're invoking them from a subdirectory. " "Such a command will print file names relative to your subdirectory if you " "give it explicit names. Here, we're going to run <command role=\"hg-cmd\">hg " "status</command> from a subdirectory, and get it to operate on the entire " "working directory while printing file names relative to our subdirectory, by " "passing it the output of the <command role=\"hg-cmd\">hg root</command> " "command." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch07-filenames.xml:76 msgid "Telling you what's going on" msgstr "告诉你正在做什么" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch07-filenames.xml:78 msgid "" "The <command role=\"hg-cmd\">hg add</command> example in the preceding " "section illustrates something else that's helpful about Mercurial commands. " "If a command operates on a file that you didn't name explicitly on the " "command line, it will usually print the name of the file, so that you will " "not be surprised what's going on." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch07-filenames.xml:85 msgid "" "The principle here is of <emphasis>least surprise</emphasis>. If you've " "exactly named a file on the command line, there's no point in repeating it " "back at you. If Mercurial is acting on a file <emphasis>implicitly</" "emphasis>, e.g. because you provided no names, or a directory, or a pattern " "(see below), it is safest to tell you what files it's operating on." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch07-filenames.xml:92 msgid "" "For commands that behave this way, you can silence them using the <option " "role=\"hg-opt-global\">-q</option> option. You can also get them to print " "the name of every file, even those you've named explicitly, using the <option " "role=\"hg-opt-global\">-v</option> option." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch07-filenames.xml:100 msgid "Using patterns to identify files" msgstr "使用模式标识文件" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch07-filenames.xml:102 msgid "" "In addition to working with file and directory names, Mercurial lets you use " "<emphasis>patterns</emphasis> to identify files. Mercurial's pattern " "handling is expressive." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch07-filenames.xml:106 msgid "" "On Unix-like systems (Linux, MacOS, etc.), the job of matching file names to " "patterns normally falls to the shell. On these systems, you must explicitly " "tell Mercurial that a name is a pattern. On Windows, the shell does not " "expand patterns, so Mercurial will automatically identify names that are " "patterns, and expand them for you." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch07-filenames.xml:113 msgid "" "To provide a pattern in place of a regular name on the command line, the " "mechanism is simple:" msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch07-filenames.xml:116 msgid "" "That is, a pattern is identified by a short text string that says what kind " "of pattern this is, followed by a colon, followed by the actual pattern." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch07-filenames.xml:120 msgid "" "Mercurial supports two kinds of pattern syntax. The most frequently used is " "called <literal>glob</literal>; this is the same kind of pattern matching " "used by the Unix shell, and should be familiar to Windows command prompt " "users, too." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch07-filenames.xml:125 msgid "" "When Mercurial does automatic pattern matching on Windows, it uses " "<literal>glob</literal> syntax. You can thus omit the <quote><literal>glob:</" "literal></quote> prefix on Windows, but it's safe to use it, too." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch07-filenames.xml:130 msgid "" "The <literal>re</literal> syntax is more powerful; it lets you specify " "patterns using regular expressions, also known as regexps." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch07-filenames.xml:134 msgid "" "By the way, in the examples that follow, notice that I'm careful to wrap all " "of my patterns in quote characters, so that they won't get expanded by the " "shell before Mercurial sees them." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch07-filenames.xml:140 msgid "Shell-style <literal>glob</literal> patterns" msgstr "外壳风格的 <literal>glob</literal> 模式" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch07-filenames.xml:142 msgid "" "This is an overview of the kinds of patterns you can use when you're matching " "on glob patterns." msgstr "" # #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch07-filenames.xml:145 msgid "" "The <quote><literal>*</literal></quote> character matches any string, within " "a single directory." msgstr "" # #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch07-filenames.xml:150 msgid "" "The <quote><literal>**</literal></quote> pattern matches any string, and " "crosses directory boundaries. It's not a standard Unix glob token, but it's " "accepted by several popular Unix shells, and is very useful." msgstr "" # #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch07-filenames.xml:157 msgid "" "The <quote><literal>?</literal></quote> pattern matches any single character." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch07-filenames.xml:162 msgid "" "The <quote><literal>[</literal></quote> character begins a " "<emphasis>character class</emphasis>. This matches any single character " "within the class. The class ends with a <quote><literal>]</literal></quote> " "character. A class may contain multiple <emphasis>range</emphasis>s of the " "form <quote><literal>a-f</literal></quote>, which is shorthand for " "<quote><literal>abcdef</literal></quote>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch07-filenames.xml:172 msgid "" "If the first character after the <quote><literal>[</literal></quote> in a " "character class is a <quote><literal>!</literal></quote>, it " "<emphasis>negates</emphasis> the class, making it match any single character " "not in the class." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch07-filenames.xml:178 msgid "" "A <quote><literal>{</literal></quote> begins a group of subpatterns, where " "the whole group matches if any subpattern in the group matches. The " "<quote><literal>,</literal></quote> character separates subpatterns, and " "<quote><literal>}</literal></quote> ends the group." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><title> #: ../en/ch07-filenames.xml:187 msgid "Watch out!" msgstr "千万小心!" # #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch07-filenames.xml:189 msgid "" "Don't forget that if you want to match a pattern in any directory, you should " "not be using the <quote><literal>*</literal></quote> match-any token, as this " "will only match within one directory. Instead, use the <quote><literal>**</" "literal></quote> token. This small example illustrates the difference " "between the two." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch07-filenames.xml:201 msgid "Regular expression matching with <literal>re</literal> patterns" msgstr "使用 <literal>re</literal> 模式的正则表达式匹配" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch07-filenames.xml:204 msgid "" "Mercurial accepts the same regular expression syntax as the Python " "programming language (it uses Python's regexp engine internally). This is " "based on the Perl language's regexp syntax, which is the most popular dialect " "in use (it's also used in Java, for example)." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch07-filenames.xml:210 msgid "" "I won't discuss Mercurial's regexp dialect in any detail here, as regexps are " "not often used. Perl-style regexps are in any case already exhaustively " "documented on a multitude of web sites, and in many books. Instead, I will " "focus here on a few things you should know if you find yourself needing to " "use regexps with Mercurial." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch07-filenames.xml:217 msgid "" "A regexp is matched against an entire file name, relative to the root of the " "repository. In other words, even if you're already in subbdirectory " "<filename class=\"directory\">foo</filename>, if you want to match files " "under this directory, your pattern must start with <quote><literal>foo/</" "literal></quote>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch07-filenames.xml:224 msgid "" "One thing to note, if you're familiar with Perl-style regexps, is that " "Mercurial's are <emphasis>rooted</emphasis>. That is, a regexp starts " "matching against the beginning of a string; it doesn't look for a match " "anywhere within the string. To match anywhere in a string, start your " "pattern with <quote><literal>.*</literal></quote>." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch07-filenames.xml:234 msgid "Filtering files" msgstr "过滤文件" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch07-filenames.xml:236 msgid "" "Not only does Mercurial give you a variety of ways to specify files; it lets " "you further winnow those files using <emphasis>filters</emphasis>. Commands " "that work with file names accept two filtering options." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch07-filenames.xml:241 msgid "" "<option role=\"hg-opt-global\">-I</option>, or <option role=\"hg-opt-global" "\">--include</option>, lets you specify a pattern that file names must match " "in order to be processed." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch07-filenames.xml:246 msgid "" "<option role=\"hg-opt-global\">-X</option>, or <option role=\"hg-opt-global" "\">--exclude</option>, gives you a way to <emphasis>avoid</emphasis> " "processing files, if they match this pattern." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch07-filenames.xml:251 msgid "" "You can provide multiple <option role=\"hg-opt-global\">-I</option> and " "<option role=\"hg-opt-global\">-X</option> options on the command line, and " "intermix them as you please. Mercurial interprets the patterns you provide " "using glob syntax by default (but you can use regexps if you need to)." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch07-filenames.xml:258 msgid "" "You can read a <option role=\"hg-opt-global\">-I</option> filter as " "<quote>process only the files that match this filter</quote>." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch07-filenames.xml:264 msgid "" "The <option role=\"hg-opt-global\">-X</option> filter is best read as " "<quote>process only the files that don't match this pattern</quote>." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch07-filenames.xml:272 msgid "Permanently ignoring unwanted files and directories" msgstr "始终忽略不需要的文件和目录" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch07-filenames.xml:274 msgid "" "When you create a new repository, the chances are that over time it will grow " "to contain files that ought to <emphasis>not</emphasis> be managed by " "Mercurial, but which you don't want to see listed every time you run " "<command>hg status</command>. For instance, <quote>build products</quote> " "are files that are created as part of a build but which should not be managed " "by a revision control system. The most common build products are output " "files produced by software tools such as compilers. As another example, many " "text editors litter a directory with lock files, temporary working files, and " "backup files, which it also makes no sense to manage." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch07-filenames.xml:286 msgid "" "To have Mercurial permanently ignore such files, create a file named " "<filename>.hgignore</filename> in the root of your repository. You " "<emphasis>should</emphasis> <command>hg add</command> this file so that it " "gets tracked with the rest of your repository contents, since your " "collaborators will probably find it useful too." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch07-filenames.xml:293 msgid "" "By default, the <filename>.hgignore</filename> file should contain a list of " "regular expressions, one per line. Empty lines are skipped. Most people " "prefer to describe the files they want to ignore using the <quote>glob</" "quote> syntax that we described above, so a typical <filename>.hgignore</" "filename> file will start with this directive:" msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch07-filenames.xml:302 msgid "" "This tells Mercurial to interpret the lines that follow as glob patterns, not " "regular expressions." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch07-filenames.xml:305 msgid "Here is a typical-looking <filename>.hgignore</filename> file." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch07-filenames.xml:329 msgid "Case sensitivity" msgstr "大小写敏感性" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch07-filenames.xml:331 msgid "" "If you're working in a mixed development environment that contains both Linux " "(or other Unix) systems and Macs or Windows systems, you should keep in the " "back of your mind the knowledge that they treat the case (<quote>N</quote> " "versus <quote>n</quote>) of file names in incompatible ways. This is not " "very likely to affect you, and it's easy to deal with if it does, but it " "could surprise you if you don't know about it." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch07-filenames.xml:340 msgid "" "Operating systems and filesystems differ in the way they handle the " "<emphasis>case</emphasis> of characters in file and directory names. There " "are three common ways to handle case in names." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch07-filenames.xml:345 msgid "" "Completely case insensitive. Uppercase and lowercase versions of a letter " "are treated as identical, both when creating a file and during subsequent " "accesses. This is common on older DOS-based systems." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch07-filenames.xml:350 msgid "" "Case preserving, but insensitive. When a file or directory is created, the " "case of its name is stored, and can be retrieved and displayed by the " "operating system. When an existing file is being looked up, its case is " "ignored. This is the standard arrangement on Windows and MacOS. The names " "<filename>foo</filename> and <filename>FoO</filename> identify the same " "file. This treatment of uppercase and lowercase letters as interchangeable " "is also referred to as <emphasis>case folding</emphasis>." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch07-filenames.xml:361 msgid "" "Case sensitive. The case of a name is significant at all times. The names " "<filename>foo</filename> and <filename>FoO</filename> identify different " "files. This is the way Linux and Unix systems normally work." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch07-filenames.xml:368 msgid "" "On Unix-like systems, it is possible to have any or all of the above ways of " "handling case in action at once. For example, if you use a USB thumb drive " "formatted with a FAT32 filesystem on a Linux system, Linux will handle names " "on that filesystem in a case preserving, but insensitive, way." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch07-filenames.xml:375 msgid "Safe, portable repository storage" msgstr "安全,可移植的版本库存储" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch07-filenames.xml:377 msgid "" "Mercurial's repository storage mechanism is <emphasis>case safe</emphasis>. " "It translates file names so that they can be safely stored on both case " "sensitive and case insensitive filesystems. This means that you can use " "normal file copying tools to transfer a Mercurial repository onto, for " "example, a USB thumb drive, and safely move that drive and repository back " "and forth between a Mac, a PC running Windows, and a Linux box." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch07-filenames.xml:388 msgid "Detecting case conflicts" msgstr "检测大小写冲突" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch07-filenames.xml:390 msgid "" "When operating in the working directory, Mercurial honours the naming policy " "of the filesystem where the working directory is located. If the filesystem " "is case preserving, but insensitive, Mercurial will treat names that differ " "only in case as the same." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch07-filenames.xml:396 msgid "" "An important aspect of this approach is that it is possible to commit a " "changeset on a case sensitive (typically Linux or Unix) filesystem that will " "cause trouble for users on case insensitive (usually Windows and MacOS) " "users. If a Linux user commits changes to two files, one named " "<filename>myfile.c</filename> and the other named <filename>MyFile.C</" "filename>, they will be stored correctly in the repository. And in the " "working directories of other Linux users, they will be correctly represented " "as separate files." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch07-filenames.xml:407 msgid "" "If a Windows or Mac user pulls this change, they will not initially have a " "problem, because Mercurial's repository storage mechanism is case safe. " "However, once they try to <command role=\"hg-cmd\">hg update</command> the " "working directory to that changeset, or <command role=\"hg-cmd\">hg merge</" "command> with that changeset, Mercurial will spot the conflict between the " "two file names that the filesystem would treat as the same, and forbid the " "update or merge from occurring." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch07-filenames.xml:419 msgid "Fixing a case conflict" msgstr "修正大小写冲突" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch07-filenames.xml:421 msgid "" "If you are using Windows or a Mac in a mixed environment where some of your " "collaborators are using Linux or Unix, and Mercurial reports a case folding " "conflict when you try to <command role=\"hg-cmd\">hg update</command> or " "<command role=\"hg-cmd\">hg merge</command>, the procedure to fix the problem " "is simple." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch07-filenames.xml:428 msgid "" "Just find a nearby Linux or Unix box, clone the problem repository onto it, " "and use Mercurial's <command role=\"hg-cmd\">hg rename</command> command to " "change the names of any offending files or directories so that they will no " "longer cause case folding conflicts. Commit this change, <command role=\"hg-" "cmd\">hg pull</command> or <command role=\"hg-cmd\">hg push</command> it " "across to your Windows or MacOS system, and <command role=\"hg-cmd\">hg " "update</command> to the revision with the non-conflicting names." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch07-filenames.xml:438 msgid "" "The changeset with case-conflicting names will remain in your project's " "history, and you still won't be able to <command role=\"hg-cmd\">hg update</" "command> your working directory to that changeset on a Windows or MacOS " "system, but you can continue development unimpeded." msgstr "" #. type: Content of: <book><chapter><title> #: ../en/ch08-branch.xml:5 msgid "Managing releases and branchy development" msgstr "发布管理与分支开发" #. type: Content of: <book><chapter><para> #: ../en/ch08-branch.xml:7 msgid "" "Mercurial provides several mechanisms for you to manage a project that is " "making progress on multiple fronts at once. To understand these mechanisms, " "let's first take a brief look at a fairly normal software project structure." msgstr "" #. type: Content of: <book><chapter><para> #: ../en/ch08-branch.xml:12 msgid "" "Many software projects issue periodic <quote>major</quote> releases that " "contain substantial new features. In parallel, they may issue <quote>minor</" "quote> releases. These are usually identical to the major releases off which " "they're based, but with a few bugs fixed." msgstr "" #. type: Content of: <book><chapter><para> #: ../en/ch08-branch.xml:18 msgid "" "In this chapter, we'll start by talking about how to keep records of project " "milestones such as releases. We'll then continue on to talk about the flow " "of work between different phases of a project, and how Mercurial can help you " "to isolate and manage this work." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch08-branch.xml:25 msgid "Giving a persistent name to a revision" msgstr "给版本指定一个永久的名称" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:27 msgid "" "Once you decide that you'd like to call a particular revision a " "<quote>release</quote>, it's a good idea to record the identity of that " "revision. This will let you reproduce that release at a later date, for " "whatever purpose you might need at the time (reproducing a bug, porting to a " "new platform, etc). &interaction.tag.init;" msgstr "" # #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:34 msgid "" "Mercurial lets you give a permanent name to any revision using the <command " "role=\"hg-cmd\">hg tag</command> command. Not surprisingly, these names are " "called <quote>tags</quote>." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:40 msgid "" "A tag is nothing more than a <quote>symbolic name</quote> for a revision. " "Tags exist purely for your convenience, so that you have a handy permanent " "way to refer to a revision; Mercurial doesn't interpret the tag names you use " "in any way. Neither does Mercurial place any restrictions on the name of a " "tag, beyond a few that are necessary to ensure that a tag can be parsed " "unambiguously. A tag name cannot contain any of the following characters:" msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch08-branch.xml:49 msgid "Colon (ASCII 58, <quote><literal>:</literal></quote>)" msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch08-branch.xml:52 msgid "Carriage return (ASCII 13, <quote><literal>\\r</literal></quote>)" msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch08-branch.xml:55 msgid "Newline (ASCII 10, <quote><literal>\\n</literal></quote>)" msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:59 msgid "" "You can use the <command role=\"hg-cmd\">hg tags</command> command to display " "the tags present in your repository. In the output, each tagged revision is " "identified first by its name, then by revision number, and finally by the " "unique hash of the revision." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:67 msgid "" "Notice that <literal>tip</literal> is listed in the output of <command role=" "\"hg-cmd\">hg tags</command>. The <literal>tip</literal> tag is a special " "<quote>floating</quote> tag, which always identifies the newest revision in " "the repository." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:73 msgid "" "In the output of the <command role=\"hg-cmd\">hg tags</command> command, tags " "are listed in reverse order, by revision number. This usually means that " "recent tags are listed before older tags. It also means that <literal>tip</" "literal> is always going to be the first tag listed in the output of <command " "role=\"hg-cmd\">hg tags</command>." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:80 msgid "" "When you run <command role=\"hg-cmd\">hg log</command>, if it displays a " "revision that has tags associated with it, it will print those tags." msgstr "" # #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:86 msgid "" "Any time you need to provide a revision ID to a Mercurial command, the " "command will accept a tag name in its place. Internally, Mercurial will " "translate your tag name into the corresponding revision ID, then use that." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:93 msgid "" "There's no limit on the number of tags you can have in a repository, or on " "the number of tags that a single revision can have. As a practical matter, " "it's not a great idea to have <quote>too many</quote> (a number which will " "vary from project to project), simply because tags are supposed to help you " "to find revisions. If you have lots of tags, the ease of using them to " "identify revisions diminishes rapidly." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:101 msgid "" "For example, if your project has milestones as frequent as every few days, " "it's perfectly reasonable to tag each one of those. But if you have a " "continuous build system that makes sure every revision can be built cleanly, " "you'd be introducing a lot of noise if you were to tag every clean build. " "Instead, you could tag failed builds (on the assumption that they're rare!), " "or simply not use tags to track buildability." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:109 msgid "" "If you want to remove a tag that you no longer want, use <command role=\"hg-" "cmd\">hg tag --remove</command>." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:114 msgid "" "You can also modify a tag at any time, so that it identifies a different " "revision, by simply issuing a new <command role=\"hg-cmd\">hg tag</command> " "command. You'll have to use the <option role=\"hg-opt-tag\">-f</option> " "option to tell Mercurial that you <emphasis>really</emphasis> want to update " "the tag." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:123 msgid "" "There will still be a permanent record of the previous identity of the tag, " "but Mercurial will no longer use it. There's thus no penalty to tagging the " "wrong revision; all you have to do is turn around and tag the correct " "revision once you discover your error." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:129 msgid "" "Mercurial stores tags in a normal revision-controlled file in your " "repository. If you've created any tags, you'll find them in a file in the " "root of your repository named <filename role=\"special\">.hgtags</filename>. " "When you run the <command role=\"hg-cmd\">hg tag</command> command, Mercurial " "modifies this file, then automatically commits the change to it. This means " "that every time you run <command role=\"hg-cmd\">hg tag</command>, you'll see " "a corresponding changeset in the output of <command role=\"hg-cmd\">hg log</" "command>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch08-branch.xml:142 msgid "Handling tag conflicts during a merge" msgstr "在合并期间处理标签冲突" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch08-branch.xml:144 msgid "" "You won't often need to care about the <filename role=\"special\">.hgtags</" "filename> file, but it sometimes makes its presence known during a merge. " "The format of the file is simple: it consists of a series of lines. Each " "line starts with a changeset hash, followed by a space, followed by the name " "of a tag." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch08-branch.xml:151 msgid "" "If you're resolving a conflict in the <filename role=\"special\">.hgtags</" "filename> file during a merge, there's one twist to modifying the <filename " "role=\"special\">.hgtags</filename> file: when Mercurial is parsing the tags " "in a repository, it <emphasis>never</emphasis> reads the working copy of the " "<filename role=\"special\">.hgtags</filename> file. Instead, it reads the " "<emphasis>most recently committed</emphasis> revision of the file." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch08-branch.xml:161 msgid "" "An unfortunate consequence of this design is that you can't actually verify " "that your merged <filename role=\"special\">.hgtags</filename> file is " "correct until <emphasis>after</emphasis> you've committed a change. So if " "you find yourself resolving a conflict on <filename role=\"special\">.hgtags</" "filename> during a merge, be sure to run <command role=\"hg-cmd\">hg tags</" "command> after you commit. If it finds an error in the <filename role=" "\"special\">.hgtags</filename> file, it will report the location of the " "error, which you can then fix and commit. You should then run <command role=" "\"hg-cmd\">hg tags</command> again, just to be sure that your fix is correct." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch08-branch.xml:176 msgid "Tags and cloning" msgstr "标签与克隆" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch08-branch.xml:178 msgid "" "You may have noticed that the <command role=\"hg-cmd\">hg clone</command> " "command has a <option role=\"hg-opt-clone\">-r</option> option that lets you " "clone an exact copy of the repository as of a particular changeset. The new " "clone will not contain any project history that comes after the revision you " "specified. This has an interaction with tags that can surprise the unwary." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch08-branch.xml:186 msgid "" "Recall that a tag is stored as a revision to the <filename role=\"special\">." "hgtags</filename> file. When you create a tag, the changeset in which its " "recorded refers to an older changeset. When you run <command role=\"hg-cmd" "\">hg clone -r foo</command> to clone a repository as of tag <literal>foo</" "literal>, the new clone <emphasis>will not contain any revision newer than " "the one the tag refers to, including the revision where the tag was created</" "emphasis>. The result is that you'll get exactly the right subset of the " "project's history in the new repository, but <emphasis>not</emphasis> the tag " "you might have expected." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch08-branch.xml:201 msgid "When permanent tags are too much" msgstr "当永久标签太多的时候" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch08-branch.xml:203 msgid "" "Since Mercurial's tags are revision controlled and carried around with a " "project's history, everyone you work with will see the tags you create. But " "giving names to revisions has uses beyond simply noting that revision " "<literal>4237e45506ee</literal> is really <literal>v2.0.2</literal>. If " "you're trying to track down a subtle bug, you might want a tag to remind you " "of something like <quote>Anne saw the symptoms with this revision</quote>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch08-branch.xml:213 msgid "" "For cases like this, what you might want to use are <emphasis>local</" "emphasis> tags. You can create a local tag with the <option role=\"hg-opt-tag" "\">-l</option> option to the <command role=\"hg-cmd\">hg tag</command> " "command. This will store the tag in a file called <filename role=\"special" "\">.hg/localtags</filename>. Unlike <filename role=\"special\">.hgtags</" "filename>, <filename role=\"special\">.hg/localtags</filename> is not " "revision controlled. Any tags you create using <option role=\"hg-opt-tag\">-" "l</option> remain strictly local to the repository you're currently working " "in." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch08-branch.xml:228 msgid "The flow of changes&emdash;big picture vs. little" msgstr "修改流程—宏观与微观" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:230 msgid "" "To return to the outline I sketched at the beginning of the chapter, let's " "think about a project that has multiple concurrent pieces of work under " "development at once." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:235 msgid "" "There might be a push for a new <quote>main</quote> release; a new minor " "bugfix release to the last main release; and an unexpected <quote>hot fix</" "quote> to an old release that is now in maintenance mode." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:240 msgid "" "The usual way people refer to these different concurrent directions of " "development is as <quote>branches</quote>. However, we've already seen " "numerous times that Mercurial treats <emphasis>all of history</emphasis> as a " "series of branches and merges. Really, what we have here is two ideas that " "are peripherally related, but which happen to share a name." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch08-branch.xml:247 msgid "" "<quote>Big picture</quote> branches represent the sweep of a project's " "evolution; people give them names, and talk about them in conversation." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch08-branch.xml:251 msgid "" "<quote>Little picture</quote> branches are artefacts of the day-to-day " "activity of developing and merging changes. They expose the narrative of how " "the code was developed." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch08-branch.xml:259 msgid "Managing big-picture branches in repositories" msgstr "在版本库中管理分支" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:261 msgid "" "The easiest way to isolate a <quote>big picture</quote> branch in Mercurial " "is in a dedicated repository. If you have an existing shared " "repository&emdash;let's call it <literal>myproject</literal>&emdash;that " "reaches a <quote>1.0</quote> milestone, you can start to prepare for future " "maintenance releases on top of version 1.0 by tagging the revision from which " "you prepared the 1.0 release." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:271 msgid "" "You can then clone a new shared <literal>myproject-1.0.1</literal> repository " "as of that tag." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:277 msgid "" "Afterwards, if someone needs to work on a bug fix that ought to go into an " "upcoming 1.0.1 minor release, they clone the <literal>myproject-1.0.1</" "literal> repository, make their changes, and push them back." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:284 msgid "" "Meanwhile, development for the next major release can continue, isolated and " "unabated, in the <literal>myproject</literal> repository." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch08-branch.xml:292 msgid "Don't repeat yourself: merging across branches" msgstr "不要重复劳动:在分支间合并" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:294 msgid "" "In many cases, if you have a bug to fix on a maintenance branch, the chances " "are good that the bug exists on your project's main branch (and possibly " "other maintenance branches, too). It's a rare developer who wants to fix the " "same bug multiple times, so let's look at a few ways that Mercurial can help " "you to manage these bugfixes without duplicating your work." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:302 msgid "" "In the simplest instance, all you need to do is pull changes from your " "maintenance branch into your local clone of the target branch." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:308 msgid "" "You'll then need to merge the heads of the two branches, and push back to the " "main branch." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch08-branch.xml:315 msgid "Naming branches within one repository" msgstr "版本库中的命名分支" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:317 msgid "" "In most instances, isolating branches in repositories is the right approach. " "Its simplicity makes it easy to understand; and so it's hard to make " "mistakes. There's a one-to-one relationship between branches you're working " "in and directories on your system. This lets you use normal (non-Mercurial-" "aware) tools to work on files within a branch/repository." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:324 msgid "" "If you're more in the <quote>power user</quote> category (<emphasis>and</" "emphasis> your collaborators are too), there is an alternative way of " "handling branches that you can consider. I've already mentioned the human-" "level distinction between <quote>small picture</quote> and <quote>big " "picture</quote> branches. While Mercurial works with multiple <quote>small " "picture</quote> branches in a repository all the time (for example after you " "pull changes in, but before you merge them), it can <emphasis>also</emphasis> " "work with multiple <quote>big picture</quote> branches." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:335 msgid "" "The key to working this way is that Mercurial lets you assign a persistent " "<emphasis>name</emphasis> to a branch. There always exists a branch named " "<literal>default</literal>. Even before you start naming branches yourself, " "you can find traces of the <literal>default</literal> branch if you look for " "them." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:342 msgid "" "As an example, when you run the <command role=\"hg-cmd\">hg commit</command> " "command, and it pops up your editor so that you can enter a commit message, " "look for a line that contains the text <quote><literal>HG: branch default</" "literal></quote> at the bottom. This is telling you that your commit will " "occur on the branch named <literal>default</literal>." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:349 msgid "" "To start working with named branches, use the <command role=\"hg-cmd\">hg " "branches</command> command. This command lists the named branches already " "present in your repository, telling you which changeset is the tip of each." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:356 msgid "" "Since you haven't created any named branches yet, the only one that exists is " "<literal>default</literal>." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:359 msgid "" "To find out what the <quote>current</quote> branch is, run the <command role=" "\"hg-cmd\">hg branch</command> command, giving it no arguments. This tells " "you what branch the parent of the current changeset is on." msgstr "" # #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:366 msgid "" "To create a new branch, run the <command role=\"hg-cmd\">hg branch</command> " "command again. This time, give it one argument: the name of the branch you " "want to create." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:372 msgid "" "After you've created a branch, you might wonder what effect the <command role=" "\"hg-cmd\">hg branch</command> command has had. What do the <command role=" "\"hg-cmd\">hg status</command> and <command role=\"hg-cmd\">hg tip</command> " "commands report?" msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:379 msgid "" "Nothing has changed in the working directory, and there's been no new history " "created. As this suggests, running the <command role=\"hg-cmd\">hg branch</" "command> command has no permanent effect; it only tells Mercurial what branch " "name to use the <emphasis>next</emphasis> time you commit a changeset." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:386 msgid "" "When you commit a change, Mercurial records the name of the branch on which " "you committed. Once you've switched from the <literal>default</literal> " "branch to another and committed, you'll see the name of the new branch show " "up in the output of <command role=\"hg-cmd\">hg log</command>, <command role=" "\"hg-cmd\">hg tip</command>, and other commands that display the same kind of " "output." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:396 msgid "" "The <command role=\"hg-cmd\">hg log</command>-like commands will print the " "branch name of every changeset that's not on the <literal>default</literal> " "branch. As a result, if you never use named branches, you'll never see this " "information." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:401 msgid "" "Once you've named a branch and committed a change with that name, every " "subsequent commit that descends from that change will inherit the same branch " "name. You can change the name of a branch at any time, using the <command " "role=\"hg-cmd\">hg branch</command> command." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:409 msgid "" "In practice, this is something you won't do very often, as branch names tend " "to have fairly long lifetimes. (This isn't a rule, just an observation.)" msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch08-branch.xml:415 msgid "Dealing with multiple named branches in a repository" msgstr "在版本库中处理多个命名分支" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:418 msgid "" "If you have more than one named branch in a repository, Mercurial will " "remember the branch that your working directory is on when you start a " "command like <command role=\"hg-cmd\">hg update</command> or <command role=" "\"hg-cmd\">hg pull -u</command>. It will update the working directory to the " "tip of this branch, no matter what the <quote>repo-wide</quote> tip is. To " "update to a revision that's on a different named branch, you may need to use " "the <option role=\"hg-opt-update\">-C</option> option to <command role=\"hg-" "cmd\">hg update</command>." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:428 msgid "" "This behavior is a little subtle, so let's see it in action. First, let's " "remind ourselves what branch we're currently on, and what branches are in our " "repository." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:434 msgid "" "We're on the <literal>bar</literal> branch, but there also exists an older " "<command role=\"hg-cmd\">hg foo</command> branch." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:438 msgid "" "We can <command role=\"hg-cmd\">hg update</command> back and forth between " "the tips of the <literal>foo</literal> and <literal>bar</literal> branches " "without needing to use the <option role=\"hg-opt-update\">-C</option> option, " "because this only involves going backwards and forwards linearly through our " "change history." msgstr "" # #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:447 msgid "" "If we go back to the <literal>foo</literal> branch and then run <command role=" "\"hg-cmd\">hg update</command>, it will keep us on <literal>foo</literal>, " "not move us to the tip of <literal>bar</literal>." msgstr "" # #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:454 msgid "" "Committing a new change on the <literal>foo</literal> branch introduces a new " "head." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch08-branch.xml:461 msgid "Branch names and merging" msgstr "分支名称与合并" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:463 msgid "" "As you've probably noticed, merges in Mercurial are not symmetrical. Let's " "say our repository has two heads, 17 and 23. If I <command role=\"hg-cmd" "\">hg update</command> to 17 and then <command role=\"hg-cmd\">hg merge</" "command> with 23, Mercurial records 17 as the first parent of the merge, and " "23 as the second. Whereas if I <command role=\"hg-cmd\">hg update</command> " "to 23 and then <command role=\"hg-cmd\">hg merge</command> with 17, it " "records 23 as the first parent, and 17 as the second." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:473 msgid "" "This affects Mercurial's choice of branch name when you merge. After a " "merge, Mercurial will retain the branch name of the first parent when you " "commit the result of the merge. If your first parent's branch name is " "<literal>foo</literal>, and you merge with <literal>bar</literal>, the branch " "name will still be <literal>foo</literal> after you merge." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:480 msgid "" "It's not unusual for a repository to contain multiple heads, each with the " "same branch name. Let's say I'm working on the <literal>foo</literal> " "branch, and so are you. We commit different changes; I pull your changes; I " "now have two heads, each claiming to be on the <literal>foo</literal> " "branch. The result of a merge will be a single head on the <literal>foo</" "literal> branch, as you might hope." msgstr "" # #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:488 msgid "" "But if I'm working on the <literal>bar</literal> branch, and I merge work " "from the <literal>foo</literal> branch, the result will remain on the " "<literal>bar</literal> branch." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:494 msgid "" "To give a more concrete example, if I'm working on the <literal>bleeding-" "edge</literal> branch, and I want to bring in the latest fixes from the " "<literal>stable</literal> branch, Mercurial will choose the <quote>right</" "quote> (<literal>bleeding-edge</literal>) branch name when I pull and merge " "from <literal>stable</literal>." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch08-branch.xml:503 msgid "Branch naming is generally useful" msgstr "分支名称通常都很有用" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:505 msgid "" "You shouldn't think of named branches as applicable only to situations where " "you have multiple long-lived branches cohabiting in a single repository. " "They're very useful even in the one-branch-per-repository case." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:510 msgid "" "In the simplest case, giving a name to each branch gives you a permanent " "record of which branch a changeset originated on. This gives you more " "context when you're trying to follow the history of a long-lived branchy " "project." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch08-branch.xml:515 msgid "" "If you're working with shared repositories, you can set up a <literal role=" "\"hook\">pretxnchangegroup</literal> hook on each that will block incoming " "changes that have the <quote>wrong</quote> branch name. This provides a " "simple, but effective, defence against people accidentally pushing changes " "from a <quote>bleeding edge</quote> branch to a <quote>stable</quote> " "branch. Such a hook might look like this inside the shared repo's <filename " "role=\"special\"> /.hgrc</filename>." msgstr "" #. type: Content of: <book><chapter><title> #: ../en/ch09-undo.xml:5 msgid "Finding and fixing mistakes" msgstr "查找和修改错误" #. type: Content of: <book><chapter><para> #: ../en/ch09-undo.xml:7 msgid "" "To err might be human, but to really handle the consequences well takes a top-" "notch revision control system. In this chapter, we'll discuss some of the " "techniques you can use when you find that a problem has crept into your " "project. Mercurial has some highly capable features that will help you to " "isolate the sources of problems, and to handle them appropriately." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch09-undo.xml:15 msgid "Erasing local history" msgstr "销毁本地历史" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch09-undo.xml:18 msgid "The accidental commit" msgstr "意外的提交" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:20 msgid "" "I have the occasional but persistent problem of typing rather more quickly " "than I can think, which sometimes results in me committing a changeset that " "is either incomplete or plain wrong. In my case, the usual kind of " "incomplete changeset is one in which I've created a new source file, but " "forgotten to <command role=\"hg-cmd\">hg add</command> it. A <quote>plain " "wrong</quote> changeset is not as common, but no less annoying." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch09-undo.xml:31 msgid "Rolling back a transaction" msgstr "回滚一个事务" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:33 msgid "" "In <xref linkend=\"sec:concepts:txn\"/>, I mentioned that Mercurial treats " "each modification of a repository as a <emphasis>transaction</emphasis>. " "Every time you commit a changeset or pull changes from another repository, " "Mercurial remembers what you did. You can undo, or <emphasis>roll back</" "emphasis>, exactly one of these actions using the <command role=\"hg-cmd\">hg " "rollback</command> command. (See <xref linkend=\"sec:undo:rollback-after-push" "\"/> for an important caveat about the use of this command.)" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:43 msgid "" "Here's a mistake that I often find myself making: committing a change in " "which I've created a new file, but forgotten to <command role=\"hg-cmd\">hg " "add</command> it." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:50 msgid "" "Looking at the output of <command role=\"hg-cmd\">hg status</command> after " "the commit immediately confirms the error." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:56 msgid "" "The commit captured the changes to the file <filename>a</filename>, but not " "the new file <filename>b</filename>. If I were to push this changeset to a " "repository that I shared with a colleague, the chances are high that " "something in <filename>a</filename> would refer to <filename>b</filename>, " "which would not be present in their repository when they pulled my changes. " "I would thus become the object of some indignation." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:65 msgid "" "However, luck is with me&emdash;I've caught my error before I pushed the " "changeset. I use the <command role=\"hg-cmd\">hg rollback</command> command, " "and Mercurial makes that last changeset vanish." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:72 msgid "" "Notice that the changeset is no longer present in the repository's history, " "and the working directory once again thinks that the file <filename>a</" "filename> is modified. The commit and rollback have left the working " "directory exactly as it was prior to the commit; the changeset has been " "completely erased. I can now safely <command role=\"hg-cmd\">hg add</" "command> the file <filename>b</filename>, and rerun my commit." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch09-undo.xml:85 msgid "The erroneous pull" msgstr "错误的抓取" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:87 msgid "" "It's common practice with Mercurial to maintain separate development branches " "of a project in different repositories. Your development team might have one " "shared repository for your project's <quote>0.9</quote> release, and another, " "containing different changes, for the <quote>1.0</quote> release." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:94 msgid "" "Given this, you can imagine that the consequences could be messy if you had a " "local <quote>0.9</quote> repository, and accidentally pulled changes from the " "shared <quote>1.0</quote> repository into it. At worst, you could be paying " "insufficient attention, and push those changes into the shared <quote>0.9</" "quote> tree, confusing your entire team (but don't worry, we'll return to " "this horror scenario later). However, it's more likely that you'll notice " "immediately, because Mercurial will display the URL it's pulling from, or you " "will see it pull a suspiciously large number of changes into the repository." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:106 msgid "" "The <command role=\"hg-cmd\">hg rollback</command> command will work nicely " "to expunge all of the changesets that you just pulled. Mercurial groups all " "changes from one <command role=\"hg-cmd\">hg pull</command> into a single " "transaction, so one <command role=\"hg-cmd\">hg rollback</command> is all you " "need to undo this mistake." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch09-undo.xml:115 msgid "Rolling back is useless once you've pushed" msgstr "当完成推送后,回滚是无效的" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:117 msgid "" "The value of the <command role=\"hg-cmd\">hg rollback</command> command drops " "to zero once you've pushed your changes to another repository. Rolling back " "a change makes it disappear entirely, but <emphasis>only</emphasis> in the " "repository in which you perform the <command role=\"hg-cmd\">hg rollback</" "command>. Because a rollback eliminates history, there's no way for the " "disappearance of a change to propagate between repositories." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:126 msgid "" "If you've pushed a change to another repository&emdash;particularly if it's a " "shared repository&emdash;it has essentially <quote>escaped into the wild,</" "quote> and you'll have to recover from your mistake in a different way. If " "you push a changeset somewhere, then roll it back, then pull from the " "repository you pushed to, the changeset you thought you'd gotten rid of will " "simply reappear in your repository." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:135 msgid "" "(If you absolutely know for sure that the change you want to roll back is the " "most recent change in the repository that you pushed to, <emphasis>and</" "emphasis> you know that nobody else could have pulled it from that " "repository, you can roll back the changeset there, too, but you really should " "not expect this to work reliably. Sooner or later a change really will make " "it into a repository that you don't directly control (or have forgotten " "about), and come back to bite you.)" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch09-undo.xml:147 msgid "You can only roll back once" msgstr "你只能回滚一次" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:149 msgid "" "Mercurial stores exactly one transaction in its transaction log; that " "transaction is the most recent one that occurred in the repository. This " "means that you can only roll back one transaction. If you expect to be able " "to roll back one transaction, then its predecessor, this is not the behavior " "you will get." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:158 msgid "" "Once you've rolled back one transaction in a repository, you can't roll back " "again in that repository until you perform another commit or pull." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch09-undo.xml:165 msgid "Reverting the mistaken change" msgstr "撤销错误的修改" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch09-undo.xml:167 msgid "" "If you make a modification to a file, and decide that you really didn't want " "to change the file at all, and you haven't yet committed your changes, the " "<command role=\"hg-cmd\">hg revert</command> command is the one you'll need. " "It looks at the changeset that's the parent of the working directory, and " "restores the contents of the file to their state as of that changeset. " "(That's a long-winded way of saying that, in the normal case, it undoes your " "modifications.)" msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch09-undo.xml:176 msgid "" "Let's illustrate how the <command role=\"hg-cmd\">hg revert</command> command " "works with yet another small example. We'll begin by modifying a file that " "Mercurial is already tracking." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch09-undo.xml:183 msgid "" "If we don't want that change, we can simply <command role=\"hg-cmd\">hg " "revert</command> the file." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch09-undo.xml:189 msgid "" "The <command role=\"hg-cmd\">hg revert</command> command provides us with an " "extra degree of safety by saving our modified file with a <filename>.orig</" "filename> extension." msgstr "" #. type: Content of: <book><chapter><sect1><tip><title> #: ../en/ch09-undo.xml:197 msgid "Be careful with <filename>.orig</filename> files" msgstr "小心 <filename>.orig</filename> 文件" #. type: Content of: <book><chapter><sect1><tip><para> #: ../en/ch09-undo.xml:199 msgid "" "It's extremely unlikely that you are either using Mercurial to manage files " "with <filename>.orig</filename> extensions or that you even care about the " "contents of such files. Just in case, though, it's useful to remember that " "<command role=\"hg-cmd\">hg revert</command> will unconditionally overwrite " "an existing file with a <filename>.orig</filename> extension. For instance, " "if you already have a file named <filename>foo.orig</filename> when you " "revert <filename>foo</filename>, the contents of <filename>foo.orig</" "filename> will be clobbered." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch09-undo.xml:211 msgid "" "Here is a summary of the cases that the <command role=\"hg-cmd\">hg revert</" "command> command can deal with. We will describe each of these in more " "detail in the section that follows." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch09-undo.xml:216 msgid "If you modify a file, it will restore the file to its unmodified state." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch09-undo.xml:219 msgid "" "If you <command role=\"hg-cmd\">hg add</command> a file, it will undo the " "<quote>added</quote> state of the file, but leave the file itself untouched." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch09-undo.xml:223 msgid "" "If you delete a file without telling Mercurial, it will restore the file to " "its unmodified contents." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch09-undo.xml:226 msgid "" "If you use the <command role=\"hg-cmd\">hg remove</command> command to remove " "a file, it will undo the <quote>removed</quote> state of the file, and " "restore the file to its unmodified contents." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch09-undo.xml:233 msgid "File management errors" msgstr "文件管理错误" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:235 msgid "" "The <command role=\"hg-cmd\">hg revert</command> command is useful for more " "than just modified files. It lets you reverse the results of all of " "Mercurial's file management commands&emdash;<command role=\"hg-cmd\">hg add</" "command>, <command role=\"hg-cmd\">hg remove</command>, and so on." msgstr "" # #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:241 msgid "" "If you <command role=\"hg-cmd\">hg add</command> a file, then decide that in " "fact you don't want Mercurial to track it, use <command role=\"hg-cmd\">hg " "revert</command> to undo the add. Don't worry; Mercurial will not modify the " "file in any way. It will just <quote>unmark</quote> the file." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:249 msgid "" "Similarly, if you ask Mercurial to <command role=\"hg-cmd\">hg remove</" "command> a file, you can use <command role=\"hg-cmd\">hg revert</command> to " "restore it to the contents it had as of the parent of the working directory. " "&interaction.daily.revert.remove; This works just as well for a file that you " "deleted by hand, without telling Mercurial (recall that in Mercurial " "terminology, this kind of file is called <quote>missing</quote>)." msgstr "" # #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:260 msgid "" "If you revert a <command role=\"hg-cmd\">hg copy</command>, the copied-to " "file remains in your working directory afterwards, untracked. Since a copy " "doesn't affect the copied-from file in any way, Mercurial doesn't do anything " "with the copied-from file." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch09-undo.xml:271 msgid "Dealing with committed changes" msgstr "处理已经提交的修改" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch09-undo.xml:273 msgid "" "Consider a case where you have committed a change <emphasis>a</emphasis>, and " "another change <emphasis>b</emphasis> on top of it; you then realise that " "change <emphasis>a</emphasis> was incorrect. Mercurial lets you <quote>back " "out</quote> an entire changeset automatically, and building blocks that let " "you reverse part of a changeset by hand." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch09-undo.xml:281 msgid "" "Before you read this section, here's something to keep in mind: the <command " "role=\"hg-cmd\">hg backout</command> command undoes the effect of a change by " "<emphasis>adding</emphasis> to your repository's history, not by modifying or " "erasing it. It's the right tool to use if you're fixing bugs, but not if " "you're trying to undo some change that has catastrophic consequences. To " "deal with those, see <xref linkend=\"sec:undo:aaaiiieee\"/>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch09-undo.xml:291 msgid "Backing out a changeset" msgstr "恢复一个修改集" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:293 msgid "" "The <command role=\"hg-cmd\">hg backout</command> command lets you " "<quote>undo</quote> the effects of an entire changeset in an automated " "fashion. Because Mercurial's history is immutable, this command " "<emphasis>does not</emphasis> get rid of the changeset you want to undo. " "Instead, it creates a new changeset that <emphasis>reverses</emphasis> the " "effect of the to-be-undone changeset." msgstr "" # #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:302 msgid "" "The operation of the <command role=\"hg-cmd\">hg backout</command> command is " "a little intricate, so let's illustrate it with some examples. First, we'll " "create a repository with some simple changes." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:309 msgid "" "The <command role=\"hg-cmd\">hg backout</command> command takes a single " "changeset ID as its argument; this is the changeset to back out. Normally, " "<command role=\"hg-cmd\">hg backout</command> will drop you into a text " "editor to write a commit message, so you can record why you're backing the " "change out. In this example, we provide a commit message on the command line " "using the <option role=\"hg-opt-backout\">-m</option> option." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch09-undo.xml:320 msgid "Backing out the tip changeset" msgstr "恢复顶点修改集" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:322 msgid "We're going to start by backing out the last changeset we committed." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:327 msgid "" "You can see that the second line from <filename>myfile</filename> is no " "longer present. Taking a look at the output of <command role=\"hg-cmd\">hg " "log</command> gives us an idea of what the <command role=\"hg-cmd\">hg " "backout</command> command has done. &interaction.backout.simple.log; Notice " "that the new changeset that <command role=\"hg-cmd\">hg backout</command> has " "created is a child of the changeset we backed out. It's easier to see this " "in <xref linkend=\"fig:undo:backout\"/>, which presents a graphical view of " "the change history. As you can see, the history is nice and linear." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><figure><title> #: ../en/ch09-undo.xml:340 ../en/ch09-undo.xml:460 msgid "" "Backing out a change using the <command role=\"hg-cmd\">hg backout</command> " "command" msgstr "使用 <command role=\"hg-cmd\">hg backout</command> 恢复一个修改" #. type: Content of: <book><chapter><sect1><sect2><figure><mediaobject> #: ../en/ch09-undo.xml:343 msgid "<imageobject><imagedata fileref=\"figs/undo-simple.png\"/></imageobject>" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch09-undo.xml:350 msgid "Backing out a non-tip change" msgstr "恢复非顶点的修改" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:352 msgid "" "If you want to back out a change other than the last one you committed, pass " "the <option role=\"hg-opt-backout\">--merge</option> option to the <command " "role=\"hg-cmd\">hg backout</command> command." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:359 msgid "" "This makes backing out any changeset a <quote>one-shot</quote> operation " "that's usually simple and fast." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:365 msgid "" "If you take a look at the contents of <filename>myfile</filename> after the " "backout finishes, you'll see that the first and third changes are present, " "but not the second." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:372 msgid "" "As the graphical history in <xref linkend=\"fig:undo:backout-non-tip\"/> " "illustrates, Mercurial still commits one change in this kind of situation " "(the box-shaped node is the ones that Mercurial commits automatically), but " "the revision graph now looks different. Before Mercurial begins the backout " "process, it first remembers what the current parent of the working directory " "is. It then backs out the target changeset, and commits that as a " "changeset. Finally, it merges back to the previous parent of the working " "directory, but notice that it <emphasis>does not commit</emphasis> the result " "of the merge. The repository now contains two heads, and the working " "directory is in a merge state." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><figure><title> #: ../en/ch09-undo.xml:387 msgid "" "Automated backout of a non-tip change using the <command role=\"hg-cmd\">hg " "backout</command> command" msgstr "使用 <command role=\"hg-cmd\">hg backout</command> 自动恢复非顶点的修改" #. type: Content of: <book><chapter><sect1><sect2><figure><mediaobject> #: ../en/ch09-undo.xml:390 msgid "" "<imageobject><imagedata fileref=\"figs/undo-non-tip.png\"/></imageobject>" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:395 msgid "" "The result is that you end up <quote>back where you were</quote>, only with " "some extra history that undoes the effect of the changeset you wanted to back " "out." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:399 msgid "" "You might wonder why Mercurial does not commit the result of the merge that " "it performed. The reason lies in Mercurial behaving conservatively: a merge " "naturally has more scope for error than simply undoing the effect of the tip " "changeset, so your work will be safest if you first inspect (and test!) the " "result of the merge, <emphasis>then</emphasis> commit it." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><title> #: ../en/ch09-undo.xml:408 msgid "Always use the <option role=\"hg-opt-backout\">--merge</option> option" msgstr "始终使用选项 <option role=\"hg-opt-backout\">--merge</option>" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch09-undo.xml:411 msgid "" "In fact, since the <option role=\"hg-opt-backout\">--merge</option> option " "will do the <quote>right thing</quote> whether or not the changeset you're " "backing out is the tip (i.e. it won't try to merge if it's backing out the " "tip, since there's no need), you should <emphasis>always</emphasis> use this " "option when you run the <command role=\"hg-cmd\">hg backout</command> command." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch09-undo.xml:422 msgid "Gaining more control of the backout process" msgstr "在恢复处理中获得更多控制" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:424 msgid "" "While I've recommended that you always use the <option role=\"hg-opt-backout" "\">--merge</option> option when backing out a change, the <command role=\"hg-" "cmd\">hg backout</command> command lets you decide how to merge a backout " "changeset. Taking control of the backout process by hand is something you " "will rarely need to do, but it can be useful to understand what the <command " "role=\"hg-cmd\">hg backout</command> command is doing for you automatically. " "To illustrate this, let's clone our first repository, but omit the backout " "change that it contains." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:437 msgid "" "As with our earlier example, We'll commit a third changeset, then back out " "its parent, and see what happens." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:443 msgid "" "Our new changeset is again a descendant of the changeset we backout out; it's " "thus a new head, <emphasis>not</emphasis> a descendant of the changeset that " "was the tip. The <command role=\"hg-cmd\">hg backout</command> command was " "quite explicit in telling us this." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:451 msgid "" "Again, it's easier to see what has happened by looking at a graph of the " "revision history, in <xref linkend=\"fig:undo:backout-manual\"/>. This makes " "it clear that when we use <command role=\"hg-cmd\">hg backout</command> to " "back out a change other than the tip, Mercurial adds a new head to the " "repository (the change it committed is box-shaped)." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><figure><mediaobject> #: ../en/ch09-undo.xml:463 msgid "<imageobject><imagedata fileref=\"figs/undo-manual.png\"/></imageobject>" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:468 msgid "" "After the <command role=\"hg-cmd\">hg backout</command> command has " "completed, it leaves the new <quote>backout</quote> changeset as the parent " "of the working directory." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:475 msgid "Now we have two isolated sets of changes." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:479 msgid "" "Let's think about what we expect to see as the contents of <filename>myfile</" "filename> now. The first change should be present, because we've never " "backed it out. The second change should be missing, as that's the change we " "backed out. Since the history graph shows the third change as a separate " "head, we <emphasis>don't</emphasis> expect to see the third change present in " "<filename>myfile</filename>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:489 msgid "" "To get the third change back into the file, we just do a normal merge of our " "two heads." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:494 msgid "" "Afterwards, the graphical history of our repository looks like <xref linkend=" "\"fig:undo:backout-manual-merge\"/>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><figure><title> #: ../en/ch09-undo.xml:499 msgid "Manually merging a backout change" msgstr "手工合并恢复修改" #. type: Content of: <book><chapter><sect1><sect2><figure><mediaobject> #: ../en/ch09-undo.xml:501 msgid "" "<imageobject><imagedata fileref=\"figs/undo-manual-merge.png\"/></imageobject>" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch09-undo.xml:508 msgid "Why <command role=\"hg-cmd\">hg backout</command> works as it does" msgstr "<command role=\"hg-cmd\">hg backout</command> 的内幕" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:511 msgid "" "Here's a brief description of how the <command role=\"hg-cmd\">hg backout</" "command> command works." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> #: ../en/ch09-undo.xml:514 msgid "" "It ensures that the working directory is <quote>clean</quote>, i.e. that the " "output of <command role=\"hg-cmd\">hg status</command> would be empty." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> #: ../en/ch09-undo.xml:518 msgid "" "It remembers the current parent of the working directory. Let's call this " "changeset <literal>orig</literal>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> #: ../en/ch09-undo.xml:522 msgid "" "It does the equivalent of a <command role=\"hg-cmd\">hg update</command> to " "sync the working directory to the changeset you want to back out. Let's call " "this changeset <literal>backout</literal>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> #: ../en/ch09-undo.xml:527 msgid "" "It finds the parent of that changeset. Let's call that changeset " "<literal>parent</literal>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> #: ../en/ch09-undo.xml:530 msgid "" "For each file that the <literal>backout</literal> changeset affected, it does " "the equivalent of a <command role=\"hg-cmd\">hg revert -r parent</command> on " "that file, to restore it to the contents it had before that changeset was " "committed." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> #: ../en/ch09-undo.xml:537 msgid "" "It commits the result as a new changeset. This changeset has " "<literal>backout</literal> as its parent." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> #: ../en/ch09-undo.xml:541 msgid "" "If you specify <option role=\"hg-opt-backout\">--merge</option> on the " "command line, it merges with <literal>orig</literal>, and commits the result " "of the merge." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:547 msgid "" "An alternative way to implement the <command role=\"hg-cmd\">hg backout</" "command> command would be to <command role=\"hg-cmd\">hg export</command> the " "to-be-backed-out changeset as a diff, then use the <option role=\"cmd-opt-" "patch\">--reverse</option> option to the <command>patch</command> command to " "reverse the effect of the change without fiddling with the working " "directory. This sounds much simpler, but it would not work nearly as well." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:557 msgid "" "The reason that <command role=\"hg-cmd\">hg backout</command> does an update, " "a commit, a merge, and another commit is to give the merge machinery the best " "chance to do a good job when dealing with all the changes <emphasis>between</" "emphasis> the change you're backing out and the current tip." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:564 msgid "" "If you're backing out a changeset that's 100 revisions back in your project's " "history, the chances that the <command>patch</command> command will be able " "to apply a reverse diff cleanly are not good, because intervening changes are " "likely to have <quote>broken the context</quote> that <command>patch</" "command> uses to determine whether it can apply a patch (if this sounds like " "gibberish, see <xref linkend=\"sec:mq:patch\"/> for a discussion of the " "<command>patch</command> command). Also, Mercurial's merge machinery will " "handle files and directories being renamed, permission changes, and " "modifications to binary files, none of which <command>patch</command> can " "deal with." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch09-undo.xml:581 msgid "Changes that should never have been" msgstr "不该发生的修改" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch09-undo.xml:583 msgid "" "Most of the time, the <command role=\"hg-cmd\">hg backout</command> command " "is exactly what you need if you want to undo the effects of a change. It " "leaves a permanent record of exactly what you did, both when committing the " "original changeset and when you cleaned up after it." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch09-undo.xml:589 msgid "" "On rare occasions, though, you may find that you've committed a change that " "really should not be present in the repository at all. For example, it would " "be very unusual, and usually considered a mistake, to commit a software " "project's object files as well as its source files. Object files have almost " "no intrinsic value, and they're <emphasis>big</emphasis>, so they increase " "the size of the repository and the amount of time it takes to clone or pull " "changes." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch09-undo.xml:598 msgid "" "Before I discuss the options that you have if you commit a <quote>brown paper " "bag</quote> change (the kind that's so bad that you want to pull a brown " "paper bag over your head), let me first discuss some approaches that probably " "won't work." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch09-undo.xml:603 msgid "" "Since Mercurial treats history as accumulative&emdash;every change builds on " "top of all changes that preceded it&emdash;you generally can't just make " "disastrous changes disappear. The one exception is when you've just " "committed a change, and it hasn't been pushed or pulled into another " "repository. That's when you can safely use the <command role=\"hg-cmd\">hg " "rollback</command> command, as I detailed in <xref linkend=\"sec:undo:rollback" "\"/>." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch09-undo.xml:612 msgid "" "After you've pushed a bad change to another repository, you <emphasis>could</" "emphasis> still use <command role=\"hg-cmd\">hg rollback</command> to make " "your local copy of the change disappear, but it won't have the consequences " "you want. The change will still be present in the remote repository, so it " "will reappear in your local repository the next time you pull." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch09-undo.xml:620 msgid "" "If a situation like this arises, and you know which repositories your bad " "change has propagated into, you can <emphasis>try</emphasis> to get rid of " "the change from <emphasis>every</emphasis> one of those repositories. This " "is, of course, not a satisfactory solution: if you miss even a single " "repository while you're expunging, the change is still <quote>in the wild</" "quote>, and could propagate further." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch09-undo.xml:628 msgid "" "If you've committed one or more changes <emphasis>after</emphasis> the change " "that you'd like to see disappear, your options are further reduced. Mercurial " "doesn't provide a way to <quote>punch a hole</quote> in history, leaving " "changesets intact." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch09-undo.xml:635 msgid "Backing out a merge" msgstr "撤销一个合并" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:637 msgid "" "Since merges are often complicated, it is not unheard of for a merge to be " "mangled badly, but committed erroneously. Mercurial provides an important " "safeguard against bad merges by refusing to commit unresolved files, but " "human ingenuity guarantees that it is still possible to mess a merge up and " "commit it." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:644 msgid "" "Given a bad merge that has been committed, usually the best way to approach " "it is to simply try to repair the damage by hand. A complete disaster that " "cannot be easily fixed up by hand ought to be very rare, but the <command " "role=\"hg-cmd\">hg backout</command> command may help in making the cleanup " "easier. It offers a <option role=\"hg-opt-backout\">--parent</option> option, " "which lets you specify which parent to revert to when backing out a merge." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><figure><title> #: ../en/ch09-undo.xml:655 msgid "A bad merge" msgstr "错误的合并" #. type: Content of: <book><chapter><sect1><sect2><figure><mediaobject> #: ../en/ch09-undo.xml:657 msgid "<imageobject><imagedata fileref=\"figs/bad-merge-1.png\"/></imageobject>" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:662 msgid "" "Suppose we have a revision graph like that in <xref linkend=\"fig:undo:bad-" "merge-1\"/>. What we'd like is to <emphasis>redo</emphasis> the merge of " "revisions 2 and 3." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:667 msgid "One way to do so would be as follows." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> #: ../en/ch09-undo.xml:671 msgid "" "Call <command role=\"hg-cmd\">hg backout --rev=4 --parent=2</command>. This " "tells <command role=\"hg-cmd\">hg backout</command> to back out revision 4, " "which is the bad merge, and to when deciding which revision to prefer, to " "choose parent 2, one of the parents of the merge. The effect can be seen in " "<xref linkend=\"fig:undo:bad-merge-2\"/>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><figure><title> #: ../en/ch09-undo.xml:679 msgid "Backing out the merge, favoring one parent" msgstr "拆除合并,关注一个父亲" #. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><figure><mediaobject> #: ../en/ch09-undo.xml:681 msgid "<imageobject><imagedata fileref=\"figs/bad-merge-2.png\"/></imageobject>" msgstr "" "<imageobject><imagedata fileref=\"figs/bad-merge-2.png\"/></imageobject>" #. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> #: ../en/ch09-undo.xml:688 msgid "" "Call <command role=\"hg-cmd\">hg backout --rev=4 --parent=3</command>. This " "tells <command role=\"hg-cmd\">hg backout</command> to back out revision 4 " "again, but this time to choose parent 3, the other parent of the merge. The " "result is visible in <xref linkend=\"fig:undo:bad-merge-3\"/>, in which the " "repository now contains three heads." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><figure><title> #: ../en/ch09-undo.xml:696 msgid "Backing out the merge, favoring the other parent" msgstr "拆除合并,关注其它父亲" #. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><figure><mediaobject> #: ../en/ch09-undo.xml:699 msgid "<imageobject><imagedata fileref=\"figs/bad-merge-3.png\"/></imageobject>" msgstr "" "<imageobject><imagedata fileref=\"figs/bad-merge-3.png\"/></imageobject>" #. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> #: ../en/ch09-undo.xml:706 msgid "" "Redo the bad merge by merging the two backout heads, which reduces the number " "of heads in the repository to two, as can be seen in <xref linkend=\"fig:undo:" "bad-merge-4\"/>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><figure><title> #: ../en/ch09-undo.xml:711 ../en/ch09-undo.xml:724 msgid "Merging the backouts" msgstr "合并拆除" #. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><figure><mediaobject> #: ../en/ch09-undo.xml:713 msgid "<imageobject><imagedata fileref=\"figs/bad-merge-4.png\"/></imageobject>" msgstr "" "<imageobject><imagedata fileref=\"figs/bad-merge-4.png\"/></imageobject>" #. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> #: ../en/ch09-undo.xml:720 msgid "" "Merge with the commit that was made after the bad merge, as shown in <xref " "linkend=\"fig:undo:bad-merge-5\"/>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><figure><mediaobject> #: ../en/ch09-undo.xml:726 msgid "<imageobject><imagedata fileref=\"figs/bad-merge-5.png\"/></imageobject>" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch09-undo.xml:735 msgid "Protect yourself from <quote>escaped</quote> changes" msgstr "使用<quote>校验</quote>修改来保护你自己" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:738 msgid "" "If you've committed some changes to your local repository and they've been " "pushed or pulled somewhere else, this isn't necessarily a disaster. You can " "protect yourself ahead of time against some classes of bad changeset. This " "is particularly easy if your team usually pulls changes from a central " "repository." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:745 msgid "" "By configuring some hooks on that repository to validate incoming changesets " "(see chapter <xref linkend=\"chap:hook\"/>), you can automatically prevent " "some kinds of bad changeset from being pushed to the central repository at " "all. With such a configuration in place, some kinds of bad changeset will " "naturally tend to <quote>die out</quote> because they can't propagate into " "the central repository. Better yet, this happens without any need for " "explicit intervention." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:755 msgid "" "For instance, an incoming change hook that verifies that a changeset will " "actually compile can prevent people from inadvertently <quote>breaking the " "build</quote>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch09-undo.xml:762 msgid "What to do about sensitive changes that escape" msgstr "处理敏感信息泄漏的方法" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:764 msgid "" "Even a carefully run project can suffer an unfortunate event such as the " "committing and uncontrolled propagation of a file that contains important " "passwords." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:768 msgid "" "If something like this happens to you, and the information that gets " "accidentally propagated is truly sensitive, your first step should be to " "mitigate the effect of the leak without trying to control the leak itself. If " "you are not 100% certain that you know exactly who could have seen the " "changes, you should immediately change passwords, cancel credit cards, or " "find some other way to make sure that the information that has leaked is no " "longer useful. In other words, assume that the change has propagated far and " "wide, and that there's nothing more you can do." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:779 msgid "" "You might hope that there would be mechanisms you could use to either figure " "out who has seen a change or to erase the change permanently everywhere, but " "there are good reasons why these are not possible." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:784 msgid "" "Mercurial does not provide an audit trail of who has pulled changes from a " "repository, because it is usually either impossible to record such " "information or trivial to spoof it. In a multi-user or networked " "environment, you should thus be extremely skeptical of yourself if you think " "that you have identified every place that a sensitive changeset has " "propagated to. Don't forget that people can and will send bundles by email, " "have their backup software save data offsite, carry repositories on USB " "sticks, and find other completely innocent ways to confound your attempts to " "track down every copy of a problematic change." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:796 msgid "" "Mercurial also does not provide a way to make a file or changeset completely " "disappear from history, because there is no way to enforce its disappearance; " "someone could easily modify their copy of Mercurial to ignore such " "directives. In addition, even if Mercurial provided such a capability, " "someone who simply hadn't pulled a <quote>make this file disappear</quote> " "changeset wouldn't be affected by it, nor would web crawlers visiting at the " "wrong time, disk backups, or other mechanisms. Indeed, no distributed " "revision control system can make data reliably vanish. Providing the illusion " "of such control could easily give a false sense of security, and be worse " "than not providing it at all." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch09-undo.xml:812 msgid "Finding the source of a bug" msgstr "查找问题的根源" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch09-undo.xml:814 msgid "" "While it's all very well to be able to back out a changeset that introduced a " "bug, this requires that you know which changeset to back out. Mercurial " "provides an invaluable command, called <command role=\"hg-cmd\">hg bisect</" "command>, that helps you to automate this process and accomplish it very " "efficiently." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch09-undo.xml:821 msgid "" "The idea behind the <command role=\"hg-cmd\">hg bisect</command> command is " "that a changeset has introduced some change of behavior that you can identify " "with a simple pass/fail test. You don't know which piece of code introduced " "the change, but you know how to test for the presence of the bug. The " "<command role=\"hg-cmd\">hg bisect</command> command uses your test to direct " "its search for the changeset that introduced the code that caused the bug." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch09-undo.xml:830 msgid "" "Here are a few scenarios to help you understand how you might apply this " "command." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch09-undo.xml:833 msgid "" "The most recent version of your software has a bug that you remember wasn't " "present a few weeks ago, but you don't know when it was introduced. Here, " "your binary test checks for the presence of that bug." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch09-undo.xml:838 msgid "" "You fixed a bug in a rush, and now it's time to close the entry in your " "team's bug database. The bug database requires a changeset ID when you close " "an entry, but you don't remember which changeset you fixed the bug in. Once " "again, your binary test checks for the presence of the bug." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch09-undo.xml:845 msgid "" "Your software works correctly, but runs 15% slower than the last time you " "measured it. You want to know which changeset introduced the performance " "regression. In this case, your binary test measures the performance of your " "software, to see whether it's <quote>fast</quote> or <quote>slow</quote>." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch09-undo.xml:852 msgid "" "The sizes of the components of your project that you ship exploded recently, " "and you suspect that something changed in the way you build your project." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch09-undo.xml:857 msgid "" "From these examples, it should be clear that the <command role=\"hg-cmd\">hg " "bisect</command> command is not useful only for finding the sources of bugs. " "You can use it to find any <quote>emergent property</quote> of a repository " "(anything that you can't find from a simple text search of the files in the " "tree) for which you can write a binary test." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch09-undo.xml:864 msgid "" "We'll introduce a little bit of terminology here, just to make it clear which " "parts of the search process are your responsibility, and which are " "Mercurial's. A <emphasis>test</emphasis> is something that <emphasis>you</" "emphasis> run when <command role=\"hg-cmd\">hg bisect</command> chooses a " "changeset. A <emphasis>probe</emphasis> is what <command role=\"hg-cmd\">hg " "bisect</command> runs to tell whether a revision is good. Finally, we'll use " "the word <quote>bisect</quote>, as both a noun and a verb, to stand in for " "the phrase <quote>search using the <command role=\"hg-cmd\">hg bisect</" "command> command</quote>." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch09-undo.xml:877 msgid "" "One simple way to automate the searching process would be simply to probe " "every changeset. However, this scales poorly. If it took ten minutes to " "test a single changeset, and you had 10,000 changesets in your repository, " "the exhaustive approach would take on average 35 <emphasis>days</emphasis> to " "find the changeset that introduced a bug. Even if you knew that the bug was " "introduced by one of the last 500 changesets, and limited your search to " "those, you'd still be looking at over 40 hours to find the changeset that " "introduced your bug." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch09-undo.xml:887 msgid "" "What the <command role=\"hg-cmd\">hg bisect</command> command does is use its " "knowledge of the <quote>shape</quote> of your project's revision history to " "perform a search in time proportional to the <emphasis>logarithm</emphasis> " "of the number of changesets to check (the kind of search it performs is " "called a dichotomic search). With this approach, searching through 10,000 " "changesets will take less than three hours, even at ten minutes per test (the " "search will require about 14 tests). Limit your search to the last hundred " "changesets, and it will take only about an hour (roughly seven tests)." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch09-undo.xml:898 msgid "" "The <command role=\"hg-cmd\">hg bisect</command> command is aware of the " "<quote>branchy</quote> nature of a Mercurial project's revision history, so " "it has no problems dealing with branches, merges, or multiple heads in a " "repository. It can prune entire branches of history with a single probe, " "which is how it operates so efficiently." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch09-undo.xml:906 msgid "Using the <command role=\"hg-cmd\">hg bisect</command> command" msgstr "使用命令 <command role=\"hg-cmd\">hg bisect</command>" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:909 msgid "" "Here's an example of <command role=\"hg-cmd\">hg bisect</command> in action." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><note><para> #: ../en/ch09-undo.xml:913 msgid "" "In versions 0.9.5 and earlier of Mercurial, <command role=\"hg-cmd\">hg " "bisect</command> was not a core command: it was distributed with Mercurial as " "an extension. This section describes the built-in command, not the old " "extension." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:920 msgid "" "Now let's create a repository, so that we can try out the <command role=\"hg-" "cmd\">hg bisect</command> command in isolation." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:926 msgid "" "We'll simulate a project that has a bug in it in a simple-minded way: create " "trivial changes in a loop, and nominate one specific change that will have " "the <quote>bug</quote>. This loop creates 35 changesets, each adding a " "single file to the repository. We'll represent our <quote>bug</quote> with a " "file that contains the text <quote>i have a gub</quote>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:936 msgid "" "The next thing that we'd like to do is figure out how to use the <command " "role=\"hg-cmd\">hg bisect</command> command. We can use Mercurial's normal " "built-in help mechanism for this." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:943 msgid "" "The <command role=\"hg-cmd\">hg bisect</command> command works in steps. " "Each step proceeds as follows." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> #: ../en/ch09-undo.xml:946 msgid "You run your binary test." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><itemizedlist><listitem><para> #: ../en/ch09-undo.xml:948 msgid "" "If the test succeeded, you tell <command role=\"hg-cmd\">hg bisect</command> " "by running the <command role=\"hg-cmd\">hg bisect --good</command> command." msgstr "" "当测试成功后,使用 <command role=\"hg-cmd\">hg bisect --good</command> 命令告" "诉 <command role=\"hg-cmd\">hg bisect</command> 命令。" #. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><itemizedlist><listitem><para> #: ../en/ch09-undo.xml:953 msgid "" "If it failed, run the <command role=\"hg-cmd\">hg bisect --bad</command> " "command." msgstr "" "如果失败,执行 <command role=\"hg-cmd\">hg bisect --bad</command> 命令。" #. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> #: ../en/ch09-undo.xml:957 msgid "" "The command uses your information to decide which changeset to test next." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><orderedlist><listitem><para> #: ../en/ch09-undo.xml:960 msgid "" "It updates the working directory to that changeset, and the process begins " "again." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:963 msgid "" "The process ends when <command role=\"hg-cmd\">hg bisect</command> identifies " "a unique changeset that marks the point where your test transitioned from " "<quote>succeeding</quote> to <quote>failing</quote>." msgstr "" # #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:968 msgid "" "To start the search, we must run the <command role=\"hg-cmd\">hg bisect --" "reset</command> command." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:973 msgid "" "In our case, the binary test we use is simple: we check to see if any file in " "the repository contains the string <quote>i have a gub</quote>. If it does, " "this changeset contains the change that <quote>caused the bug</quote>. By " "convention, a changeset that has the property we're searching for is " "<quote>bad</quote>, while one that doesn't is <quote>good</quote>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:981 msgid "" "Most of the time, the revision to which the working directory is synced " "(usually the tip) already exhibits the problem introduced by the buggy " "change, so we'll mark it as <quote>bad</quote>." msgstr "" # #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:988 msgid "" "Our next task is to nominate a changeset that we know <emphasis>doesn't</" "emphasis> have the bug; the <command role=\"hg-cmd\">hg bisect</command> " "command will <quote>bracket</quote> its search between the first pair of good " "and bad changesets. In our case, we know that revision 10 didn't have the " "bug. (I'll have more words about choosing the first <quote>good</quote> " "changeset later.)" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:998 msgid "Notice that this command printed some output." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch09-undo.xml:1000 msgid "" "It told us how many changesets it must consider before it can identify the " "one that introduced the bug, and how many tests that will require." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch09-undo.xml:1004 msgid "" "It updated the working directory to the next changeset to test, and told us " "which changeset it's testing." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:1009 msgid "" "We now run our test in the working directory. We use the <command>grep</" "command> command to see if our <quote>bad</quote> file is present in the " "working directory. If it is, this revision is bad; if not, this revision is " "good. &interaction.bisect.search.step1;" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:1015 msgid "" "This test looks like a perfect candidate for automation, so let's turn it " "into a shell function." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:1019 msgid "" "We can now run an entire test step with a single command, <literal>mytest</" "literal>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:1024 msgid "A few more invocations of our canned test step command, and we're done." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:1029 msgid "" "Even though we had 40 changesets to search through, the <command role=\"hg-cmd" "\">hg bisect</command> command let us find the changeset that introduced our " "<quote>bug</quote> with only five tests. Because the number of tests that " "the <command role=\"hg-cmd\">hg bisect</command> command performs grows " "logarithmically with the number of changesets to search, the advantage that " "it has over the <quote>brute force</quote> search approach increases with " "every changeset you add." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch09-undo.xml:1040 msgid "Cleaning up after your search" msgstr "搜索后的清理" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:1042 msgid "" "When you're finished using the <command role=\"hg-cmd\">hg bisect</command> " "command in a repository, you can use the <command role=\"hg-cmd\">hg bisect --" "reset</command> command to drop the information it was using to drive your " "search. The command doesn't use much space, so it doesn't matter if you " "forget to run this command. However, <command role=\"hg-cmd\">hg bisect</" "command> won't let you start a new search in that repository until you do a " "<command role=\"hg-cmd\">hg bisect --reset</command>." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch09-undo.xml:1057 msgid "Tips for finding bugs effectively" msgstr "有效查找问题的技巧" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch09-undo.xml:1060 msgid "Give consistent input" msgstr "给出一致的输入" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:1062 msgid "" "The <command role=\"hg-cmd\">hg bisect</command> command requires that you " "correctly report the result of every test you perform. If you tell it that a " "test failed when it really succeeded, it <emphasis>might</emphasis> be able " "to detect the inconsistency. If it can identify an inconsistency in your " "reports, it will tell you that a particular changeset is both good and bad. " "However, it can't do this perfectly; it's about as likely to report the wrong " "changeset as the source of the bug." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch09-undo.xml:1074 msgid "Automate as much as possible" msgstr "尽量自动" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:1076 msgid "" "When I started using the <command role=\"hg-cmd\">hg bisect</command> " "command, I tried a few times to run my tests by hand, on the command line. " "This is an approach that I, at least, am not suited to. After a few tries, I " "found that I was making enough mistakes that I was having to restart my " "searches several times before finally getting correct results." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:1084 msgid "" "My initial problems with driving the <command role=\"hg-cmd\">hg bisect</" "command> command by hand occurred even with simple searches on small " "repositories; if the problem you're looking for is more subtle, or the number " "of tests that <command role=\"hg-cmd\">hg bisect</command> must perform " "increases, the likelihood of operator error ruining the search is much " "higher. Once I started automating my tests, I had much better results." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:1093 msgid "The key to automated testing is twofold:" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch09-undo.xml:1095 msgid "always test for the same symptom, and" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch09-undo.xml:1097 msgid "" "always feed consistent input to the <command role=\"hg-cmd\">hg bisect</" "command> command." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:1100 msgid "" "In my tutorial example above, the <command>grep</command> command tests for " "the symptom, and the <literal>if</literal> statement takes the result of this " "check and ensures that we always feed the same input to the <command role=" "\"hg-cmd\">hg bisect</command> command. The <literal>mytest</literal> " "function marries these together in a reproducible way, so that every test is " "uniform and consistent." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch09-undo.xml:1110 msgid "Check your results" msgstr "检查你的结果" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:1112 msgid "" "Because the output of a <command role=\"hg-cmd\">hg bisect</command> search " "is only as good as the input you give it, don't take the changeset it reports " "as the absolute truth. A simple way to cross-check its report is to manually " "run your test at each of the following changesets:" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch09-undo.xml:1118 msgid "" "The changeset that it reports as the first bad revision. Your test should " "still report this as bad." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch09-undo.xml:1122 msgid "" "The parent of that changeset (either parent, if it's a merge). Your test " "should report this changeset as good." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch09-undo.xml:1126 msgid "" "A child of that changeset. Your test should report this changeset as bad." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch09-undo.xml:1132 msgid "Beware interference between bugs" msgstr "谨防问题之间的冲突" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:1134 msgid "" "It's possible that your search for one bug could be disrupted by the presence " "of another. For example, let's say your software crashes at revision 100, " "and worked correctly at revision 50. Unknown to you, someone else introduced " "a different crashing bug at revision 60, and fixed it at revision 80. This " "could distort your results in one of several ways." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:1142 msgid "" "It is possible that this other bug completely <quote>masks</quote> yours, " "which is to say that it occurs before your bug has a chance to manifest " "itself. If you can't avoid that other bug (for example, it prevents your " "project from building), and so can't tell whether your bug is present in a " "particular changeset, the <command role=\"hg-cmd\">hg bisect</command> " "command cannot help you directly. Instead, you can mark a changeset as " "untested by running <command role=\"hg-cmd\">hg bisect --skip</command>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:1152 msgid "" "A different problem could arise if your test for a bug's presence is not " "specific enough. If you check for <quote>my program crashes</quote>, then " "both your crashing bug and an unrelated crashing bug that masks it will look " "like the same thing, and mislead <command role=\"hg-cmd\">hg bisect</command>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:1159 msgid "" "Another useful situation in which to use <command role=\"hg-cmd\">hg bisect --" "skip</command> is if you can't test a revision because your project was in a " "broken and hence untestable state at that revision, perhaps because someone " "checked in a change that prevented the project from building." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch09-undo.xml:1168 msgid "Bracket your search lazily" msgstr "减少你的查找工作" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:1170 msgid "" "Choosing the first <quote>good</quote> and <quote>bad</quote> changesets that " "will mark the end points of your search is often easy, but it bears a little " "discussion nevertheless. From the perspective of <command role=\"hg-cmd\">hg " "bisect</command>, the <quote>newest</quote> changeset is conventionally " "<quote>bad</quote>, and the older changeset is <quote>good</quote>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:1178 msgid "" "If you're having trouble remembering when a suitable <quote>good</quote> " "change was, so that you can tell <command role=\"hg-cmd\">hg bisect</" "command>, you could do worse than testing changesets at random. Just " "remember to eliminate contenders that can't possibly exhibit the bug (perhaps " "because the feature with the bug isn't present yet) and those where another " "problem masks the bug (as I discussed above)." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch09-undo.xml:1187 msgid "" "Even if you end up <quote>early</quote> by thousands of changesets or months " "of history, you will only add a handful of tests to the total number that " "<command role=\"hg-cmd\">hg bisect</command> must perform, thanks to its " "logarithmic behavior." msgstr "" #. type: Content of: <book><chapter><title> #: ../en/ch10-hook.xml:5 msgid "Handling repository events with hooks" msgstr "使用钩子处理版本库事件" #. type: Content of: <book><chapter><para> #: ../en/ch10-hook.xml:7 msgid "" "Mercurial offers a powerful mechanism to let you perform automated actions in " "response to events that occur in a repository. In some cases, you can even " "control Mercurial's response to those events." msgstr "" #. type: Content of: <book><chapter><para> #: ../en/ch10-hook.xml:12 msgid "" "The name Mercurial uses for one of these actions is a <emphasis>hook</" "emphasis>. Hooks are called <quote>triggers</quote> in some revision control " "systems, but the two names refer to the same idea." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch10-hook.xml:18 msgid "An overview of hooks in Mercurial" msgstr "Mercurial 钩子概述" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch10-hook.xml:20 msgid "" "Here is a brief list of the hooks that Mercurial supports. We will revisit " "each of these hooks in more detail later, in <xref linkend=\"sec:hook:ref\"/>." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch10-hook.xml:24 msgid "" "Each of the hooks whose description begins with the word <quote>Controlling</" "quote> has the ability to determine whether an activity can proceed. If the " "hook succeeds, the activity may proceed; if it fails, the activity is either " "not permitted or undone, depending on the hook." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:31 msgid "" "<literal role=\"hook\">changegroup</literal>: This is run after a group of " "changesets has been brought into the repository from elsewhere." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:35 msgid "" "<literal role=\"hook\">commit</literal>: This is run after a new changeset " "has been created in the local repository." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:39 msgid "" "<literal role=\"hook\">incoming</literal>: This is run once for each new " "changeset that is brought into the repository from elsewhere. Notice the " "difference from <literal role=\"hook\">changegroup</literal>, which is run " "once per <emphasis>group</emphasis> of changesets brought in." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:46 msgid "" "<literal role=\"hook\">outgoing</literal>: This is run after a group of " "changesets has been transmitted from this repository." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:50 msgid "" "<literal role=\"hook\">prechangegroup</literal>: This is run before starting " "to bring a group of changesets into the repository." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:55 msgid "" "<literal role=\"hook\">precommit</literal>: Controlling. This is run before " "starting a commit." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:59 msgid "" "<literal role=\"hook\">preoutgoing</literal>: Controlling. This is run before " "starting to transmit a group of changesets from this repository." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:64 msgid "" "<literal role=\"hook\">pretag</literal>: Controlling. This is run before " "creating a tag." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:68 msgid "" "<literal role=\"hook\">pretxnchangegroup</literal>: Controlling. This is run " "after a group of changesets has been brought into the local repository from " "another, but before the transaction completes that will make the changes " "permanent in the repository." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:76 msgid "" "<literal role=\"hook\">pretxncommit</literal>: Controlling. This is run after " "a new changeset has been created in the local repository, but before the " "transaction completes that will make it permanent." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:82 msgid "" "<literal role=\"hook\">preupdate</literal>: Controlling. This is run before " "starting an update or merge of the working directory." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:87 msgid "" "<literal role=\"hook\">tag</literal>: This is run after a tag is created." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:91 msgid "" "<literal role=\"hook\">update</literal>: This is run after an update or merge " "of the working directory has finished." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch10-hook.xml:99 msgid "Hooks and security" msgstr "钩子与安全性" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch10-hook.xml:102 msgid "Hooks are run with your privileges" msgstr "钩子以你的特权执行" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:104 msgid "" "When you run a Mercurial command in a repository, and the command causes a " "hook to run, that hook runs on <emphasis>your</emphasis> system, under " "<emphasis>your</emphasis> user account, with <emphasis>your</emphasis> " "privilege level. Since hooks are arbitrary pieces of executable code, you " "should treat them with an appropriate level of suspicion. Do not install a " "hook unless you are confident that you know who created it and what it does." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:115 msgid "" "In some cases, you may be exposed to hooks that you did not install " "yourself. If you work with Mercurial on an unfamiliar system, Mercurial will " "run hooks defined in that system's global <filename role=\"special\">~/.hgrc</" "filename> file." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:122 msgid "" "If you are working with a repository owned by another user, Mercurial can run " "hooks defined in that user's repository, but it will still run them as " "<quote>you</quote>. For example, if you <command role=\"hg-cmd\">hg pull</" "command> from that repository, and its <filename role=\"special\">.hg/hgrc</" "filename> defines a local <literal role=\"hook\">outgoing</literal> hook, " "that hook will run under your user account, even though you don't own that " "repository." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><note><para> #: ../en/ch10-hook.xml:134 msgid "" "This only applies if you are pulling from a repository on a local or network " "filesystem. If you're pulling over http or ssh, any <literal role=\"hook" "\">outgoing</literal> hook will run under whatever account is executing the " "server process, on the server." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:142 msgid "" "To see what hooks are defined in a repository, use the <command role=\"hg-cmd" "\">hg showconfig hooks</command> command. If you are working in one " "repository, but talking to another that you do not own (e.g. using <command " "role=\"hg-cmd\">hg pull</command> or <command role=\"hg-cmd\">hg incoming</" "command>), remember that it is the other repository's hooks you should be " "checking, not your own." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch10-hook.xml:153 msgid "Hooks do not propagate" msgstr "钩子不会传播" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:155 msgid "" "In Mercurial, hooks are not revision controlled, and do not propagate when " "you clone, or pull from, a repository. The reason for this is simple: a hook " "is a completely arbitrary piece of executable code. It runs under your user " "identity, with your privilege level, on your machine." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:162 msgid "" "It would be extremely reckless for any distributed revision control system to " "implement revision-controlled hooks, as this would offer an easily " "exploitable way to subvert the accounts of users of the revision control " "system." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:168 msgid "" "Since Mercurial does not propagate hooks, if you are collaborating with other " "people on a common project, you should not assume that they are using the " "same Mercurial hooks as you are, or that theirs are correctly configured. " "You should document the hooks you expect people to use." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:175 msgid "" "In a corporate intranet, this is somewhat easier to control, as you can for " "example provide a <quote>standard</quote> installation of Mercurial on an NFS " "filesystem, and use a site-wide <filename role=\"special\">~/.hgrc</filename> " "file to define hooks that all users will see. However, this too has its " "limits; see below." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch10-hook.xml:184 msgid "Hooks can be overridden" msgstr "钩子可以被覆盖" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:186 msgid "" "Mercurial allows you to override a hook definition by redefining the hook. " "You can disable it by setting its value to the empty string, or change its " "behavior as you wish." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:191 msgid "" "If you deploy a system- or site-wide <filename role=\"special\">~/.hgrc</" "filename> file that defines some hooks, you should thus understand that your " "users can disable or override those hooks." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch10-hook.xml:199 msgid "Ensuring that critical hooks are run" msgstr "确保关键钩子的执行" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:201 msgid "" "Sometimes you may want to enforce a policy that you do not want others to be " "able to work around. For example, you may have a requirement that every " "changeset must pass a rigorous set of tests. Defining this requirement via a " "hook in a site-wide <filename role=\"special\">~/.hgrc</filename> won't work " "for remote users on laptops, and of course local users can subvert it at will " "by overriding the hook." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:210 msgid "" "Instead, you can set up your policies for use of Mercurial so that people are " "expected to propagate changes through a well-known <quote>canonical</quote> " "server that you have locked down and configured appropriately." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:216 msgid "" "One way to do this is via a combination of social engineering and " "technology. Set up a restricted-access account; users can push changes over " "the network to repositories managed by this account, but they cannot log into " "the account and run normal shell commands. In this scenario, a user can " "commit a changeset that contains any old garbage they want." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:225 msgid "" "When someone pushes a changeset to the server that everyone pulls from, the " "server will test the changeset before it accepts it as permanent, and reject " "it if it fails to pass the test suite. If people only pull changes from this " "filtering server, it will serve to ensure that all changes that people pull " "have been automatically vetted." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch10-hook.xml:237 msgid "A short tutorial on using hooks" msgstr "使用钩子的简短指南" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch10-hook.xml:239 msgid "" "It is easy to write a Mercurial hook. Let's start with a hook that runs when " "you finish a <command role=\"hg-cmd\">hg commit</command>, and simply prints " "the hash of the changeset you just created. The hook is called <literal role=" "\"hook\">commit</literal>." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch10-hook.xml:246 msgid "All hooks follow the pattern in this example." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch10-hook.xml:250 msgid "" "You add an entry to the <literal role=\"rc-hooks\">hooks</literal> section of " "your <filename role=\"special\">~/.hgrc</filename>. On the left is the name " "of the event to trigger on; on the right is the action to take. As you can " "see, you can run an arbitrary shell command in a hook. Mercurial passes " "extra information to the hook using environment variables (look for " "<envar>HG_NODE</envar> in the example)." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch10-hook.xml:260 msgid "Performing multiple actions per event" msgstr "每个事件执行多个操作" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:262 msgid "" "Quite often, you will want to define more than one hook for a particular kind " "of event, as shown below." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:267 msgid "" "Mercurial lets you do this by adding an <emphasis>extension</emphasis> to the " "end of a hook's name. You extend a hook's name by giving the name of the " "hook, followed by a full stop (the <quote><literal>.</literal></quote> " "character), followed by some more text of your choosing. For example, " "Mercurial will run both <literal>commit.foo</literal> and <literal>commit." "bar</literal> when the <literal>commit</literal> event occurs." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:278 msgid "" "To give a well-defined order of execution when there are multiple hooks " "defined for an event, Mercurial sorts hooks by extension, and executes the " "hook commands in this sorted order. In the above example, it will execute " "<literal>commit.bar</literal> before <literal>commit.foo</literal>, and " "<literal>commit</literal> before both." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:287 msgid "" "It is a good idea to use a somewhat descriptive extension when you define a " "new hook. This will help you to remember what the hook was for. If the hook " "fails, you'll get an error message that contains the hook name and extension, " "so using a descriptive extension could give you an immediate hint as to why " "the hook failed (see <xref linkend=\"sec:hook:perm\"/> for an example)." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch10-hook.xml:298 msgid "Controlling whether an activity can proceed" msgstr "控制处理的活动" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:300 msgid "" "In our earlier examples, we used the <literal role=\"hook\">commit</literal> " "hook, which is run after a commit has completed. This is one of several " "Mercurial hooks that run after an activity finishes. Such hooks have no way " "of influencing the activity itself." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:307 msgid "" "Mercurial defines a number of events that occur before an activity starts; or " "after it starts, but before it finishes. Hooks that trigger on these events " "have the added ability to choose whether the activity can continue, or will " "abort." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:313 msgid "" "The <literal role=\"hook\">pretxncommit</literal> hook runs after a commit " "has all but completed. In other words, the metadata representing the " "changeset has been written out to disk, but the transaction has not yet been " "allowed to complete. The <literal role=\"hook\">pretxncommit</literal> hook " "has the ability to decide whether the transaction can complete, or must be " "rolled back." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:322 msgid "" "If the <literal role=\"hook\">pretxncommit</literal> hook exits with a status " "code of zero, the transaction is allowed to complete; the commit finishes; " "and the <literal role=\"hook\">commit</literal> hook is run. If the <literal " "role=\"hook\">pretxncommit</literal> hook exits with a non-zero status code, " "the transaction is rolled back; the metadata representing the changeset is " "erased; and the <literal role=\"hook\">commit</literal> hook is not run." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:334 msgid "" "The hook in the example above checks that a commit comment contains a bug " "ID. If it does, the commit can complete. If not, the commit is rolled back." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch10-hook.xml:342 msgid "Writing your own hooks" msgstr "编写钩子" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch10-hook.xml:344 msgid "" "When you are writing a hook, you might find it useful to run Mercurial either " "with the <option role=\"hg-opt-global\">-v</option> option, or the <envar " "role=\"rc-item-ui\">verbose</envar> config item set to <quote>true</quote>. " "When you do so, Mercurial will print a message before it calls each hook." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch10-hook.xml:353 msgid "Choosing how your hook should run" msgstr "选择钩子的执行方式" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:355 msgid "" "You can write a hook either as a normal program&emdash;typically a shell " "script&emdash;or as a Python function that is executed within the Mercurial " "process." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:360 msgid "" "Writing a hook as an external program has the advantage that it requires no " "knowledge of Mercurial's internals. You can call normal Mercurial commands " "to get any added information you need. The trade-off is that external hooks " "are slower than in-process hooks." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:367 msgid "" "An in-process Python hook has complete access to the Mercurial API, and does " "not <quote>shell out</quote> to another process, so it is inherently faster " "than an external hook. It is also easier to obtain much of the information " "that a hook requires by using the Mercurial API than by running Mercurial " "commands." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:375 msgid "" "If you are comfortable with Python, or require high performance, writing your " "hooks in Python may be a good choice. However, when you have a " "straightforward hook to write and you don't need to care about performance " "(probably the majority of hooks), a shell script is perfectly fine." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch10-hook.xml:384 msgid "Hook parameters" msgstr "钩子的参数" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:386 msgid "" "Mercurial calls each hook with a set of well-defined parameters. In Python, " "a parameter is passed as a keyword argument to your hook function. For an " "external program, a parameter is passed as an environment variable." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:392 msgid "" "Whether your hook is written in Python or as a shell script, the hook-" "specific parameter names and values will be the same. A boolean parameter " "will be represented as a boolean value in Python, but as the number 1 (for " "<quote>true</quote>) or 0 (for <quote>false</quote>) as an environment " "variable for an external hook. If a hook parameter is named <literal>foo</" "literal>, the keyword argument for a Python hook will also be named " "<literal>foo</literal>, while the environment variable for an external hook " "will be named <literal>HG_FOO</literal>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch10-hook.xml:406 msgid "Hook return values and activity control" msgstr "钩子的返回值与活动控制" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:408 msgid "" "A hook that executes successfully must exit with a status of zero if " "external, or return boolean <quote>false</quote> if in-process. Failure is " "indicated with a non-zero exit status from an external hook, or an in-process " "hook returning boolean <quote>true</quote>. If an in-process hook raises an " "exception, the hook is considered to have failed." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:416 msgid "" "For a hook that controls whether an activity can proceed, zero/false means " "<quote>allow</quote>, while non-zero/true/exception means <quote>deny</quote>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch10-hook.xml:423 msgid "Writing an external hook" msgstr "编写外部钩子" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:425 msgid "" "When you define an external hook in your <filename role=\"special\">~/.hgrc</" "filename> and the hook is run, its value is passed to your shell, which " "interprets it. This means that you can use normal shell constructs in the " "body of the hook." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:432 msgid "" "An executable hook is always run with its current directory set to a " "repository's root directory." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:436 msgid "" "Each hook parameter is passed in as an environment variable; the name is " "upper-cased, and prefixed with the string <quote><literal>HG_</literal></" "quote>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:441 msgid "" "With the exception of hook parameters, Mercurial does not set or modify any " "environment variables when running a hook. This is useful to remember if you " "are writing a site-wide hook that may be run by a number of different users " "with differing environment variables set. In multi-user situations, you " "should not rely on environment variables being set to the values you have in " "your environment when testing the hook." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch10-hook.xml:452 msgid "Telling Mercurial to use an in-process hook" msgstr "让 Mercurial 使用进程内钩子" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:454 msgid "" "The <filename role=\"special\">~/.hgrc</filename> syntax for defining an in-" "process hook is slightly different than for an executable hook. The value of " "the hook must start with the text <quote><literal>python:</literal></quote>, " "and continue with the fully-qualified name of a callable object to use as the " "hook's value." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:462 msgid "" "The module in which a hook lives is automatically imported when a hook is " "run. So long as you have the module name and <envar>PYTHONPATH</envar> " "right, it should <quote>just work</quote>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:468 msgid "" "The following <filename role=\"special\">~/.hgrc</filename> example snippet " "illustrates the syntax and meaning of the notions we just described." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:474 msgid "" "When Mercurial runs the <literal>commit.example</literal> hook, it imports " "<literal>mymodule.submodule</literal>, looks for the callable object named " "<literal>myhook</literal>, and calls it." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch10-hook.xml:482 msgid "Writing an in-process hook" msgstr "编写进程内钩子" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:484 msgid "" "The simplest in-process hook does nothing, but illustrates the basic shape of " "the hook API:" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:489 msgid "" "The first argument to a Python hook is always a <literal role=\"py-mod-" "mercurial.ui\">ui</literal> object. The second is a repository object; at " "the moment, it is always an instance of <literal role=\"py-mod-mercurial." "localrepo\">localrepository</literal>. Following these two arguments are " "other keyword arguments. Which ones are passed in depends on the hook being " "called, but a hook can ignore arguments it doesn't care about by dropping " "them into a keyword argument dict, as with <literal>**kwargs</literal> above." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch10-hook.xml:504 msgid "Some hook examples" msgstr "钩子样例" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch10-hook.xml:507 msgid "Writing meaningful commit messages" msgstr "编写有意义的提交日志" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:509 msgid "" "It's hard to imagine a useful commit message being very short. The simple " "<literal role=\"hook\">pretxncommit</literal> hook of the example below will " "prevent you from committing a changeset with a message that is less than ten " "bytes long." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch10-hook.xml:519 msgid "Checking for trailing whitespace" msgstr "检查行尾空格" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:521 msgid "" "An interesting use of a commit-related hook is to help you to write cleaner " "code. A simple example of <quote>cleaner code</quote> is the dictum that a " "change should not add any new lines of text that contain <quote>trailing " "whitespace</quote>. Trailing whitespace is a series of space and tab " "characters at the end of a line of text. In most cases, trailing whitespace " "is unnecessary, invisible noise, but it is occasionally problematic, and " "people often prefer to get rid of it." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:532 msgid "" "You can use either the <literal role=\"hook\">precommit</literal> or <literal " "role=\"hook\">pretxncommit</literal> hook to tell whether you have a trailing " "whitespace problem. If you use the <literal role=\"hook\">precommit</" "literal> hook, the hook will not know which files you are committing, so it " "will have to check every modified file in the repository for trailing white " "space. If you want to commit a change to just the file <filename>foo</" "filename>, but the file <filename>bar</filename> contains trailing " "whitespace, doing a check in the <literal role=\"hook\">precommit</literal> " "hook will prevent you from committing <filename>foo</filename> due to the " "problem with <filename>bar</filename>. This doesn't seem right." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:548 msgid "" "Should you choose the <literal role=\"hook\">pretxncommit</literal> hook, the " "check won't occur until just before the transaction for the commit " "completes. This will allow you to check for problems only the exact files " "that are being committed. However, if you entered the commit message " "interactively and the hook fails, the transaction will roll back; you'll have " "to re-enter the commit message after you fix the trailing whitespace and run " "<command role=\"hg-cmd\">hg commit</command> again." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:561 msgid "" "In this example, we introduce a simple <literal role=\"hook\">pretxncommit</" "literal> hook that checks for trailing whitespace. This hook is short, but " "not very helpful. It exits with an error status if a change adds a line with " "trailing whitespace to any file, but does not print any information that " "might help us to identify the offending file or line. It also has the nice " "property of not paying attention to unmodified lines; only lines that " "introduce new trailing whitespace cause problems." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:574 msgid "" "The above version is much more complex, but also more useful. It parses a " "unified diff to see if any lines add trailing whitespace, and prints the name " "of the file and the line number of each such occurrence. Even better, if the " "change adds trailing whitespace, this hook saves the commit comment and " "prints the name of the save file before exiting and telling Mercurial to roll " "the transaction back, so you can use the <option role=\"hg-opt-commit\">-l " "filename</option> option to <command role=\"hg-cmd\">hg commit</command> to " "reuse the saved commit message once you've corrected the problem." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:588 msgid "" "As a final aside, note in the example above the use of <command>sed</" "command>'s in-place editing feature to get rid of trailing whitespace from a " "file. This is concise and useful enough that I will reproduce it here (using " "<command>perl</command> for good measure)." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch10-hook.xml:598 msgid "Bundled hooks" msgstr "内置的钩子" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch10-hook.xml:600 msgid "" "Mercurial ships with several bundled hooks. You can find them in the " "<filename class=\"directory\">hgext</filename> directory of a Mercurial " "source tree. If you are using a Mercurial binary package, the hooks will be " "located in the <filename class=\"directory\">hgext</filename> directory of " "wherever your package installer put Mercurial." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch10-hook.xml:609 msgid "" "<literal role=\"hg-ext\">acl</literal>&emdash;access control for parts of a " "repository" msgstr "<literal role=\"hg-ext\">acl</literal>—版本库的访问控制" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:612 msgid "" "The <literal role=\"hg-ext\">acl</literal> extension lets you control which " "remote users are allowed to push changesets to a networked server. You can " "protect any portion of a repository (including the entire repo), so that a " "specific remote user can push changes that do not affect the protected " "portion." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:620 msgid "" "This extension implements access control based on the identity of the user " "performing a push, <emphasis>not</emphasis> on who committed the changesets " "they're pushing. It makes sense to use this hook only if you have a locked-" "down server environment that authenticates remote users, and you want to be " "sure that only specific users are allowed to push changes to that server." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><title> #: ../en/ch10-hook.xml:630 msgid "Configuring the <literal role=\"hook\">acl</literal> hook" msgstr "配置 <literal role=\"hook\">acl</literal> 钩子" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch10-hook.xml:633 msgid "" "In order to manage incoming changesets, the <literal role=\"hg-ext\">acl</" "literal> hook must be used as a <literal role=\"hook\">pretxnchangegroup</" "literal> hook. This lets it see which files are modified by each incoming " "changeset, and roll back a group of changesets if they modify " "<quote>forbidden</quote> files. Example:" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch10-hook.xml:643 msgid "" "The <literal role=\"hg-ext\">acl</literal> extension is configured using " "three sections." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch10-hook.xml:647 msgid "" "The <literal role=\"rc-acl\">acl</literal> section has only one entry, <envar " "role=\"rc-item-acl\">sources</envar>, which lists the sources of incoming " "changesets that the hook should pay attention to. You don't normally need to " "configure this section." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:654 msgid "" "<envar role=\"rc-item-acl\">serve</envar>: Control incoming changesets that " "are arriving from a remote repository over http or ssh. This is the default " "value of <envar role=\"rc-item-acl\">sources</envar>, and usually the only " "setting you'll need for this configuration item." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:662 msgid "" "<envar role=\"rc-item-acl\">pull</envar>: Control incoming changesets that " "are arriving via a pull from a local repository." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:667 msgid "" "<envar role=\"rc-item-acl\">push</envar>: Control incoming changesets that " "are arriving via a push from a local repository." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:672 msgid "" "<envar role=\"rc-item-acl\">bundle</envar>: Control incoming changesets that " "are arriving from another repository via a bundle." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch10-hook.xml:678 msgid "" "The <literal role=\"rc-acl.allow\">acl.allow</literal> section controls the " "users that are allowed to add changesets to the repository. If this section " "is not present, all users that are not explicitly denied are allowed. If " "this section is present, all users that are not explicitly allowed are denied " "(so an empty section means that all users are denied)." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch10-hook.xml:687 msgid "" "The <literal role=\"rc-acl.deny\">acl.deny</literal> section determines which " "users are denied from adding changesets to the repository. If this section " "is not present or is empty, no users are denied." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch10-hook.xml:693 msgid "" "The syntaxes for the <literal role=\"rc-acl.allow\">acl.allow</literal> and " "<literal role=\"rc-acl.deny\">acl.deny</literal> sections are identical. On " "the left of each entry is a glob pattern that matches files or directories, " "relative to the root of the repository; on the right, a user name." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch10-hook.xml:701 msgid "" "In the following example, the user <literal>docwriter</literal> can only push " "changes to the <filename class=\"directory\">docs</filename> subtree of the " "repository, while <literal>intern</literal> can push changes to any file or " "directory except <filename class=\"directory\">source/sensitive</filename>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><title> #: ../en/ch10-hook.xml:715 ../en/ch10-hook.xml:979 ../en/ch10-hook.xml:1169 msgid "Testing and troubleshooting" msgstr "测试与问题处理" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch10-hook.xml:717 msgid "" "If you want to test the <literal role=\"hg-ext\">acl</literal> hook, run it " "with Mercurial's debugging output enabled. Since you'll probably be running " "it on a server where it's not convenient (or sometimes possible) to pass in " "the <option role=\"hg-opt-global\">--debug</option> option, don't forget that " "you can enable debugging output in your <filename role=\"special\">~/.hgrc</" "filename>:" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch10-hook.xml:728 msgid "" "With this enabled, the <literal role=\"hg-ext\">acl</literal> hook will print " "enough information to let you figure out why it is allowing or forbidding " "pushes from specific users." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch10-hook.xml:737 msgid "" "<literal role=\"hg-ext\">bugzilla</literal>&emdash;integration with Bugzilla" msgstr "<literal role=\"hg-ext\">bugzilla</literal>—与 Bugzilla 的集成" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:741 msgid "" "The <literal role=\"hg-ext\">bugzilla</literal> extension adds a comment to a " "Bugzilla bug whenever it finds a reference to that bug ID in a commit " "comment. You can install this hook on a shared server, so that any time a " "remote user pushes changes to this server, the hook gets run." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:748 msgid "" "It adds a comment to the bug that looks like this (you can configure the " "contents of the comment&emdash;see below):" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:757 msgid "" "The value of this hook is that it automates the process of updating a bug any " "time a changeset refers to it. If you configure the hook properly, it makes " "it easy for people to browse straight from a Bugzilla bug to a changeset that " "refers to that bug." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:764 msgid "" "You can use the code in this hook as a starting point for some more exotic " "Bugzilla integration recipes. Here are a few possibilities:" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:769 msgid "" "Require that every changeset pushed to the server have a valid bug ID in its " "commit comment. In this case, you'd want to configure the hook as a <literal " "role=\"hook\">pretxncommit</literal> hook. This would allow the hook to " "reject changes that didn't contain bug IDs." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:777 msgid "" "Allow incoming changesets to automatically modify the <emphasis>state</" "emphasis> of a bug, as well as simply adding a comment. For example, the " "hook could recognise the string <quote>fixed bug 31337</quote> as indicating " "that it should update the state of bug 31337 to <quote>requires testing</" "quote>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><title> #: ../en/ch10-hook.xml:787 msgid "Configuring the <literal role=\"hook\">bugzilla</literal> hook" msgstr "配置 <literal role=\"hook\">bugzilla</literal> 钩子" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch10-hook.xml:790 msgid "" "You should configure this hook in your server's <filename role=\"special\">~/." "hgrc</filename> as an <literal role=\"hook\">incoming</literal> hook, for " "example as follows:" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch10-hook.xml:798 msgid "" "Because of the specialised nature of this hook, and because Bugzilla was not " "written with this kind of integration in mind, configuring this hook is a " "somewhat involved process." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch10-hook.xml:804 msgid "" "Before you begin, you must install the MySQL bindings for Python on the host" "(s) where you'll be running the hook. If this is not available as a binary " "package for your system, you can download it from <citation>web:mysql-python</" "citation>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch10-hook.xml:811 msgid "" "Configuration information for this hook lives in the <literal role=\"rc-" "bugzilla\">bugzilla</literal> section of your <filename role=\"special\">~/." "hgrc</filename>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:816 msgid "" "<envar role=\"rc-item-bugzilla\">version</envar>: The version of Bugzilla " "installed on the server. The database schema that Bugzilla uses changes " "occasionally, so this hook has to know exactly which schema to use." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:822 msgid "" "<envar role=\"rc-item-bugzilla\">host</envar>: The hostname of the MySQL " "server that stores your Bugzilla data. The database must be configured to " "allow connections from whatever host you are running the <literal role=\"hook" "\">bugzilla</literal> hook on." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:829 msgid "" "<envar role=\"rc-item-bugzilla\">user</envar>: The username with which to " "connect to the MySQL server. The database must be configured to allow this " "user to connect from whatever host you are running the <literal role=\"hook" "\">bugzilla</literal> hook on. This user must be able to access and modify " "Bugzilla tables. The default value of this item is <literal>bugs</literal>, " "which is the standard name of the Bugzilla user in a MySQL database." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:840 msgid "" "<envar role=\"rc-item-bugzilla\">password</envar>: The MySQL password for the " "user you configured above. This is stored as plain text, so you should make " "sure that unauthorised users cannot read the <filename role=\"special\">~/." "hgrc</filename> file where you store this information." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:849 msgid "" "<envar role=\"rc-item-bugzilla\">db</envar>: The name of the Bugzilla " "database on the MySQL server. The default value of this item is " "<literal>bugs</literal>, which is the standard name of the MySQL database " "where Bugzilla stores its data." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:856 msgid "" "<envar role=\"rc-item-bugzilla\">notify</envar>: If you want Bugzilla to send " "out a notification email to subscribers after this hook has added a comment " "to a bug, you will need this hook to run a command whenever it updates the " "database. The command to run depends on where you have installed Bugzilla, " "but it will typically look something like this, if you have Bugzilla " "installed in <filename class=\"directory\">/var/www/html/bugzilla</filename>:" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:869 msgid "" "The Bugzilla <literal>processmail</literal> program expects to be given a bug " "ID (the hook replaces <quote><literal>%s</literal></quote> with the bug ID) " "and an email address. It also expects to be able to write to some files in " "the directory that it runs in. If Bugzilla and this hook are not installed " "on the same machine, you will need to find a way to run <literal>processmail</" "literal> on the server where Bugzilla is installed." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><title> #: ../en/ch10-hook.xml:884 msgid "Mapping committer names to Bugzilla user names" msgstr "提交者的名称与 Bugzilla 用户名称的映射" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch10-hook.xml:886 msgid "" "By default, the <literal role=\"hg-ext\">bugzilla</literal> hook tries to use " "the email address of a changeset's committer as the Bugzilla user name with " "which to update a bug. If this does not suit your needs, you can map " "committer email addresses to Bugzilla user names using a <literal role=\"rc-" "usermap\">usermap</literal> section." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch10-hook.xml:895 msgid "" "Each item in the <literal role=\"rc-usermap\">usermap</literal> section " "contains an email address on the left, and a Bugzilla user name on the right." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch10-hook.xml:902 msgid "" "You can either keep the <literal role=\"rc-usermap\">usermap</literal> data " "in a normal <filename role=\"special\">~/.hgrc</filename>, or tell the " "<literal role=\"hg-ext\">bugzilla</literal> hook to read the information from " "an external <filename>usermap</filename> file. In the latter case, you can " "store <filename>usermap</filename> data by itself in (for example) a user-" "modifiable repository. This makes it possible to let your users maintain " "their own <envar role=\"rc-item-bugzilla\">usermap</envar> entries. The main " "<filename role=\"special\">~/.hgrc</filename> file might look like this:" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch10-hook.xml:918 msgid "" "While the <filename>usermap</filename> file that it refers to might look like " "this:" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><title> #: ../en/ch10-hook.xml:926 msgid "Configuring the text that gets added to a bug" msgstr "配置增加到问题中的正文" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch10-hook.xml:928 msgid "" "You can configure the text that this hook adds as a comment; you specify it " "in the form of a Mercurial template. Several <filename role=\"special\">~/." "hgrc</filename> entries (still in the <literal role=\"rc-bugzilla\">bugzilla</" "literal> section) control this behavior." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:935 msgid "" "<literal>strip</literal>: The number of leading path elements to strip from a " "repository's path name to construct a partial path for a URL. For example, if " "the repositories on your server live under <filename class=\"directory\">/" "home/hg/repos</filename>, and you have a repository whose path is <filename " "class=\"directory\">/home/hg/repos/app/tests</filename>, then setting " "<literal>strip</literal> to <literal>4</literal> will give a partial path of " "<filename class=\"directory\">app/tests</filename>. The hook will make this " "partial path available when expanding a template, as <literal>webroot</" "literal>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:949 msgid "" "<literal>template</literal>: The text of the template to use. In addition to " "the usual changeset-related variables, this template can use <literal>hgweb</" "literal> (the value of the <literal>hgweb</literal> configuration item above) " "and <literal>webroot</literal> (the path constructed using <literal>strip</" "literal> above)." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch10-hook.xml:959 msgid "" "In addition, you can add a <envar role=\"rc-item-web\">baseurl</envar> item " "to the <literal role=\"rc-web\">web</literal> section of your <filename role=" "\"special\">~/.hgrc</filename>. The <literal role=\"hg-ext\">bugzilla</" "literal> hook will make this available when expanding a template, as the base " "string to use when constructing a URL that will let users browse from a " "Bugzilla comment to view a changeset. Example:" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch10-hook.xml:971 msgid "" "Here is an example set of <literal role=\"hg-ext\">bugzilla</literal> hook " "config information." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch10-hook.xml:981 msgid "" "The most common problems with configuring the <literal role=\"hg-ext" "\">bugzilla</literal> hook relate to running Bugzilla's " "<filename>processmail</filename> script and mapping committer names to user " "names." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch10-hook.xml:987 msgid "" "Recall from <xref linkend=\"sec:hook:bugzilla:config\"/> above that the user " "that runs the Mercurial process on the server is also the one that will run " "the <filename>processmail</filename> script. The <filename>processmail</" "filename> script sometimes causes Bugzilla to write to files in its " "configuration directory, and Bugzilla's configuration files are usually owned " "by the user that your web server runs under." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch10-hook.xml:998 msgid "" "You can cause <filename>processmail</filename> to be run with the suitable " "user's identity using the <command>sudo</command> command. Here is an " "example entry for a <filename>sudoers</filename> file." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch10-hook.xml:1005 msgid "" "This allows the <literal>hg_user</literal> user to run a " "<filename>processmail-wrapper</filename> program under the identity of " "<literal>httpd_user</literal>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch10-hook.xml:1010 msgid "" "This indirection through a wrapper script is necessary, because " "<filename>processmail</filename> expects to be run with its current directory " "set to wherever you installed Bugzilla; you can't specify that kind of " "constraint in a <filename>sudoers</filename> file. The contents of the " "wrapper script are simple:" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch10-hook.xml:1019 msgid "" "It doesn't seem to matter what email address you pass to " "<filename>processmail</filename>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch10-hook.xml:1023 msgid "" "If your <literal role=\"rc-usermap\">usermap</literal> is not set up " "correctly, users will see an error message from the <literal role=\"hg-ext" "\">bugzilla</literal> hook when they push changes to the server. The error " "message will look like this:" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch10-hook.xml:1030 msgid "" "What this means is that the committer's address, <literal>john.q." "public@example.com</literal>, is not a valid Bugzilla user name, nor does it " "have an entry in your <literal role=\"rc-usermap\">usermap</literal> that " "maps it to a valid Bugzilla user name." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch10-hook.xml:1040 msgid "" "<literal role=\"hg-ext\">notify</literal>&emdash;send email notifications" msgstr "<literal role=\"hg-ext\">notify</literal>—邮件通知" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1043 msgid "" "Although Mercurial's built-in web server provides RSS feeds of changes in " "every repository, many people prefer to receive change notifications via " "email. The <literal role=\"hg-ext\">notify</literal> hook lets you send out " "notifications to a set of email addresses whenever changesets arrive that " "those subscribers are interested in." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1051 msgid "" "As with the <literal role=\"hg-ext\">bugzilla</literal> hook, the <literal " "role=\"hg-ext\">notify</literal> hook is template-driven, so you can " "customise the contents of the notification messages that it sends." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1057 msgid "" "By default, the <literal role=\"hg-ext\">notify</literal> hook includes a " "diff of every changeset that it sends out; you can limit the size of the " "diff, or turn this feature off entirely. It is useful for letting " "subscribers review changes immediately, rather than clicking to follow a URL." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><title> #: ../en/ch10-hook.xml:1065 msgid "Configuring the <literal role=\"hg-ext\">notify</literal> hook" msgstr "配置 <literal role=\"hg-ext\">notify</literal> 钩子" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch10-hook.xml:1068 msgid "" "You can set up the <literal role=\"hg-ext\">notify</literal> hook to send one " "email message per incoming changeset, or one per incoming group of changesets " "(all those that arrived in a single pull or push)." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch10-hook.xml:1080 msgid "" "Configuration information for this hook lives in the <literal role=\"rc-notify" "\">notify</literal> section of a <filename role=\"special\">~/.hgrc</" "filename> file." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:1085 msgid "" "<envar role=\"rc-item-notify\">test</envar>: By default, this hook does not " "send out email at all; instead, it prints the message that it " "<emphasis>would</emphasis> send. Set this item to <literal>false</literal> " "to allow email to be sent. The reason that sending of email is turned off by " "default is that it takes several tries to configure this extension exactly as " "you would like, and it would be bad form to spam subscribers with a number of " "<quote>broken</quote> notifications while you debug your configuration." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:1097 msgid "" "<envar role=\"rc-item-notify\">config</envar>: The path to a configuration " "file that contains subscription information. This is kept separate from the " "main <filename role=\"special\">~/.hgrc</filename> so that you can maintain " "it in a repository of its own. People can then clone that repository, update " "their subscriptions, and push the changes back to your server." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:1106 msgid "" "<envar role=\"rc-item-notify\">strip</envar>: The number of leading path " "separator characters to strip from a repository's path, when deciding whether " "a repository has subscribers. For example, if the repositories on your " "server live in <filename class=\"directory\">/home/hg/repos</filename>, and " "<literal role=\"hg-ext\">notify</literal> is considering a repository named " "<filename class=\"directory\">/home/hg/repos/shared/test</filename>, setting " "<envar role=\"rc-item-notify\">strip</envar> to <literal>4</literal> will " "cause <literal role=\"hg-ext\">notify</literal> to trim the path it considers " "down to <filename class=\"directory\">shared/test</filename>, and it will " "match subscribers against that." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:1123 msgid "" "<envar role=\"rc-item-notify\">template</envar>: The template text to use " "when sending messages. This specifies both the contents of the message " "header and its body." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:1129 msgid "" "<envar role=\"rc-item-notify\">maxdiff</envar>: The maximum number of lines " "of diff data to append to the end of a message. If a diff is longer than " "this, it is truncated. By default, this is set to 300. Set this to " "<literal>0</literal> to omit diffs from notification emails." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:1138 msgid "" "<envar role=\"rc-item-notify\">sources</envar>: A list of sources of " "changesets to consider. This lets you limit <literal role=\"hg-ext\">notify</" "literal> to only sending out email about changes that remote users pushed " "into this repository via a server, for example. See <xref linkend=\"sec:hook:" "sources\"/> for the sources you can specify here." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch10-hook.xml:1149 msgid "" "If you set the <envar role=\"rc-item-web\">baseurl</envar> item in the " "<literal role=\"rc-web\">web</literal> section, you can use it in a template; " "it will be available as <literal>webroot</literal>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch10-hook.xml:1155 msgid "" "Here is an example set of <literal role=\"hg-ext\">notify</literal> " "configuration information." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch10-hook.xml:1161 msgid "This will produce a message that looks like the following:" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch10-hook.xml:1171 msgid "" "Do not forget that by default, the <literal role=\"hg-ext\">notify</literal> " "extension <emphasis>will not send any mail</emphasis> until you explicitly " "configure it to do so, by setting <envar role=\"rc-item-notify\">test</envar> " "to <literal>false</literal>. Until you do that, it simply prints the message " "it <emphasis>would</emphasis> send." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch10-hook.xml:1183 msgid "Information for writers of hooks" msgstr "编写钩子的信息" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch10-hook.xml:1186 msgid "In-process hook execution" msgstr "进程内钩子的执行" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1188 msgid "An in-process hook is called with arguments of the following form:" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1192 msgid "" "The <literal>ui</literal> parameter is a <literal role=\"py-mod-mercurial.ui" "\">ui</literal> object. The <literal>repo</literal> parameter is a <literal " "role=\"py-mod-mercurial.localrepo\">localrepository</literal> object. The " "names and values of the <literal>**kwargs</literal> parameters depend on the " "hook being invoked, with the following common features:" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:1201 msgid "" "If a parameter is named <literal>node</literal> or <literal>parentN</" "literal>, it will contain a hexadecimal changeset ID. The empty string is " "used to represent <quote>null changeset ID</quote> instead of a string of " "zeroes." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:1208 msgid "" "If a parameter is named <literal>url</literal>, it will contain the URL of a " "remote repository, if that can be determined." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:1213 msgid "" "Boolean-valued parameters are represented as Python <literal>bool</literal> " "objects." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1218 msgid "" "An in-process hook is called without a change to the process's working " "directory (unlike external hooks, which are run in the root of the " "repository). It must not change the process's working directory, or it will " "cause any calls it makes into the Mercurial API to fail." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1225 msgid "" "If a hook returns a boolean <quote>false</quote> value, it is considered to " "have succeeded. If it returns a boolean <quote>true</quote> value or raises " "an exception, it is considered to have failed. A useful way to think of the " "calling convention is <quote>tell me if you fail</quote>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1232 msgid "" "Note that changeset IDs are passed into Python hooks as hexadecimal strings, " "not the binary hashes that Mercurial's APIs normally use. To convert a hash " "from hex to binary, use the <literal>bin</literal> function." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch10-hook.xml:1240 msgid "External hook execution" msgstr "外部钩子的执行" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1242 msgid "" "An external hook is passed to the shell of the user running Mercurial. " "Features of that shell, such as variable substitution and command " "redirection, are available. The hook is run in the root directory of the " "repository (unlike in-process hooks, which are run in the same directory that " "Mercurial was run in)." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1250 msgid "" "Hook parameters are passed to the hook as environment variables. Each " "environment variable's name is converted in upper case and prefixed with the " "string <quote><literal>HG_</literal></quote>. For example, if the name of a " "parameter is <quote><literal>node</literal></quote>, the name of the " "environment variable representing that parameter will be " "<quote><literal>HG_NODE</literal></quote>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1259 msgid "" "A boolean parameter is represented as the string <quote><literal>1</literal></" "quote> for <quote>true</quote>, <quote><literal>0</literal></quote> for " "<quote>false</quote>. If an environment variable is named <envar>HG_NODE</" "envar>, <envar>HG_PARENT1</envar> or <envar>HG_PARENT2</envar>, it contains a " "changeset ID represented as a hexadecimal string. The empty string is used " "to represent <quote>null changeset ID</quote> instead of a string of zeroes. " "If an environment variable is named <envar>HG_URL</envar>, it will contain " "the URL of a remote repository, if that can be determined." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1271 msgid "" "If a hook exits with a status of zero, it is considered to have succeeded. " "If it exits with a non-zero status, it is considered to have failed." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch10-hook.xml:1278 msgid "Finding out where changesets come from" msgstr "检查修改集来自何处" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1280 msgid "" "A hook that involves the transfer of changesets between a local repository " "and another may be able to find out information about the <quote>far side</" "quote>. Mercurial knows <emphasis>how</emphasis> changes are being " "transferred, and in many cases <emphasis>where</emphasis> they are being " "transferred to or from." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><title> #: ../en/ch10-hook.xml:1289 msgid "Sources of changesets" msgstr "修改集的来源" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch10-hook.xml:1291 msgid "" "Mercurial will tell a hook what means are, or were, used to transfer " "changesets between repositories. This is provided by Mercurial in a Python " "parameter named <literal>source</literal>, or an environment variable named " "<envar>HG_SOURCE</envar>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:1299 msgid "" "<literal>serve</literal>: Changesets are transferred to or from a remote " "repository over http or ssh." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:1304 msgid "" "<literal>pull</literal>: Changesets are being transferred via a pull from one " "repository into another." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:1309 msgid "" "<literal>push</literal>: Changesets are being transferred via a push from one " "repository into another." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:1314 msgid "" "<literal>bundle</literal>: Changesets are being transferred to or from a " "bundle." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><title> #: ../en/ch10-hook.xml:1321 msgid "Where changes are going&emdash;remote repository URLs" msgstr "修改集要到哪里—远程版本库的地址" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch10-hook.xml:1324 msgid "" "When possible, Mercurial will tell a hook the location of the <quote>far " "side</quote> of an activity that transfers changeset data between " "repositories. This is provided by Mercurial in a Python parameter named " "<literal>url</literal>, or an environment variable named <envar>HG_URL</" "envar>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><para> #: ../en/ch10-hook.xml:1332 msgid "" "This information is not always known. If a hook is invoked in a repository " "that is being served via http or ssh, Mercurial cannot tell where the remote " "repository is, but it may know where the client is connecting from. In such " "cases, the URL will take one of the following forms:" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:1339 msgid "" "<literal>remote:ssh:1.2.3.4</literal>&emdash;remote ssh client, at the IP " "address <literal>1.2.3.4</literal>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:1344 msgid "" "<literal>remote:http:1.2.3.4</literal>&emdash;remote http client, at the IP " "address <literal>1.2.3.4</literal>. If the client is using SSL, this will be " "of the form <literal>remote:https:1.2.3.4</literal>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><sect3><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:1351 msgid "Empty&emdash;no information could be discovered about the remote client." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch10-hook.xml:1359 msgid "Hook reference" msgstr "钩子参考" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch10-hook.xml:1362 msgid "" "<literal role=\"hook\">changegroup</literal>&emdash;after remote changesets " "added" msgstr "<literal role=\"hook\">changegroup</literal>—增加远程修改集之后" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1365 msgid "" "This hook is run after a group of pre-existing changesets has been added to " "the repository, for example via a <command role=\"hg-cmd\">hg pull</command> " "or <command role=\"hg-cmd\">hg unbundle</command>. This hook is run once per " "operation that added one or more changesets. This is in contrast to the " "<literal role=\"hook\">incoming</literal> hook, which is run once per " "changeset, regardless of whether the changesets arrive in a group." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1375 msgid "" "Some possible uses for this hook include kicking off an automated build or " "test of the added changesets, updating a bug database, or notifying " "subscribers that a repository contains new changes." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1381 ../en/ch10-hook.xml:1421 ../en/ch10-hook.xml:1465 #: ../en/ch10-hook.xml:1507 ../en/ch10-hook.xml:1562 ../en/ch10-hook.xml:1602 #: ../en/ch10-hook.xml:1638 ../en/ch10-hook.xml:1672 ../en/ch10-hook.xml:1736 #: ../en/ch10-hook.xml:1794 ../en/ch10-hook.xml:1830 ../en/ch10-hook.xml:1857 msgid "Parameters to this hook:" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:1384 ../en/ch10-hook.xml:1739 msgid "" "<literal>node</literal>: A changeset ID. The changeset ID of the first " "changeset in the group that was added. All changesets between this and " "<literal role=\"tag\">tip</literal>, inclusive, were added by a single " "<command role=\"hg-cmd\">hg pull</command>, <command role=\"hg-cmd\">hg push</" "command> or <command role=\"hg-cmd\">hg unbundle</command>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:1393 ../en/ch10-hook.xml:1472 ../en/ch10-hook.xml:1565 #: ../en/ch10-hook.xml:1749 msgid "" "<literal>source</literal>: A string. The source of these changes. See <xref " "linkend=\"sec:hook:sources\"/> for details." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:1398 ../en/ch10-hook.xml:1477 ../en/ch10-hook.xml:1528 #: ../en/ch10-hook.xml:1570 ../en/ch10-hook.xml:1651 ../en/ch10-hook.xml:1754 msgid "" "<literal>url</literal>: A URL. The location of the remote repository, if " "known. See <xref linkend=\"sec:hook:url\"/> for more information." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1404 msgid "" "See also: <literal role=\"hook\">incoming</literal> (<xref linkend=\"sec:hook:" "incoming\"/>), <literal role=\"hook\">prechangegroup</literal> (<xref linkend=" "\"sec:hook:prechangegroup\"/>), <literal role=\"hook\">pretxnchangegroup</" "literal> (<xref linkend=\"sec:hook:pretxnchangegroup\"/>)" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch10-hook.xml:1415 msgid "" "<literal role=\"hook\">commit</literal>&emdash;after a new changeset is " "created" msgstr "<literal role=\"hook\">commit</literal>—创建新修改集之后" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1418 msgid "This hook is run after a new changeset has been created." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:1424 ../en/ch10-hook.xml:1797 msgid "" "<literal>node</literal>: A changeset ID. The changeset ID of the newly " "committed changeset." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:1428 ../en/ch10-hook.xml:1801 msgid "" "<literal>parent1</literal>: A changeset ID. The changeset ID of the first " "parent of the newly committed changeset." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:1433 ../en/ch10-hook.xml:1806 msgid "" "<literal>parent2</literal>: A changeset ID. The changeset ID of the second " "parent of the newly committed changeset." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1439 msgid "" "See also: <literal role=\"hook\">precommit</literal> (<xref linkend=\"sec:" "hook:precommit\"/>), <literal role=\"hook\">pretxncommit</literal> (<xref " "linkend=\"sec:hook:pretxncommit\"/>)" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch10-hook.xml:1448 msgid "" "<literal role=\"hook\">incoming</literal>&emdash;after one remote changeset " "is added" msgstr "<literal role=\"hook\">incoming</literal>—增加远程修改集之后" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1451 msgid "" "This hook is run after a pre-existing changeset has been added to the " "repository, for example via a <command role=\"hg-cmd\">hg push</command>. If " "a group of changesets was added in a single operation, this hook is called " "once for each added changeset." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1458 msgid "" "You can use this hook for the same purposes as the <literal role=\"hook" "\">changegroup</literal> hook (<xref linkend=\"sec:hook:changegroup\"/>); " "it's simply more convenient sometimes to run a hook once per group of " "changesets, while other times it's handier once per changeset." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:1468 msgid "" "<literal>node</literal>: A changeset ID. The ID of the newly added changeset." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1483 msgid "" "See also: <literal role=\"hook\">changegroup</literal> (<xref linkend=\"sec:" "hook:changegroup\"/>) <literal role=\"hook\">prechangegroup</literal> (<xref " "linkend=\"sec:hook:prechangegroup\"/>), <literal role=\"hook" "\">pretxnchangegroup</literal> (<xref linkend=\"sec:hook:pretxnchangegroup\"/" ">)" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch10-hook.xml:1494 msgid "" "<literal role=\"hook\">outgoing</literal>&emdash;after changesets are " "propagated" msgstr "<literal role=\"hook\">outgoing</literal>—传播修改集之后" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1497 msgid "" "This hook is run after a group of changesets has been propagated out of this " "repository, for example by a <command role=\"hg-cmd\">hg push</command> or " "<command role=\"hg-cmd\">hg bundle</command> command." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1503 msgid "" "One possible use for this hook is to notify administrators that changes have " "been pulled." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:1510 msgid "" "<literal>node</literal>: A changeset ID. The changeset ID of the first " "changeset of the group that was sent." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:1515 msgid "" "<literal>source</literal>: A string. The source of the of the operation (see " "<xref linkend=\"sec:hook:sources\"/>). If a remote client pulled changes " "from this repository, <literal>source</literal> will be <literal>serve</" "literal>. If the client that obtained changes from this repository was " "local, <literal>source</literal> will be <literal>bundle</literal>, " "<literal>pull</literal>, or <literal>push</literal>, depending on the " "operation the client performed." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1534 msgid "" "See also: <literal role=\"hook\">preoutgoing</literal> (<xref linkend=\"sec:" "hook:preoutgoing\"/>)" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch10-hook.xml:1541 msgid "" "<literal role=\"hook\">prechangegroup</literal>&emdash;before starting to add " "remote changesets" msgstr "<literal role=\"hook\">prechangegroup</literal>—增加远程修改集之前" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1545 msgid "" "This controlling hook is run before Mercurial begins to add a group of " "changesets from another repository." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1549 msgid "" "This hook does not have any information about the changesets to be added, " "because it is run before transmission of those changesets is allowed to " "begin. If this hook fails, the changesets will not be transmitted." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1555 msgid "" "One use for this hook is to prevent external changes from being added to a " "repository. For example, you could use this to <quote>freeze</quote> a " "server-hosted branch temporarily or permanently so that users cannot push to " "it, while still allowing a local administrator to modify the repository." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1576 msgid "" "See also: <literal role=\"hook\">changegroup</literal> (<xref linkend=\"sec:" "hook:changegroup\"/>), <literal role=\"hook\">incoming</literal> (<xref " "linkend=\"sec:hook:incoming\"/>), <literal role=\"hook\">pretxnchangegroup</" "literal> (<xref linkend=\"sec:hook:pretxnchangegroup\"/>)" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch10-hook.xml:1587 msgid "" "<literal role=\"hook\">precommit</literal>&emdash;before starting to commit a " "changeset" msgstr "<literal role=\"hook\">precommit</literal>—提交修改集之前" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1590 msgid "" "This hook is run before Mercurial begins to commit a new changeset. It is run " "before Mercurial has any of the metadata for the commit, such as the files to " "be committed, the commit message, or the commit date." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1596 msgid "" "One use for this hook is to disable the ability to commit new changesets, " "while still allowing incoming changesets. Another is to run a build or test, " "and only allow the commit to begin if the build or test succeeds." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:1605 msgid "" "<literal>parent1</literal>: A changeset ID. The changeset ID of the first " "parent of the working directory." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:1610 msgid "" "<literal>parent2</literal>: A changeset ID. The changeset ID of the second " "parent of the working directory." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1615 msgid "" "If the commit proceeds, the parents of the working directory will become the " "parents of the new changeset." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1619 msgid "" "See also: <literal role=\"hook\">commit</literal> (<xref linkend=\"sec:hook:" "commit\"/>), <literal role=\"hook\">pretxncommit</literal> (<xref linkend=" "\"sec:hook:pretxncommit\"/>)" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch10-hook.xml:1627 msgid "" "<literal role=\"hook\">preoutgoing</literal>&emdash;before starting to " "propagate changesets" msgstr "<literal role=\"hook\">preoutgoing</literal>—传播修改集之前" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1630 msgid "" "This hook is invoked before Mercurial knows the identities of the changesets " "to be transmitted." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1634 msgid "" "One use for this hook is to prevent changes from being transmitted to another " "repository." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:1641 msgid "" "<literal>source</literal>: A string. The source of the operation that is " "attempting to obtain changes from this repository (see <xref linkend=\"sec:" "hook:sources\"/>). See the documentation for the <literal>source</literal> " "parameter to the <literal role=\"hook\">outgoing</literal> hook, in <xref " "linkend=\"sec:hook:outgoing\"/>, for possible values of this parameter." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1657 msgid "" "See also: <literal role=\"hook\">outgoing</literal> (<xref linkend=\"sec:hook:" "outgoing\"/>)" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch10-hook.xml:1664 msgid "" "<literal role=\"hook\">pretag</literal>&emdash;before tagging a changeset" msgstr "<literal role=\"hook\">pretag</literal>—创建标签之前" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1667 msgid "" "This controlling hook is run before a tag is created. If the hook succeeds, " "creation of the tag proceeds. If the hook fails, the tag is not created." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:1675 msgid "" "<literal>local</literal>: A boolean. Whether the tag is local to this " "repository instance (i.e. stored in <filename role=\"special\">.hg/localtags</" "filename>) or managed by Mercurial (stored in <filename role=\"special\">." "hgtags</filename>)." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:1682 msgid "" "<literal>node</literal>: A changeset ID. The ID of the changeset to be " "tagged." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:1686 msgid "<literal>tag</literal>: A string. The name of the tag to be created." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1691 msgid "" "If the tag to be created is revision-controlled, the <literal role=\"hook" "\">precommit</literal> and <literal role=\"hook\">pretxncommit</literal> " "hooks (<xref linkend=\"sec:hook:commit\"/> and <xref linkend=\"sec:hook:" "pretxncommit\"/>) will also be run." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1699 msgid "" "See also: <literal role=\"hook\">tag</literal> (<xref linkend=\"sec:hook:tag" "\"/>)" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch10-hook.xml:1705 msgid "" "<literal role=\"hook\">pretxnchangegroup</literal>&emdash;before completing " "addition of remote changesets" msgstr "" "<literal role=\"hook\">pretxnchangegroup</literal>—完成增加远程修改集之前" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1709 msgid "" "This controlling hook is run before a transaction&emdash;that manages the " "addition of a group of new changesets from outside the repository&emdash;" "completes. If the hook succeeds, the transaction completes, and all of the " "changesets become permanent within this repository. If the hook fails, the " "transaction is rolled back, and the data for the changesets is erased." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1718 msgid "" "This hook can access the metadata associated with the almost-added " "changesets, but it should not do anything permanent with this data. It must " "also not modify the working directory." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1724 msgid "" "While this hook is running, if other Mercurial processes access this " "repository, they will be able to see the almost-added changesets as if they " "are permanent. This may lead to race conditions if you do not take steps to " "avoid them." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1731 msgid "" "This hook can be used to automatically vet a group of changesets. If the " "hook fails, all of the changesets are <quote>rejected</quote> when the " "transaction rolls back." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1760 msgid "" "See also: <literal role=\"hook\">changegroup</literal> (<xref linkend=\"sec:" "hook:changegroup\"/>), <literal role=\"hook\">incoming</literal> (<xref " "linkend=\"sec:hook:incoming\"/>), <literal role=\"hook\">prechangegroup</" "literal> (<xref linkend=\"sec:hook:prechangegroup\"/>)" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch10-hook.xml:1771 msgid "" "<literal role=\"hook\">pretxncommit</literal>&emdash;before completing commit " "of new changeset" msgstr "<literal role=\"hook\">pretxncommit</literal>—完成提交之前" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1774 msgid "" "This controlling hook is run before a transaction&emdash;that manages a new " "commit&emdash;completes. If the hook succeeds, the transaction completes and " "the changeset becomes permanent within this repository. If the hook fails, " "the transaction is rolled back, and the commit data is erased." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1782 msgid "" "This hook can access the metadata associated with the almost-new changeset, " "but it should not do anything permanent with this data. It must also not " "modify the working directory." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1788 msgid "" "While this hook is running, if other Mercurial processes access this " "repository, they will be able to see the almost-new changeset as if it is " "permanent. This may lead to race conditions if you do not take steps to " "avoid them." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1812 msgid "" "See also: <literal role=\"hook\">precommit</literal> (<xref linkend=\"sec:" "hook:precommit\"/>)" msgstr "" "参见: <literal role=\"hook\">precommit</literal> (<xref linkend=\"sec:hook:" "precommit\"/>)" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch10-hook.xml:1819 msgid "" "<literal role=\"hook\">preupdate</literal>&emdash;before updating or merging " "working directory" msgstr "<literal role=\"hook\">preupdate</literal>—更新或合并工作目录之前" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1822 msgid "" "This controlling hook is run before an update or merge of the working " "directory begins. It is run only if Mercurial's normal pre-update checks " "determine that the update or merge can proceed. If the hook succeeds, the " "update or merge may proceed; if it fails, the update or merge does not start." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:1833 msgid "" "<literal>parent1</literal>: A changeset ID. The ID of the parent that the " "working directory is to be updated to. If the working directory is being " "merged, it will not change this parent." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:1839 msgid "" "<literal>parent2</literal>: A changeset ID. Only set if the working directory " "is being merged. The ID of the revision that the working directory is being " "merged with." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1846 msgid "" "See also: <literal role=\"hook\">update</literal> (<xref linkend=\"sec:hook:" "update\"/>)" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch10-hook.xml:1851 msgid "<literal role=\"hook\">tag</literal>&emdash;after tagging a changeset" msgstr "<literal role=\"hook\">tag</literal>—创建标签之后" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1854 msgid "This hook is run after a tag has been created." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:1860 msgid "" "<literal>local</literal>: A boolean. Whether the new tag is local to this " "repository instance (i.e. stored in <filename role=\"special\">.hg/" "localtags</filename>) or managed by Mercurial (stored in <filename role=" "\"special\">.hgtags</filename>)." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:1868 msgid "" "<literal>node</literal>: A changeset ID. The ID of the changeset that was " "tagged." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:1872 msgid "<literal>tag</literal>: A string. The name of the tag that was created." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1877 msgid "" "If the created tag is revision-controlled, the <literal role=\"hook\">commit</" "literal> hook (section <xref linkend=\"sec:hook:commit\"/>) is run before " "this hook." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1882 msgid "" "See also: <literal role=\"hook\">pretag</literal> (<xref linkend=\"sec:hook:" "pretag\"/>)" msgstr "" "参见: <literal role=\"hook\">pretag</literal> (<xref linkend=\"sec:hook:pretag" "\"/>)" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch10-hook.xml:1888 msgid "" "<literal role=\"hook\">update</literal>&emdash;after updating or merging " "working directory" msgstr "<literal role=\"hook\">update</literal>—更新或合并工作目录之后" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1891 msgid "" "This hook is run after an update or merge of the working directory " "completes. Since a merge can fail (if the external <command>hgmerge</" "command> command fails to resolve conflicts in a file), this hook " "communicates whether the update or merge completed cleanly." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:1899 msgid "" "<literal>error</literal>: A boolean. Indicates whether the update or merge " "completed successfully." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:1904 msgid "" "<literal>parent1</literal>: A changeset ID. The ID of the parent that the " "working directory was updated to. If the working directory was merged, it " "will not have changed this parent." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch10-hook.xml:1910 msgid "" "<literal>parent2</literal>: A changeset ID. Only set if the working " "directory was merged. The ID of the revision that the working directory was " "merged with." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch10-hook.xml:1916 msgid "" "See also: <literal role=\"hook\">preupdate</literal> (<xref linkend=\"sec:" "hook:preupdate\"/>)" msgstr "" #. type: Content of: <book><chapter><title> #: ../en/ch11-template.xml:5 msgid "Customizing the output of Mercurial" msgstr "定制 Mercurial 的输出" #. type: Content of: <book><chapter><para> #: ../en/ch11-template.xml:7 msgid "" "Mercurial provides a powerful mechanism to let you control how it displays " "information. The mechanism is based on templates. You can use templates to " "generate specific output for a single command, or to customize the entire " "appearance of the built-in web interface." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch11-template.xml:14 msgid "Using precanned output styles" msgstr "使用预定义的输出样式" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch11-template.xml:16 msgid "" "Packaged with Mercurial are some output styles that you can use immediately. " "A style is simply a precanned template that someone wrote and installed " "somewhere that Mercurial can find." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch11-template.xml:21 msgid "" "Before we take a look at Mercurial's bundled styles, let's review its normal " "output." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch11-template.xml:26 msgid "" "This is somewhat informative, but it takes up a lot of space&emdash;five " "lines of output per changeset. The <literal>compact</literal> style reduces " "this to three lines, presented in a sparse manner." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch11-template.xml:33 msgid "" "The <literal>changelog</literal> style hints at the expressive power of " "Mercurial's templating engine. This style attempts to follow the GNU " "Project's changelog guidelines<citation>web:changelog</citation>." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch11-template.xml:40 msgid "" "You will not be shocked to learn that Mercurial's default output style is " "named <literal>default</literal>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch11-template.xml:44 msgid "Setting a default style" msgstr "设置默认样式" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch11-template.xml:46 msgid "" "You can modify the output style that Mercurial will use for every command by " "editing your <filename role=\"special\">~/.hgrc</filename> file, naming the " "style you would prefer to use." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch11-template.xml:54 msgid "" "If you write a style of your own, you can use it by either providing the path " "to your style file, or copying your style file into a location where " "Mercurial can find it (typically the <literal>templates</literal> " "subdirectory of your Mercurial install directory)." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch11-template.xml:63 msgid "Commands that support styles and templates" msgstr "支持样式和模版的命令" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch11-template.xml:65 msgid "" "All of Mercurial's <quote><literal>log</literal>-like</quote> commands let " "you use styles and templates: <command role=\"hg-cmd\">hg incoming</command>, " "<command role=\"hg-cmd\">hg log</command>, <command role=\"hg-cmd\">hg " "outgoing</command>, and <command role=\"hg-cmd\">hg tip</command>." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch11-template.xml:72 msgid "" "As I write this manual, these are so far the only commands that support " "styles and templates. Since these are the most important commands that need " "customizable output, there has been little pressure from the Mercurial user " "community to add style and template support to other commands." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch11-template.xml:80 msgid "The basics of templating" msgstr "模版基础" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch11-template.xml:82 msgid "" "At its simplest, a Mercurial template is a piece of text. Some of the text " "never changes, while other parts are <emphasis>expanded</emphasis>, or " "replaced with new text, when necessary." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch11-template.xml:87 msgid "" "Before we continue, let's look again at a simple example of Mercurial's " "normal output." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch11-template.xml:92 msgid "" "Now, let's run the same command, but using a template to change its output." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch11-template.xml:97 msgid "" "The example above illustrates the simplest possible template; it's just a " "piece of static text, printed once for each changeset. The <option role=\"hg-" "opt-log\">--template</option> option to the <command role=\"hg-cmd\">hg log</" "command> command tells Mercurial to use the given text as the template when " "printing each changeset." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch11-template.xml:105 msgid "" "Notice that the template string above ends with the text <quote><literal>\\n</" "literal></quote>. This is an <emphasis>escape sequence</emphasis>, telling " "Mercurial to print a newline at the end of each template item. If you omit " "this newline, Mercurial will run each piece of output together. See <xref " "linkend=\"sec:template:escape\"/> for more details of escape sequences." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch11-template.xml:113 msgid "" "A template that prints a fixed string of text all the time isn't very useful; " "let's try something a bit more complex." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch11-template.xml:119 msgid "" "As you can see, the string <quote><literal>{desc}</literal></quote> in the " "template has been replaced in the output with the description of each " "changeset. Every time Mercurial finds text enclosed in curly braces " "(<quote><literal>{</literal></quote> and <quote><literal>}</literal></" "quote>), it will try to replace the braces and text with the expansion of " "whatever is inside. To print a literal curly brace, you must escape it, as " "described in <xref linkend=\"sec:template:escape\"/>." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch11-template.xml:131 msgid "Common template keywords" msgstr "模版关键字" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch11-template.xml:133 msgid "" "You can start writing simple templates immediately using the keywords below." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch11-template.xml:137 msgid "" "<literal role=\"template-keyword\">author</literal>: String. The unmodified " "author of the changeset." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch11-template.xml:141 msgid "" "<literal role=\"template-keyword\">branches</literal>: String. The name of " "the branch on which the changeset was committed. Will be empty if the branch " "name was <literal>default</literal>." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch11-template.xml:147 msgid "" "<literal role=\"template-keyword\">date</literal>: Date information. The " "date when the changeset was committed. This is <emphasis>not</emphasis> " "human-readable; you must pass it through a filter that will render it " "appropriately. See <xref linkend=\"sec:template:filter\"/> for more " "information on filters. The date is expressed as a pair of numbers. The " "first number is a Unix UTC timestamp (seconds since January 1, 1970); the " "second is the offset of the committer's timezone from UTC, in seconds." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch11-template.xml:158 msgid "" "<literal role=\"template-keyword\">desc</literal>: String. The text of the " "changeset description." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch11-template.xml:161 msgid "" "<literal role=\"template-keyword\">files</literal>: List of strings. All " "files modified, added, or removed by this changeset." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch11-template.xml:166 msgid "" "<literal role=\"template-keyword\">file_adds</literal>: List of strings. " "Files added by this changeset." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch11-template.xml:170 msgid "" "<literal role=\"template-keyword\">file_dels</literal>: List of strings. " "Files removed by this changeset." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch11-template.xml:174 msgid "" "<literal role=\"template-keyword\">node</literal>: String. The changeset " "identification hash, as a 40-character hexadecimal string." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch11-template.xml:178 msgid "" "<literal role=\"template-keyword\">parents</literal>: List of strings. The " "parents of the changeset." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch11-template.xml:182 msgid "" "<literal role=\"template-keyword\">rev</literal>: Integer. The repository-" "local changeset revision number." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch11-template.xml:186 msgid "" "<literal role=\"template-keyword\">tags</literal>: List of strings. Any tags " "associated with the changeset." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch11-template.xml:192 msgid "" "A few simple experiments will show us what to expect when we use these " "keywords; you can see the results below." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch11-template.xml:197 msgid "" "As we noted above, the date keyword does not produce human-readable output, " "so we must treat it specially. This involves using a <emphasis>filter</" "emphasis>, about which more in <xref linkend=\"sec:template:filter\"/>." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch11-template.xml:206 msgid "Escape sequences" msgstr "转义序列" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch11-template.xml:208 msgid "" "Mercurial's templating engine recognises the most commonly used escape " "sequences in strings. When it sees a backslash (<quote><literal>\\</" "literal></quote>) character, it looks at the following character and " "substitutes the two characters with a single replacement, as described below." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch11-template.xml:215 msgid "" "<literal>\\</literal>: Backslash, <quote><literal>\\</literal></quote>, ASCII " "134." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch11-template.xml:219 msgid "<literal>\\n</literal>: Newline, ASCII 12." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch11-template.xml:222 msgid "<literal>\\r</literal>: Carriage return, ASCII 15." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch11-template.xml:225 msgid "<literal>\\t</literal>: Tab, ASCII 11." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch11-template.xml:228 msgid "<literal>\\v</literal>: Vertical tab, ASCII 13." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch11-template.xml:231 msgid "" "<literal>\\{</literal>: Open curly brace, <quote><literal>{</literal></" "quote>, ASCII 173." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch11-template.xml:235 msgid "" "<literal>\\}</literal>: Close curly brace, <quote><literal>}</literal></" "quote>, ASCII 175." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch11-template.xml:240 msgid "" "As indicated above, if you want the expansion of a template to contain a " "literal <quote><literal>\\</literal></quote>, <quote><literal>{</literal></" "quote>, or <quote><literal>{</literal></quote> character, you must escape it." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch11-template.xml:248 msgid "Filtering keywords to change their results" msgstr "通过过滤关键字来修改输出结果" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch11-template.xml:250 msgid "" "Some of the results of template expansion are not immediately easy to use. " "Mercurial lets you specify an optional chain of <emphasis>filters</emphasis> " "to modify the result of expanding a keyword. You have already seen a common " "filter, <literal role=\"template-kw-filt-date\">isodate</literal>, in action " "above, to make a date readable." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch11-template.xml:257 msgid "" "Below is a list of the most commonly used filters that Mercurial supports. " "While some filters can be applied to any text, others can only be used in " "specific circumstances. The name of each filter is followed first by an " "indication of where it can be used, then a description of its effect." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch11-template.xml:264 msgid "" "<literal role=\"template-filter\">addbreaks</literal>: Any text. Add an XHTML " "<quote><literal><br/></literal></quote> tag before the end of every " "line except the last. For example, <quote><literal>foo\\nbar</literal></" "quote> becomes <quote><literal>foo<br/>\\nbar</literal></quote>." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch11-template.xml:271 msgid "" "<literal role=\"template-kw-filt-date\">age</literal>: <literal role=" "\"template-keyword\">date</literal> keyword. Render the age of the date, " "relative to the current time. Yields a string like <quote><literal>10 " "minutes</literal></quote>." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch11-template.xml:278 msgid "" "<literal role=\"template-filter\">basename</literal>: Any text, but most " "useful for the <literal role=\"template-keyword\">files</literal> keyword and " "its relatives. Treat the text as a path, and return the basename. For " "example, <quote><literal>foo/bar/baz</literal></quote> becomes " "<quote><literal>baz</literal></quote>." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch11-template.xml:287 msgid "" "<literal role=\"template-kw-filt-date\">date</literal>: <literal role=" "\"template-keyword\">date</literal> keyword. Render a date in a similar " "format to the Unix <literal role=\"template-keyword\">date</literal> command, " "but with timezone included. Yields a string like <quote><literal>Mon Sep 04 " "15:13:13 2006 -0700</literal></quote>." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch11-template.xml:295 msgid "" "<literal role=\"template-kw-filt-author\">domain</literal>: Any text, but " "most useful for the <literal role=\"template-keyword\">author</literal> " "keyword. Finds the first string that looks like an email address, and " "extract just the domain component. For example, <quote><literal>Bryan " "O'Sullivan <bos@serpentine.com></literal></quote> becomes " "<quote><literal>serpentine.com</literal></quote>." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch11-template.xml:305 msgid "" "<literal role=\"template-kw-filt-author\">email</literal>: Any text, but most " "useful for the <literal role=\"template-keyword\">author</literal> keyword. " "Extract the first string that looks like an email address. For example, " "<quote><literal>Bryan O'Sullivan <bos@serpentine.com></literal></quote> " "becomes <quote><literal>bos@serpentine.com</literal></quote>." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch11-template.xml:314 msgid "" "<literal role=\"template-filter\">escape</literal>: Any text. Replace the " "special XML/XHTML characters <quote><literal>&</literal></quote>, " "<quote><literal><</literal></quote> and <quote><literal>></literal></" "quote> with XML entities." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch11-template.xml:322 msgid "" "<literal role=\"template-filter\">fill68</literal>: Any text. Wrap the text " "to fit in 68 columns. This is useful before you pass text through the " "<literal role=\"template-filter\">tabindent</literal> filter, and still want " "it to fit in an 80-column fixed-font window." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch11-template.xml:330 msgid "" "<literal role=\"template-filter\">fill76</literal>: Any text. Wrap the text " "to fit in 76 columns." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch11-template.xml:334 msgid "" "<literal role=\"template-filter\">firstline</literal>: Any text. Yield the " "first line of text, without any trailing newlines." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch11-template.xml:339 msgid "" "<literal role=\"template-kw-filt-date\">hgdate</literal>: <literal role=" "\"template-keyword\">date</literal> keyword. Render the date as a pair of " "readable numbers. Yields a string like <quote><literal>1157407993 25200</" "literal></quote>." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch11-template.xml:346 msgid "" "<literal role=\"template-kw-filt-date\">isodate</literal>: <literal role=" "\"template-keyword\">date</literal> keyword. Render the date as a text " "string in ISO 8601 format. Yields a string like <quote><literal>2006-09-04 " "15:13:13 -0700</literal></quote>." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch11-template.xml:353 msgid "" "<literal role=\"template-filter\">obfuscate</literal>: Any text, but most " "useful for the <literal role=\"template-keyword\">author</literal> keyword. " "Yield the input text rendered as a sequence of XML entities. This helps to " "defeat some particularly stupid screen-scraping email harvesting spambots." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch11-template.xml:361 msgid "" "<literal role=\"template-kw-filt-author\">person</literal>: Any text, but " "most useful for the <literal role=\"template-keyword\">author</literal> " "keyword. Yield the text before an email address. For example, " "<quote><literal>Bryan O'Sullivan <bos@serpentine.com></literal></quote> " "becomes <quote><literal>Bryan O'Sullivan</literal></quote>." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch11-template.xml:370 msgid "" "<literal role=\"template-kw-filt-date\">rfc822date</literal>: <literal role=" "\"template-keyword\">date</literal> keyword. Render a date using the same " "format used in email headers. Yields a string like <quote><literal>Mon, 04 " "Sep 2006 15:13:13 -0700</literal></quote>." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch11-template.xml:377 msgid "" "<literal role=\"template-kw-filt-node\">short</literal>: Changeset hash. " "Yield the short form of a changeset hash, i.e. a 12-character hexadecimal " "string." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch11-template.xml:382 msgid "" "<literal role=\"template-kw-filt-date\">shortdate</literal>: <literal role=" "\"template-keyword\">date</literal> keyword. Render the year, month, and day " "of the date. Yields a string like <quote><literal>2006-09-04</literal></" "quote>." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch11-template.xml:388 msgid "" "<literal role=\"template-filter\">strip</literal>: Any text. Strip all " "leading and trailing whitespace from the string." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch11-template.xml:392 msgid "" "<literal role=\"template-filter\">tabindent</literal>: Any text. Yield the " "text, with every line except the first starting with a tab character." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch11-template.xml:397 msgid "" "<literal role=\"template-filter\">urlescape</literal>: Any text. Escape all " "characters that are considered <quote>special</quote> by URL parsers. For " "example, <literal>foo bar</literal> becomes <literal>foo%20bar</literal>." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch11-template.xml:404 msgid "" "<literal role=\"template-kw-filt-author\">user</literal>: Any text, but most " "useful for the <literal role=\"template-keyword\">author</literal> keyword. " "Return the <quote>user</quote> portion of an email address. For example, " "<quote><literal>Bryan O'Sullivan <bos@serpentine.com></literal></quote> " "becomes <quote><literal>bos</literal></quote>." msgstr "" #. type: Content of: <book><chapter><sect1><note><para> #: ../en/ch11-template.xml:418 msgid "" "If you try to apply a filter to a piece of data that it cannot process, " "Mercurial will fail and print a Python exception. For example, trying to run " "the output of the <literal role=\"template-keyword\">desc</literal> keyword " "into the <literal role=\"template-kw-filt-date\">isodate</literal> filter is " "not a good idea." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch11-template.xml:427 msgid "Combining filters" msgstr "组合过滤器" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch11-template.xml:429 msgid "" "It is easy to combine filters to yield output in the form you would like. " "The following chain of filters tidies up a description, then makes sure that " "it fits cleanly into 68 columns, then indents it by a further 8 characters " "(at least on Unix-like systems, where a tab is conventionally 8 characters " "wide)." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch11-template.xml:438 msgid "" "Note the use of <quote><literal>\\t</literal></quote> (a tab character) in " "the template to force the first line to be indented; this is necessary since " "<literal role=\"template-keyword\">tabindent</literal> indents all lines " "<emphasis>except</emphasis> the first." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch11-template.xml:444 msgid "" "Keep in mind that the order of filters in a chain is significant. The first " "filter is applied to the result of the keyword; the second to the result of " "the first filter; and so on. For example, using <literal>fill68|tabindent</" "literal> gives very different results from <literal>tabindent|fill68</" "literal>." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch11-template.xml:454 msgid "From templates to styles" msgstr "从模版到样式" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch11-template.xml:456 msgid "" "A command line template provides a quick and simple way to format some " "output. Templates can become verbose, though, and it's useful to be able to " "give a template a name. A style file is a template with a name, stored in a " "file." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch11-template.xml:461 msgid "" "More than that, using a style file unlocks the power of Mercurial's " "templating engine in ways that are not possible using the command line " "<option role=\"hg-opt-log\">--template</option> option." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch11-template.xml:467 msgid "The simplest of style files" msgstr "最简单的样式文件" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch11-template.xml:469 msgid "Our simple style file contains just one line:" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch11-template.xml:473 msgid "" "This tells Mercurial, <quote>if you're printing a changeset, use the text on " "the right as the template</quote>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch11-template.xml:479 msgid "Style file syntax" msgstr "样式文件语法" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch11-template.xml:481 msgid "The syntax rules for a style file are simple." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch11-template.xml:484 msgid "The file is processed one line at a time." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch11-template.xml:487 msgid "Leading and trailing white space are ignored." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch11-template.xml:490 msgid "Empty lines are skipped." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch11-template.xml:492 msgid "" "If a line starts with either of the characters <quote><literal>#</literal></" "quote> or <quote><literal>;</literal></quote>, the entire line is treated as " "a comment, and skipped as if empty." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch11-template.xml:497 msgid "" "A line starts with a keyword. This must start with an alphabetic character " "or underscore, and can subsequently contain any alphanumeric character or " "underscore. (In regexp notation, a keyword must match <literal>[A-Za-z_][A-" "Za-z0-9_]*</literal>.)" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch11-template.xml:503 msgid "" "The next element must be an <quote><literal>=</literal></quote> character, " "which can be preceded or followed by an arbitrary amount of white space." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch11-template.xml:508 msgid "" "If the rest of the line starts and ends with matching quote characters " "(either single or double quote), it is treated as a template body." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch11-template.xml:512 msgid "" "If the rest of the line <emphasis>does not</emphasis> start with a quote " "character, it is treated as the name of a file; the contents of this file " "will be read and used as a template body." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch11-template.xml:521 msgid "Style files by example" msgstr "样式文件例子" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch11-template.xml:523 msgid "" "To illustrate how to write a style file, we will construct a few by example. " "Rather than provide a complete style file and walk through it, we'll mirror " "the usual process of developing a style file by starting with something very " "simple, and walking through a series of successively more complete examples." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch11-template.xml:530 msgid "Identifying mistakes in style files" msgstr "在样式文件中定位错误" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch11-template.xml:532 msgid "" "If Mercurial encounters a problem in a style file you are working on, it " "prints a terse error message that, once you figure out what it means, is " "actually quite useful." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch11-template.xml:538 msgid "" "Notice that <filename>broken.style</filename> attempts to define a " "<literal>changeset</literal> keyword, but forgets to give any content for it. " "When instructed to use this style file, Mercurial promptly complains." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch11-template.xml:545 msgid "This error message looks intimidating, but it is not too hard to follow." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch11-template.xml:549 msgid "" "The first component is simply Mercurial's way of saying <quote>I am giving " "up</quote>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch11-template.xml:553 msgid "Next comes the name of the style file that contains the error." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch11-template.xml:557 msgid "" "Following the file name is the line number where the error was encountered." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch11-template.xml:561 msgid "Finally, a description of what went wrong." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch11-template.xml:565 msgid "" "The description of the problem is not always clear (as in this case), but " "even when it is cryptic, it is almost always trivial to visually inspect the " "offending line in the style file and see what is wrong." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch11-template.xml:574 msgid "Uniquely identifying a repository" msgstr "版本库的唯一标识" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch11-template.xml:576 msgid "" "If you would like to be able to identify a Mercurial repository <quote>fairly " "uniquely</quote> using a short string as an identifier, you can use the first " "revision in the repository." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch11-template.xml:583 msgid "" "This is likely to be unique, and so it is useful in many cases. There are a " "few caveats." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch11-template.xml:586 msgid "" "It will not work in a completely empty repository, because such a repository " "does not have a revision zero." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch11-template.xml:590 msgid "" "Neither will it work in the (extremely rare) case where a repository is a " "merge of two or more formerly independent repositories, and you still have " "those repositories around." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch11-template.xml:595 msgid "Here are some uses to which you could put this identifier:" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch11-template.xml:598 msgid "" "As a key into a table for a database that manages repositories on a server." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch11-template.xml:601 msgid "" "As half of a {<emphasis>repository ID</emphasis>, <emphasis>revision ID</" "emphasis>} tuple. Save this information away when you run an automated build " "or other activity, so that you can <quote>replay</quote> the build later if " "necessary." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch11-template.xml:611 msgid "Listing files on multiple lines" msgstr "每行列出一个文件" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch11-template.xml:613 msgid "" "Suppose we want to list the files changed by a changeset, one per line, with " "a little indentation before each file name." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch11-template.xml:621 msgid "Mimicking Subversion's output" msgstr "模仿 Subversion 的输出" # #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch11-template.xml:623 msgid "" "Let's try to emulate the default output format used by another revision " "control tool, Subversion." msgstr "" # #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch11-template.xml:628 msgid "" "Since Subversion's output style is fairly simple, it is easy to copy-and-" "paste a hunk of its output into a file, and replace the text produced above " "by Subversion with the template values we'd like to see expanded." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch11-template.xml:635 msgid "" "There are a few small ways in which this template deviates from the output " "produced by Subversion." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch11-template.xml:638 msgid "" "Subversion prints a <quote>readable</quote> date (the <quote><literal>Wed, 27 " "Sep 2006</literal></quote> in the example output above) in parentheses. " "Mercurial's templating engine does not provide a way to display a date in " "this format without also printing the time and time zone." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch11-template.xml:645 msgid "" "We emulate Subversion's printing of <quote>separator</quote> lines full of " "<quote><literal>-</literal></quote> characters by ending the template with " "such a line. We use the templating engine's <literal role=\"template-keyword" "\">header</literal> keyword to print a separator line as the first line of " "output (see below), thus achieving similar output to Subversion." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch11-template.xml:654 msgid "" "Subversion's output includes a count in the header of the number of lines in " "the commit message. We cannot replicate this in Mercurial; the templating " "engine does not currently provide a filter that counts the number of lines " "the template generates." msgstr "" # #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch11-template.xml:660 msgid "" "It took me no more than a minute or two of work to replace literal text from " "an example of Subversion's output with some keywords and filters to give the " "template above. The style file simply refers to the template." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch11-template.xml:667 msgid "" "We could have included the text of the template file directly in the style " "file by enclosing it in quotes and replacing the newlines with " "<quote><literal>\\n</literal></quote> sequences, but it would have made the " "style file too difficult to read. Readability is a good guide when you're " "trying to decide whether some text belongs in a style file, or in a template " "file that the style file points to. If the style file will look too big or " "cluttered if you insert a literal piece of text, drop it into a template " "instead." msgstr "" #. type: Content of: <book><chapter><title> #: ../en/ch12-mq.xml:5 msgid "Managing change with Mercurial Queues" msgstr "使用 MQ 管理修改" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch12-mq.xml:8 msgid "The patch management problem" msgstr "补丁的管理问题" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:10 msgid "" "Here is a common scenario: you need to install a software package from " "source, but you find a bug that you must fix in the source before you can " "start using the package. You make your changes, forget about the package for " "a while, and a few months later you need to upgrade to a newer version of the " "package. If the newer version of the package still has the bug, you must " "extract your fix from the older source tree and apply it against the newer " "version. This is a tedious task, and it's easy to make mistakes." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:20 msgid "" "This is a simple case of the <quote>patch management</quote> problem. You " "have an <quote>upstream</quote> source tree that you can't change; you need " "to make some local changes on top of the upstream tree; and you'd like to be " "able to keep those changes separate, so that you can apply them to newer " "versions of the upstream source." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:27 msgid "" "The patch management problem arises in many situations. Probably the most " "visible is that a user of an open source software project will contribute a " "bug fix or new feature to the project's maintainers in the form of a patch." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:32 msgid "" "Distributors of operating systems that include open source software often " "need to make changes to the packages they distribute so that they will build " "properly in their environments." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:37 msgid "" "When you have few changes to maintain, it is easy to manage a single patch " "using the standard <command>diff</command> and <command>patch</command> " "programs (see <xref linkend=\"sec:mq:patch\"/> for a discussion of these " "tools). Once the number of changes grows, it starts to make sense to maintain " "patches as discrete <quote>chunks of work,</quote> so that for example a " "single patch will contain only one bug fix (the patch might modify several " "files, but it's doing <quote>only one thing</quote>), and you may have a " "number of such patches for different bugs you need fixed and local changes " "you require. In this situation, if you submit a bug fix patch to the " "upstream maintainers of a package and they include your fix in a subsequent " "release, you can simply drop that single patch when you're updating to the " "newer release." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:52 msgid "" "Maintaining a single patch against an upstream tree is a little tedious and " "error-prone, but not difficult. However, the complexity of the problem grows " "rapidly as the number of patches you have to maintain increases. With more " "than a tiny number of patches in hand, understanding which ones you have " "applied and maintaining them moves from messy to overwhelming." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:59 msgid "" "Fortunately, Mercurial includes a powerful extension, Mercurial Queues (or " "simply <quote>MQ</quote>), that massively simplifies the patch management " "problem." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch12-mq.xml:65 msgid "The prehistory of Mercurial Queues" msgstr "MQ 的历史" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:67 msgid "" "During the late 1990s, several Linux kernel developers started to maintain " "<quote>patch series</quote> that modified the behavior of the Linux kernel. " "Some of these series were focused on stability, some on feature coverage, and " "others were more speculative." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:73 msgid "" "The sizes of these patch series grew rapidly. In 2002, Andrew Morton " "published some shell scripts he had been using to automate the task of " "managing his patch queues. Andrew was successfully using these scripts to " "manage hundreds (sometimes thousands) of patches on top of the Linux kernel." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch12-mq.xml:80 msgid "A patchwork quilt" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:82 msgid "" "In early 2003, Andreas Gruenbacher and Martin Quinson borrowed the approach " "of Andrew's scripts and published a tool called <quote>patchwork quilt</" "quote> <citation>web:quilt</citation>, or simply <quote>quilt</quote> (see " "<citation>gruenbacher:2005</citation> for a paper describing it). Because " "quilt substantially automated patch management, it rapidly gained a large " "following among open source software developers." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:91 msgid "" "Quilt manages a <emphasis>stack of patches</emphasis> on top of a directory " "tree. To begin, you tell quilt to manage a directory tree, and tell it which " "files you want to manage; it stores away the names and contents of those " "files. To fix a bug, you create a new patch (using a single command), edit " "the files you need to fix, then <quote>refresh</quote> the patch." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:99 msgid "" "The refresh step causes quilt to scan the directory tree; it updates the " "patch with all of the changes you have made. You can create another patch on " "top of the first, which will track the changes required to modify the tree " "from <quote>tree with one patch applied</quote> to <quote>tree with two " "patches applied</quote>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:106 msgid "" "You can <emphasis>change</emphasis> which patches are applied to the tree. " "If you <quote>pop</quote> a patch, the changes made by that patch will vanish " "from the directory tree. Quilt remembers which patches you have popped, " "though, so you can <quote>push</quote> a popped patch again, and the " "directory tree will be restored to contain the modifications in the patch. " "Most importantly, you can run the <quote>refresh</quote> command at any time, " "and the topmost applied patch will be updated. This means that you can, at " "any time, change both which patches are applied and what modifications those " "patches make." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:118 msgid "" "Quilt knows nothing about revision control tools, so it works equally well on " "top of an unpacked tarball or a Subversion working copy." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch12-mq.xml:124 msgid "From patchwork quilt to Mercurial Queues" msgstr "从 patchwork quilt 到 MQ" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:126 msgid "" "In mid-2005, Chris Mason took the features of quilt and wrote an extension " "that he called Mercurial Queues, which added quilt-like behavior to Mercurial." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:130 msgid "" "The key difference between quilt and MQ is that quilt knows nothing about " "revision control systems, while MQ is <emphasis>integrated</emphasis> into " "Mercurial. Each patch that you push is represented as a Mercurial " "changeset. Pop a patch, and the changeset goes away." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:136 msgid "" "Because quilt does not care about revision control tools, it is still a " "tremendously useful piece of software to know about for situations where you " "cannot use Mercurial and MQ." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch12-mq.xml:144 msgid "The huge advantage of MQ" msgstr "MQ 的巨大优势" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:146 msgid "" "I cannot overstate the value that MQ offers through the unification of " "patches and revision control." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:149 msgid "" "A major reason that patches have persisted in the free software and open " "source world&emdash;in spite of the availability of increasingly capable " "revision control tools over the years&emdash;is the <emphasis>agility</" "emphasis> they offer." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:155 msgid "" "Traditional revision control tools make a permanent, irreversible record of " "everything that you do. While this has great value, it's also somewhat " "stifling. If you want to perform a wild-eyed experiment, you have to be " "careful in how you go about it, or you risk leaving unneeded&emdash;or worse, " "misleading or destabilising&emdash;traces of your missteps and errors in the " "permanent revision record." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:163 msgid "" "By contrast, MQ's marriage of distributed revision control with patches makes " "it much easier to isolate your work. Your patches live on top of normal " "revision history, and you can make them disappear or reappear at will. If " "you don't like a patch, you can drop it. If a patch isn't quite as you want " "it to be, simply fix it&emdash;as many times as you need to, until you have " "refined it into the form you desire." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:171 msgid "" "As an example, the integration of patches with revision control makes " "understanding patches and debugging their effects&emdash;and their interplay " "with the code they're based on&emdash;<emphasis>enormously</emphasis> easier. " "Since every applied patch has an associated changeset, you can give <command " "role=\"hg-cmd\">hg log</command> a file name to see which changesets and " "patches affected the file. You can use the <command role=\"hg-cmd\">hg " "bisect</command> command to binary-search through all changesets and applied " "patches to see where a bug got introduced or fixed. You can use the <command " "role=\"hg-cmd\">hg annotate</command> command to see which changeset or patch " "modified a particular line of a source file. And so on." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:189 msgid "" "Because MQ doesn't hide its patch-oriented nature, it is helpful to " "understand what patches are, and a little about the tools that work with them." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:193 msgid "" "The traditional Unix <command>diff</command> command compares two files, and " "prints a list of differences between them. The <command>patch</command> " "command understands these differences as <emphasis>modifications</emphasis> " "to make to a file. Take a look below for a simple example of these commands " "in action." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:202 msgid "" "The type of file that <command>diff</command> generates (and <command>patch</" "command> takes as input) is called a <quote>patch</quote> or a <quote>diff</" "quote>; there is no difference between a patch and a diff. (We'll use the " "term <quote>patch</quote>, since it's more commonly used.)" msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:208 msgid "" "A patch file can start with arbitrary text; the <command>patch</command> " "command ignores this text, but MQ uses it as the commit message when creating " "changesets. To find the beginning of the patch content, <command>patch</" "command> searches for the first line that starts with the string " "<quote><literal>diff -</literal></quote>." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:215 msgid "" "MQ works with <emphasis>unified</emphasis> diffs (<command>patch</command> " "can accept several other diff formats, but MQ doesn't). A unified diff " "contains two kinds of header. The <emphasis>file header</emphasis> describes " "the file being modified; it contains the name of the file to modify. When " "<command>patch</command> sees a new file header, it looks for a file with " "that name to start modifying." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:223 msgid "" "After the file header comes a series of <emphasis>hunks</emphasis>. Each " "hunk starts with a header; this identifies the range of line numbers within " "the file that the hunk should modify. Following the header, a hunk starts " "and ends with a few (usually three) lines of text from the unmodified file; " "these are called the <emphasis>context</emphasis> for the hunk. If there's " "only a small amount of context between successive hunks, <command>diff</" "command> doesn't print a new hunk header; it just runs the hunks together, " "with a few lines of context between modifications." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:235 msgid "" "Each line of context begins with a space character. Within the hunk, a line " "that begins with <quote><literal>-</literal></quote> means <quote>remove this " "line,</quote> while a line that begins with <quote><literal>+</literal></" "quote> means <quote>insert this line.</quote> For example, a line that is " "modified is represented by one deletion and one insertion." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:243 msgid "" "We will return to some of the more subtle aspects of patches later (in <xref " "linkend=\"sec:mq:adv-patch\"/>), but you should have enough information now " "to use MQ." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch12-mq.xml:250 msgid "Getting started with Mercurial Queues" msgstr "开始使用 MQ" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:252 msgid "" "Because MQ is implemented as an extension, you must explicitly enable before " "you can use it. (You don't need to download anything; MQ ships with the " "standard Mercurial distribution.) To enable MQ, edit your <filename role=" "\"home\">~/.hgrc</filename> file, and add the lines below." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:262 msgid "" "Once the extension is enabled, it will make a number of new commands " "available. To verify that the extension is working, you can use <command " "role=\"hg-cmd\">hg help</command> to see if the <command role=\"hg-ext-mq" "\">qinit</command> command is now available." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:270 msgid "" "You can use MQ with <emphasis>any</emphasis> Mercurial repository, and its " "commands only operate within that repository. To get started, simply prepare " "the repository using the <command role=\"hg-ext-mq\">qinit</command> command." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:277 msgid "" "This command creates an empty directory called <filename role=\"special\" " "class=\"directory\">.hg/patches</filename>, where MQ will keep its metadata. " "As with many Mercurial commands, the <command role=\"hg-ext-mq\">qinit</" "command> command prints nothing if it succeeds." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch12-mq.xml:284 msgid "Creating a new patch" msgstr "创建新补丁" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:286 msgid "" "To begin work on a new patch, use the <command role=\"hg-ext-mq\">qnew</" "command> command. This command takes one argument, the name of the patch to " "create." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:290 msgid "" "MQ will use this as the name of an actual file in the <filename role=\"special" "\" class=\"directory\">.hg/patches</filename> directory, as you can see below." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:297 msgid "" "Also newly present in the <filename role=\"special\" class=\"directory\">.hg/" "patches</filename> directory are two other files, <filename role=\"special" "\">series</filename> and <filename role=\"special\">status</filename>. The " "<filename role=\"special\">series</filename> file lists all of the patches " "that MQ knows about for this repository, with one patch per line. Mercurial " "uses the <filename role=\"special\">status</filename> file for internal book-" "keeping; it tracks all of the patches that MQ has <emphasis>applied</" "emphasis> in this repository." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><note><para> #: ../en/ch12-mq.xml:309 msgid "" "You may sometimes want to edit the <filename role=\"special\">series</" "filename> file by hand; for example, to change the sequence in which some " "patches are applied. However, manually editing the <filename role=\"special" "\">status</filename> file is almost always a bad idea, as it's easy to " "corrupt MQ's idea of what is happening." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:318 msgid "" "Once you have created your new patch, you can edit files in the working " "directory as you usually would. All of the normal Mercurial commands, such " "as <command role=\"hg-cmd\">hg diff</command> and <command role=\"hg-cmd\">hg " "annotate</command>, work exactly as they did before." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch12-mq.xml:326 msgid "Refreshing a patch" msgstr "刷新补丁" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:328 msgid "" "When you reach a point where you want to save your work, use the <command " "role=\"hg-ext-mq\">qrefresh</command> command to update the patch you are " "working on." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:334 msgid "" "This command folds the changes you have made in the working directory into " "your patch, and updates its corresponding changeset to contain those changes." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:338 msgid "" "You can run <command role=\"hg-ext-mq\">qrefresh</command> as often as you " "like, so it's a good way to <quote>checkpoint</quote> your work. Refresh " "your patch at an opportune time; try an experiment; and if the experiment " "doesn't work out, <command role=\"hg-cmd\">hg revert</command> your " "modifications back to the last time you refreshed." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch12-mq.xml:349 msgid "Stacking and tracking patches" msgstr "堆叠和跟踪补丁" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:351 msgid "" "Once you have finished working on a patch, or need to work on another, you " "can use the <command role=\"hg-ext-mq\">qnew</command> command again to " "create a new patch. Mercurial will apply this patch on top of your existing " "patch." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:359 msgid "" "Notice that the patch contains the changes in our prior patch as part of its " "context (you can see this more clearly in the output of <command role=\"hg-cmd" "\">hg annotate</command>)." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:364 msgid "" "So far, with the exception of <command role=\"hg-ext-mq\">qnew</command> and " "<command role=\"hg-ext-mq\">qrefresh</command>, we've been careful to only " "use regular Mercurial commands. However, MQ provides many commands that are " "easier to use when you are thinking about patches, as illustrated below." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch12-mq.xml:374 msgid "" "The <command role=\"hg-ext-mq\">qseries</command> command lists every patch " "that MQ knows about in this repository, from oldest to newest (most recently " "<emphasis>created</emphasis>)." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch12-mq.xml:380 msgid "" "The <command role=\"hg-ext-mq\">qapplied</command> command lists every patch " "that MQ has <emphasis>applied</emphasis> in this repository, again from " "oldest to newest (most recently applied)." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch12-mq.xml:389 msgid "Manipulating the patch stack" msgstr "操作补丁堆栈" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:391 msgid "" "The previous discussion implied that there must be a difference between " "<quote>known</quote> and <quote>applied</quote> patches, and there is. MQ " "can manage a patch without it being applied in the repository." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:396 msgid "" "An <emphasis>applied</emphasis> patch has a corresponding changeset in the " "repository, and the effects of the patch and changeset are visible in the " "working directory. You can undo the application of a patch using the " "<command role=\"hg-ext-mq\">qpop</command> command. MQ still <emphasis>knows " "about</emphasis>, or manages, a popped patch, but the patch no longer has a " "corresponding changeset in the repository, and the working directory does not " "contain the changes made by the patch. <xref linkend=\"fig:mq:stack\"/> " "illustrates the difference between applied and tracked patches." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><figure><title> #: ../en/ch12-mq.xml:409 msgid "Applied and unapplied patches in the MQ patch stack" msgstr "在 MQ 补丁堆栈中应用和撤销补丁" #. type: Content of: <book><chapter><sect1><sect2><figure><mediaobject> #: ../en/ch12-mq.xml:412 msgid "<imageobject><imagedata fileref=\"figs/mq-stack.png\"/></imageobject>" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:417 msgid "" "You can reapply an unapplied, or popped, patch using the <command role=\"hg-" "ext-mq\">qpush</command> command. This creates a new changeset to correspond " "to the patch, and the patch's changes once again become present in the " "working directory. See below for examples of <command role=\"hg-ext-mq" "\">qpop</command> and <command role=\"hg-ext-mq\">qpush</command> in action." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:427 msgid "" "Notice that once we have popped a patch or two patches, the output of " "<command role=\"hg-ext-mq\">qseries</command> remains the same, while that of " "<command role=\"hg-ext-mq\">qapplied</command> has changed." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch12-mq.xml:435 msgid "Pushing and popping many patches" msgstr "压入或弹出多个补丁" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:437 msgid "" "While <command role=\"hg-ext-mq\">qpush</command> and <command role=\"hg-ext-" "mq\">qpop</command> each operate on a single patch at a time by default, you " "can push and pop many patches in one go. The <option role=\"hg-ext-mq-cmd-" "qpush-opt\">-a</option> option to <command role=\"hg-ext-mq\">qpush</command> " "causes it to push all unapplied patches, while the <option role=\"hg-ext-mq-" "cmd-qpop-opt\">-a</option> option to <command role=\"hg-ext-mq\">qpop</" "command> causes it to pop all applied patches. (For some more ways to push " "and pop many patches, see <xref linkend=\"sec:mq:perf\"/> below.)" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch12-mq.xml:453 msgid "Safety checks, and overriding them" msgstr "安全的检查,然后覆盖它们" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:455 msgid "" "Several MQ commands check the working directory before they do anything, and " "fail if they find any modifications. They do this to ensure that you won't " "lose any changes that you have made, but not yet incorporated into a patch. " "The example below illustrates this; the <command role=\"hg-ext-mq\">qnew</" "command> command will not create a new patch if there are outstanding " "changes, caused in this case by the <command role=\"hg-cmd\">hg add</command> " "of <filename>file3</filename>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:467 msgid "" "Commands that check the working directory all take an <quote>I know what I'm " "doing</quote> option, which is always named <option>-f</option>. The exact " "meaning of <option>-f</option> depends on the command. For example, <command " "role=\"hg-cmd\">hg qnew <option role=\"hg-ext-mq-cmd-qnew-opt\">-f</option></" "command> will incorporate any outstanding changes into the new patch it " "creates, but <command role=\"hg-cmd\">hg qpop <option role=\"hg-ext-mq-cmd-" "qpop-opt\">-f</option></command> will revert modifications to any files " "affected by the patch that it is popping. Be sure to read the documentation " "for a command's <option>-f</option> option before you use it!" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch12-mq.xml:482 msgid "Working on several patches at once" msgstr "同时处理多个补丁" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:484 msgid "" "The <command role=\"hg-ext-mq\">qrefresh</command> command always refreshes " "the <emphasis>topmost</emphasis> applied patch. This means that you can " "suspend work on one patch (by refreshing it), pop or push to make a different " "patch the top, and work on <emphasis>that</emphasis> patch for a while." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:491 msgid "" "Here's an example that illustrates how you can use this ability. Let's say " "you're developing a new feature as two patches. The first is a change to the " "core of your software, and the second&emdash;layered on top of the " "first&emdash;changes the user interface to use the code you just added to the " "core. If you notice a bug in the core while you're working on the UI patch, " "it's easy to fix the core. Simply <command role=\"hg-ext-mq\">qrefresh</" "command> the UI patch to save your in-progress changes, and <command role=" "\"hg-ext-mq\">qpop</command> down to the core patch. Fix the core bug, " "<command role=\"hg-ext-mq\">qrefresh</command> the core patch, and <command " "role=\"hg-ext-mq\">qpush</command> back to the UI patch to continue where you " "left off." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch12-mq.xml:508 msgid "More about patches" msgstr "关于补丁的更多信息" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:510 msgid "" "MQ uses the GNU <command>patch</command> command to apply patches, so it's " "helpful to know a few more detailed aspects of how <command>patch</command> " "works, and about patches themselves." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch12-mq.xml:516 msgid "The strip count" msgstr "修剪计数" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:518 msgid "" "If you look at the file headers in a patch, you will notice that the " "pathnames usually have an extra component on the front that isn't present in " "the actual path name. This is a holdover from the way that people used to " "generate patches (people still do this, but it's somewhat rare with modern " "revision control tools)." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:525 msgid "" "Alice would unpack a tarball, edit her files, then decide that she wanted to " "create a patch. So she'd rename her working directory, unpack the tarball " "again (hence the need for the rename), and use the <option role=\"cmd-opt-diff" "\">-r</option> and <option role=\"cmd-opt-diff\">-N</option> options to " "<command>diff</command> to recursively generate a patch between the " "unmodified directory and the modified one. The result would be that the name " "of the unmodified directory would be at the front of the left-hand path in " "every file header, and the name of the modified directory would be at the " "front of the right-hand path." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:538 msgid "" "Since someone receiving a patch from the Alices of the net would be unlikely " "to have unmodified and modified directories with exactly the same names, the " "<command>patch</command> command has a <option role=\"cmd-opt-patch\">-p</" "option> option that indicates the number of leading path name components to " "strip when trying to apply a patch. This number is called the " "<emphasis>strip count</emphasis>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:546 msgid "" "An option of <quote><literal>-p1</literal></quote> means <quote>use a strip " "count of one</quote>. If <command>patch</command> sees a file name " "<filename>foo/bar/baz</filename> in a file header, it will strip " "<filename>foo</filename> and try to patch a file named <filename>bar/baz</" "filename>. (Strictly speaking, the strip count refers to the number of " "<emphasis>path separators</emphasis> (and the components that go with them ) " "to strip. A strip count of one will turn <filename>foo/bar</filename> into " "<filename>bar</filename>, but <filename>/foo/bar</filename> (notice the extra " "leading slash) into <filename>foo/bar</filename>.)" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:559 msgid "" "The <quote>standard</quote> strip count for patches is one; almost all " "patches contain one leading path name component that needs to be stripped. " "Mercurial's <command role=\"hg-cmd\">hg diff</command> command generates path " "names in this form, and the <command role=\"hg-cmd\">hg import</command> " "command and MQ expect patches to have a strip count of one." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:567 msgid "" "If you receive a patch from someone that you want to add to your patch queue, " "and the patch needs a strip count other than one, you cannot just <command " "role=\"hg-ext-mq\">qimport</command> the patch, because <command role=\"hg-" "ext-mq\">qimport</command> does not yet have a <literal>-p</literal> option " "(see <ulink role=\"hg-bug\" url=\"http://www.selenic.com/mercurial/bts/" "issue311\">issue 311</ulink>). Your best bet is to <command role=\"hg-ext-mq" "\">qnew</command> a patch of your own, then use <command>patch -pN</command> " "to apply their patch, followed by <command role=\"hg-cmd\">hg addremove</" "command> to pick up any files added or removed by the patch, followed by " "<command role=\"hg-ext-mq\">hg qrefresh</command>. This complexity may become " "unnecessary; see <ulink role=\"hg-bug\" url=\"http://www.selenic.com/" "mercurial/bts/issue311\">issue 311</ulink> for details." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch12-mq.xml:587 msgid "Strategies for applying a patch" msgstr "应用补丁的策略" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:589 msgid "" "When <command>patch</command> applies a hunk, it tries a handful of " "successively less accurate strategies to try to make the hunk apply. This " "falling-back technique often makes it possible to take a patch that was " "generated against an old version of a file, and apply it against a newer " "version of that file." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:596 msgid "" "First, <command>patch</command> tries an exact match, where the line numbers, " "the context, and the text to be modified must apply exactly. If it cannot " "make an exact match, it tries to find an exact match for the context, without " "honouring the line numbering information. If this succeeds, it prints a line " "of output saying that the hunk was applied, but at some <emphasis>offset</" "emphasis> from the original line number." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:605 msgid "" "If a context-only match fails, <command>patch</command> removes the first and " "last lines of the context, and tries a <emphasis>reduced</emphasis> context-" "only match. If the hunk with reduced context succeeds, it prints a message " "saying that it applied the hunk with a <emphasis>fuzz factor</emphasis> (the " "number after the fuzz factor indicates how many lines of context " "<command>patch</command> had to trim before the patch applied)." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:614 msgid "" "When neither of these techniques works, <command>patch</command> prints a " "message saying that the hunk in question was rejected. It saves rejected " "hunks (also simply called <quote>rejects</quote>) to a file with the same " "name, and an added <filename role=\"special\">.rej</filename> extension. It " "also saves an unmodified copy of the file with a <filename role=\"special\">." "orig</filename> extension; the copy of the file without any extensions will " "contain any changes made by hunks that <emphasis>did</emphasis> apply " "cleanly. If you have a patch that modifies <filename>foo</filename> with six " "hunks, and one of them fails to apply, you will have: an unmodified " "<filename>foo.orig</filename>, a <filename>foo.rej</filename> containing one " "hunk, and <filename>foo</filename>, containing the changes made by the five " "successful hunks." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch12-mq.xml:632 msgid "Some quirks of patch representation" msgstr "补丁的一些特性" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:634 msgid "" "There are a few useful things to know about how <command>patch</command> " "works with files." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch12-mq.xml:637 msgid "" "This should already be obvious, but <command>patch</command> cannot handle " "binary files." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch12-mq.xml:641 msgid "" "Neither does it care about the executable bit; it creates new files as " "readable, but not executable." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch12-mq.xml:645 msgid "" "<command>patch</command> treats the removal of a file as a diff between the " "file to be removed and the empty file. So your idea of <quote>I deleted this " "file</quote> looks like <quote>every line of this file was deleted</quote> in " "a patch." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch12-mq.xml:651 msgid "" "It treats the addition of a file as a diff between the empty file and the " "file to be added. So in a patch, your idea of <quote>I added this file</" "quote> looks like <quote>every line of this file was added</quote>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch12-mq.xml:657 msgid "" "It treats a renamed file as the removal of the old name, and the addition of " "the new name. This means that renamed files have a big footprint in " "patches. (Note also that Mercurial does not currently try to infer when " "files have been renamed or copied in a patch.)" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch12-mq.xml:663 msgid "" "<command>patch</command> cannot represent empty files, so you cannot use a " "patch to represent the notion <quote>I added this empty file to the tree</" "quote>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch12-mq.xml:671 msgid "Beware the fuzz" msgstr "当心毛刺" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:673 msgid "" "While applying a hunk at an offset, or with a fuzz factor, will often be " "completely successful, these inexact techniques naturally leave open the " "possibility of corrupting the patched file. The most common cases typically " "involve applying a patch twice, or at an incorrect location in the file. If " "<command>patch</command> or <command role=\"hg-ext-mq\">qpush</command> ever " "mentions an offset or fuzz factor, you should make sure that the modified " "files are correct afterwards." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:683 msgid "" "It's often a good idea to refresh a patch that has applied with an offset or " "fuzz factor; refreshing the patch generates new context information that will " "make it apply cleanly. I say <quote>often,</quote> not <quote>always,</" "quote> because sometimes refreshing a patch will make it fail to apply " "against a different revision of the underlying files. In some cases, such as " "when you're maintaining a patch that must sit on top of multiple versions of " "a source tree, it's acceptable to have a patch apply with some fuzz, provided " "you've verified the results of the patching process in such cases." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch12-mq.xml:696 msgid "Handling rejection" msgstr "处理拒绝" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:698 msgid "" "If <command role=\"hg-ext-mq\">qpush</command> fails to apply a patch, it " "will print an error message and exit. If it has left <filename role=\"special" "\">.rej</filename> files behind, it is usually best to fix up the rejected " "hunks before you push more patches or do any further work." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:704 msgid "" "If your patch <emphasis>used to</emphasis> apply cleanly, and no longer does " "because you've changed the underlying code that your patches are based on, " "Mercurial Queues can help; see <xref linkend=\"sec:mq:merge\"/> for details." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:709 msgid "" "Unfortunately, there aren't any great techniques for dealing with rejected " "hunks. Most often, you'll need to view the <filename role=\"special\">.rej</" "filename> file and edit the target file, applying the rejected hunks by hand." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:714 msgid "" "A Linux kernel hacker, Chris Mason (the author of Mercurial Queues), wrote a " "tool called <command>mpatch</command> (<ulink url=\"http://oss.oracle.com/" "~mason/mpatch/\">http://oss.oracle.com/~mason/mpatch/</ulink>), which takes a " "simple approach to automating the application of hunks rejected by " "<command>patch</command>. The <command>mpatch</command> command can help " "with four common reasons that a hunk may be rejected:" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch12-mq.xml:724 msgid "The context in the middle of a hunk has changed." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch12-mq.xml:727 msgid "A hunk is missing some context at the beginning or end." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch12-mq.xml:730 msgid "" "A large hunk might apply better&emdash;either entirely or in part&emdash;if " "it was broken up into smaller hunks." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch12-mq.xml:734 msgid "" "A hunk removes lines with slightly different content than those currently " "present in the file." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:738 msgid "" "If you use <command>mpatch</command>, you should be doubly careful to check " "your results when you're done. In fact, <command>mpatch</command> enforces " "this method of double-checking the tool's output, by automatically dropping " "you into a merge program when it has done its job, so that you can verify its " "work and finish off any remaining merges." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch12-mq.xml:749 msgid "More on patch management" msgstr "补丁管理进阶" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:751 msgid "" "As you grow familiar with MQ, you will find yourself wanting to perform other " "kinds of patch management operations." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch12-mq.xml:755 msgid "Deleting unwanted patches" msgstr "删除不需要的补丁" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:757 msgid "" "If you want to get rid of a patch, use the <command role=\"hg-ext-mq\">hg " "qdelete</command> command to delete the patch file and remove its entry from " "the patch series. If you try to delete a patch that is still applied, " "<command role=\"hg-ext-mq\">hg qdelete</command> will refuse." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch12-mq.xml:767 msgid "Converting to and from permanent revisions" msgstr "与持久版本的相互转换" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:769 msgid "" "Once you're done working on a patch and want to turn it into a permanent " "changeset, use the <command role=\"hg-ext-mq\">hg qfinish</command> command. " "Pass a revision to the command to identify the patch that you want to turn " "into a regular changeset; this patch must already be applied." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:777 msgid "" "The <command role=\"hg-ext-mq\">hg qfinish</command> command accepts an " "<option>--all</option> or <option>-a</option> option, which turns all applied " "patches into regular changesets." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:782 msgid "" "It is also possible to turn an existing changeset into a patch, by passing " "the <option>-r</option> option to <command role=\"hg-ext-mq\">hg qimport</" "command>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:788 msgid "" "Note that it only makes sense to convert a changeset into a patch if you have " "not propagated that changeset into any other repositories. The imported " "changeset's ID will change every time you refresh the patch, which will make " "Mercurial treat it as unrelated to the original changeset if you have pushed " "it somewhere else." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch12-mq.xml:798 msgid "Getting the best performance out of MQ" msgstr "MQ 的性能" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:800 msgid "" "MQ is very efficient at handling a large number of patches. I ran some " "performance experiments in mid-2006 for a talk that I gave at the 2006 " "EuroPython conference (on modern hardware, you should expect better " "performance than you'll see below). I used as my data set the Linux 2.6.17-" "mm1 patch series, which consists of 1,738 patches. I applied these on top of " "a Linux kernel repository containing all 27,472 revisions between Linux " "2.6.12-rc2 and Linux 2.6.17." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:809 msgid "" "On my old, slow laptop, I was able to <command role=\"hg-cmd\">hg qpush " "<option role=\"hg-ext-mq-cmd-qpush-opt\">-a</option></command> all 1,738 " "patches in 3.5 minutes, and <command role=\"hg-cmd\">hg qpop <option role=" "\"hg-ext-mq-cmd-qpop-opt\">-a</option></command> them all in 30 seconds. (On " "a newer laptop, the time to push all patches dropped to two minutes.) I " "could <command role=\"hg-ext-mq\">qrefresh</command> one of the biggest " "patches (which made 22,779 lines of changes to 287 files) in 6.6 seconds." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:820 msgid "" "Clearly, MQ is well suited to working in large trees, but there are a few " "tricks you can use to get the best performance of it." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:824 msgid "" "First of all, try to <quote>batch</quote> operations together. Every time " "you run <command role=\"hg-ext-mq\">qpush</command> or <command role=\"hg-ext-" "mq\">qpop</command>, these commands scan the working directory once to make " "sure you haven't made some changes and then forgotten to run <command role=" "\"hg-ext-mq\">qrefresh</command>. On a small tree, the time that this scan " "takes is unnoticeable. However, on a medium-sized tree (containing tens of " "thousands of files), it can take a second or more." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:835 msgid "" "The <command role=\"hg-ext-mq\">qpush</command> and <command role=\"hg-ext-mq" "\">qpop</command> commands allow you to push and pop multiple patches at a " "time. You can identify the <quote>destination patch</quote> that you want to " "end up at. When you <command role=\"hg-ext-mq\">qpush</command> with a " "destination specified, it will push patches until that patch is at the top of " "the applied stack. When you <command role=\"hg-ext-mq\">qpop</command> to a " "destination, MQ will pop patches until the destination patch is at the top." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:845 msgid "" "You can identify a destination patch using either the name of the patch, or " "by number. If you use numeric addressing, patches are counted from zero; " "this means that the first patch is zero, the second is one, and so on." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch12-mq.xml:852 msgid "Updating your patches when the underlying code changes" msgstr "当基础代码改变时,更新补丁的方法" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:855 msgid "" "It's common to have a stack of patches on top of an underlying repository " "that you don't modify directly. If you're working on changes to third-party " "code, or on a feature that is taking longer to develop than the rate of " "change of the code beneath, you will often need to sync up with the " "underlying code, and fix up any hunks in your patches that no longer apply. " "This is called <emphasis>rebasing</emphasis> your patch series." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:864 msgid "" "The simplest way to do this is to <command role=\"hg-cmd\">hg qpop <option " "role=\"hg-ext-mq-cmd-qpop-opt\">hg -a</option></command> your patches, then " "<command role=\"hg-cmd\">hg pull</command> changes into the underlying " "repository, and finally <command role=\"hg-cmd\">hg qpush <option role=\"hg-" "ext-mq-cmd-qpop-opt\">-a</option></command> your patches again. MQ will stop " "pushing any time it runs across a patch that fails to apply during conflicts, " "allowing you to fix your conflicts, <command role=\"hg-ext-mq\">qrefresh</" "command> the affected patch, and continue pushing until you have fixed your " "entire stack." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:876 msgid "" "This approach is easy to use and works well if you don't expect changes to " "the underlying code to affect how well your patches apply. If your patch " "stack touches code that is modified frequently or invasively in the " "underlying repository, however, fixing up rejected hunks by hand quickly " "becomes tiresome." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:883 msgid "" "It's possible to partially automate the rebasing process. If your patches " "apply cleanly against some revision of the underlying repo, MQ can use this " "information to help you to resolve conflicts between your patches and a " "different revision." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:889 msgid "The process is a little involved." msgstr "" #. type: Content of: <book><chapter><sect1><orderedlist><listitem><para> #: ../en/ch12-mq.xml:891 msgid "" "To begin, <command role=\"hg-cmd\">hg qpush -a</command> all of your patches " "on top of the revision where you know that they apply cleanly." msgstr "" #. type: Content of: <book><chapter><sect1><orderedlist><listitem><para> #: ../en/ch12-mq.xml:895 msgid "" "Save a backup copy of your patch directory using <command role=\"hg-cmd\">hg " "qsave <option role=\"hg-ext-mq-cmd-qsave-opt\">hg -e</option> <option role=" "\"hg-ext-mq-cmd-qsave-opt\">hg -c</option></command>. This prints the name " "of the directory that it has saved the patches in. It will save the patches " "to a directory called <filename role=\"special\" class=\"directory\">.hg/" "patches.N</filename>, where <literal>N</literal> is a small integer. It also " "commits a <quote>save changeset</quote> on top of your applied patches; this " "is for internal book-keeping, and records the states of the <filename role=" "\"special\">series</filename> and <filename role=\"special\">status</" "filename> files." msgstr "" #. type: Content of: <book><chapter><sect1><orderedlist><listitem><para> #: ../en/ch12-mq.xml:909 msgid "" "Use <command role=\"hg-cmd\">hg pull</command> to bring new changes into the " "underlying repository. (Don't run <command role=\"hg-cmd\">hg pull -u</" "command>; see below for why.)" msgstr "" #. type: Content of: <book><chapter><sect1><orderedlist><listitem><para> #: ../en/ch12-mq.xml:914 msgid "" "Update to the new tip revision, using <command role=\"hg-cmd\">hg update " "<option role=\"hg-opt-update\">-C</option></command> to override the patches " "you have pushed." msgstr "" #. type: Content of: <book><chapter><sect1><orderedlist><listitem><para> #: ../en/ch12-mq.xml:919 msgid "" "Merge all patches using <command>hg qpush -m -a</command>. The <option role=" "\"hg-ext-mq-cmd-qpush-opt\">-m</option> option to <command role=\"hg-ext-mq" "\">qpush</command> tells MQ to perform a three-way merge if the patch fails " "to apply." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:927 msgid "" "During the <command role=\"hg-cmd\">hg qpush <option role=\"hg-ext-mq-cmd-" "qpush-opt\">hg -m</option></command>, each patch in the <filename role=" "\"special\">series</filename> file is applied normally. If a patch applies " "with fuzz or rejects, MQ looks at the queue you <command role=\"hg-ext-mq" "\">qsave</command>d, and performs a three-way merge with the corresponding " "changeset. This merge uses Mercurial's normal merge machinery, so it may pop " "up a GUI merge tool to help you to resolve problems." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:937 msgid "" "When you finish resolving the effects of a patch, MQ refreshes your patch " "based on the result of the merge." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:940 msgid "" "At the end of this process, your repository will have one extra head from the " "old patch queue, and a copy of the old patch queue will be in <filename role=" "\"special\" class=\"directory\">.hg/patches.N</filename>. You can remove the " "extra head using <command role=\"hg-cmd\">hg qpop -a -n patches.N</command> " "or <command role=\"hg-cmd\">hg strip</command>. You can delete <filename " "role=\"special\" class=\"directory\">.hg/patches.N</filename> once you are " "sure that you no longer need it as a backup." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch12-mq.xml:952 msgid "Identifying patches" msgstr "标识补丁" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:954 msgid "" "MQ commands that work with patches let you refer to a patch either by using " "its name or by a number. By name is obvious enough; pass the name " "<filename>foo.patch</filename> to <command role=\"hg-ext-mq\">qpush</" "command>, for example, and it will push patches until <filename>foo.patch</" "filename> is applied." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:961 msgid "" "As a shortcut, you can refer to a patch using both a name and a numeric " "offset; <literal>foo.patch-2</literal> means <quote>two patches before " "<literal>foo.patch</literal></quote>, while <literal>bar.patch+4</literal> " "means <quote>four patches after <literal>bar.patch</literal></quote>." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:967 msgid "" "Referring to a patch by index isn't much different. The first patch printed " "in the output of <command role=\"hg-ext-mq\">qseries</command> is patch zero " "(yes, it's one of those start-at-zero counting systems); the second is patch " "one; and so on." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:973 msgid "" "MQ also makes it easy to work with patches when you are using normal " "Mercurial commands. Every command that accepts a changeset ID will also " "accept the name of an applied patch. MQ augments the tags normally in the " "repository with an eponymous one for each applied patch. In addition, the " "special tags <literal role=\"tag\">qbase</literal> and <literal role=\"tag" "\">qtip</literal> identify the <quote>bottom-most</quote> and topmost applied " "patches, respectively." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:983 msgid "" "These additions to Mercurial's normal tagging capabilities make dealing with " "patches even more of a breeze." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch12-mq.xml:986 msgid "Want to patchbomb a mailing list with your latest series of changes?" msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch12-mq.xml:989 msgid "" "(Don't know what <quote>patchbombing</quote> is? See <xref linkend=\"sec:" "hgext:patchbomb\"/>.)" msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch12-mq.xml:992 msgid "" "Need to see all of the patches since <literal>foo.patch</literal> that have " "touched files in a subdirectory of your tree?" msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:999 msgid "" "Because MQ makes the names of patches available to the rest of Mercurial " "through its normal internal tag machinery, you don't need to type in the " "entire name of a patch when you want to identify it by name." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:1004 msgid "" "Another nice consequence of representing patch names as tags is that when you " "run the <command role=\"hg-cmd\">hg log</command> command, it will display a " "patch's name as a tag, simply as part of its normal output. This makes it " "easy to visually distinguish applied patches from underlying <quote>normal</" "quote> revisions. The following example shows a few normal Mercurial " "commands in use with applied patches." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch12-mq.xml:1017 msgid "Useful things to know about" msgstr "其它需要了解的东西" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:1019 msgid "" "There are a number of aspects of MQ usage that don't fit tidily into sections " "of their own, but that are good to know. Here they are, in one place." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch12-mq.xml:1024 msgid "" "Normally, when you <command role=\"hg-ext-mq\">qpop</command> a patch and " "<command role=\"hg-ext-mq\">qpush</command> it again, the changeset that " "represents the patch after the pop/push will have a <emphasis>different " "identity</emphasis> than the changeset that represented the hash beforehand. " "See <xref linkend=\"sec:mqref:cmd:qpush\"/> for information as to why this is." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch12-mq.xml:1033 msgid "" "It's not a good idea to <command role=\"hg-cmd\">hg merge</command> changes " "from another branch with a patch changeset, at least if you want to maintain " "the <quote>patchiness</quote> of that changeset and changesets below it on " "the patch stack. If you try to do this, it will appear to succeed, but MQ " "will become confused." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch12-mq.xml:1044 msgid "Managing patches in a repository" msgstr "在版本库管理补丁" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:1046 msgid "" "Because MQ's <filename role=\"special\" class=\"directory\">.hg/patches</" "filename> directory resides outside a Mercurial repository's working " "directory, the <quote>underlying</quote> Mercurial repository knows nothing " "about the management or presence of patches." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:1052 msgid "" "This presents the interesting possibility of managing the contents of the " "patch directory as a Mercurial repository in its own right. This can be a " "useful way to work. For example, you can work on a patch for a while, " "<command role=\"hg-ext-mq\">qrefresh</command> it, then <command role=\"hg-cmd" "\">hg commit</command> the current state of the patch. This lets you " "<quote>roll back</quote> to that version of the patch later on." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:1061 msgid "" "You can then share different versions of the same patch stack among multiple " "underlying repositories. I use this when I am developing a Linux kernel " "feature. I have a pristine copy of my kernel sources for each of several CPU " "architectures, and a cloned repository under each that contains the patches I " "am working on. When I want to test a change on a different architecture, I " "push my current patches to the patch repository associated with that kernel " "tree, pop and push all of my patches, and build and test that kernel." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:1071 msgid "" "Managing patches in a repository makes it possible for multiple developers to " "work on the same patch series without colliding with each other, all on top " "of an underlying source base that they may or may not control." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch12-mq.xml:1077 msgid "MQ support for patch repositories" msgstr "MQ 支持补丁版本库" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:1079 msgid "" "MQ helps you to work with the <filename role=\"special\" class=\"directory\">." "hg/patches</filename> directory as a repository; when you prepare a " "repository for working with patches using <command role=\"hg-ext-mq\">qinit</" "command>, you can pass the <option role=\"hg-ext-mq-cmd-qinit-opt\">hg -c</" "option> option to create the <filename role=\"special\" class=\"directory\">." "hg/patches</filename> directory as a Mercurial repository." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><note><para> #: ../en/ch12-mq.xml:1089 msgid "" "If you forget to use the <option role=\"hg-ext-mq-cmd-qinit-opt\">hg -c</" "option> option, you can simply go into the <filename role=\"special\" class=" "\"directory\">.hg/patches</filename> directory at any time and run <command " "role=\"hg-cmd\">hg init</command>. Don't forget to add an entry for the " "<filename role=\"special\">status</filename> file to the <filename role=" "\"special\">.hgignore</filename> file, though" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><note><para> #: ../en/ch12-mq.xml:1098 msgid "" "(<command role=\"hg-cmd\">hg qinit <option role=\"hg-ext-mq-cmd-qinit-opt" "\">hg -c</option></command> does this for you automatically); you " "<emphasis>really</emphasis> don't want to manage the <filename role=\"special" "\">status</filename> file." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:1105 msgid "" "As a convenience, if MQ notices that the <filename class=\"directory\">.hg/" "patches</filename> directory is a repository, it will automatically <command " "role=\"hg-cmd\">hg add</command> every patch that you create and import." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:1110 msgid "" "MQ provides a shortcut command, <command role=\"hg-ext-mq\">qcommit</" "command>, that runs <command role=\"hg-cmd\">hg commit</command> in the " "<filename role=\"special\" class=\"directory\">.hg/patches</filename> " "directory. This saves some bothersome typing." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:1116 msgid "" "Finally, as a convenience to manage the patch directory, you can define the " "alias <command>mq</command> on Unix systems. For example, on Linux systems " "using the <command>bash</command> shell, you can include the following " "snippet in your <filename role=\"home\">~/.bashrc</filename>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:1125 msgid "" "You can then issue commands of the form <command>mq pull</command> from the " "main repository." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch12-mq.xml:1130 msgid "A few things to watch out for" msgstr "需要注意的事情" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:1132 msgid "" "MQ's support for working with a repository full of patches is limited in a " "few small respects." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:1135 msgid "" "MQ cannot automatically detect changes that you make to the patch directory. " "If you <command role=\"hg-cmd\">hg pull</command>, manually edit, or <command " "role=\"hg-cmd\">hg update</command> changes to patches or the <filename role=" "\"special\">series</filename> file, you will have to <command role=\"hg-cmd" "\">hg qpop <option role=\"hg-ext-mq-cmd-qpop-opt\">-a</option></command> and " "then <command role=\"hg-cmd\">hg qpush <option role=\"hg-ext-mq-cmd-qpush-opt" "\">-a</option></command> in the underlying repository to see those changes " "show up there. If you forget to do this, you can confuse MQ's idea of which " "patches are applied." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch12-mq.xml:1151 msgid "Third party tools for working with patches" msgstr "操作补丁的第三方工具" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:1153 msgid "" "Once you've been working with patches for a while, you'll find yourself " "hungry for tools that will help you to understand and manipulate the patches " "you're dealing with." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:1157 msgid "" "The <command>diffstat</command> command <citation>web:diffstat</citation> " "generates a histogram of the modifications made to each file in a patch. It " "provides a good way to <quote>get a sense of</quote> a patch&emdash;which " "files it affects, and how much change it introduces to each file and as a " "whole. (I find that it's a good idea to use <command>diffstat</command>'s " "<option role=\"cmd-opt-diffstat\">-p</option> option as a matter of course, " "as otherwise it will try to do clever things with prefixes of file names that " "inevitably confuse at least me.)" msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:1171 msgid "" "The <literal role=\"package\">patchutils</literal> package <citation>web:" "patchutils</citation> is invaluable. It provides a set of small utilities " "that follow the <quote>Unix philosophy;</quote> each does one useful thing " "with a patch. The <literal role=\"package\">patchutils</literal> command I " "use most is <command>filterdiff</command>, which extracts subsets from a " "patch file. For example, given a patch that modifies hundreds of files " "across dozens of directories, a single invocation of <command>filterdiff</" "command> can generate a smaller patch that only touches files whose names " "match a particular glob pattern. See <xref linkend=\"mq-collab:tips:interdiff" "\"/> for another example." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch12-mq.xml:1187 msgid "Good ways to work with patches" msgstr "操作补丁的好习惯" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:1189 msgid "" "Whether you are working on a patch series to submit to a free software or " "open source project, or a series that you intend to treat as a sequence of " "regular changesets when you're done, you can use some simple techniques to " "keep your work well organized." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:1195 msgid "" "Give your patches descriptive names. A good name for a patch might be " "<filename>rework-device-alloc.patch</filename>, because it will immediately " "give you a hint what the purpose of the patch is. Long names shouldn't be a " "problem; you won't be typing the names often, but you <emphasis>will</" "emphasis> be running commands like <command role=\"hg-ext-mq\">qapplied</" "command> and <command role=\"hg-ext-mq\">qtop</command> over and over. Good " "naming becomes especially important when you have a number of patches to work " "with, or if you are juggling a number of different tasks and your patches " "only get a fraction of your attention." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:1207 msgid "" "Be aware of what patch you're working on. Use the <command role=\"hg-ext-mq" "\">qtop</command> command and skim over the text of your patches " "frequently&emdash;for example, using <command role=\"hg-cmd\">hg tip <option " "role=\"hg-opt-tip\">-p</option></command>)&emdash;to be sure of where you " "stand. I have several times worked on and <command role=\"hg-ext-mq" "\">qrefresh</command>ed a patch other than the one I intended, and it's often " "tricky to migrate changes into the right patch after making them in the wrong " "one." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:1217 msgid "" "For this reason, it is very much worth investing a little time to learn how " "to use some of the third-party tools I described in <xref linkend=\"sec:mq:" "tools\"/>, particularly <command>diffstat</command> and <command>filterdiff</" "command>. The former will give you a quick idea of what changes your patch " "is making, while the latter makes it easy to splice hunks selectively out of " "one patch and into another." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch12-mq.xml:1228 msgid "MQ cookbook" msgstr "MQ 手册" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch12-mq.xml:1231 msgid "Manage <quote>trivial</quote> patches" msgstr "管理<quote>琐碎的</quote>补丁" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:1233 msgid "" "Because the overhead of dropping files into a new Mercurial repository is so " "low, it makes a lot of sense to manage patches this way even if you simply " "want to make a few changes to a source tarball that you downloaded." msgstr "" # #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:1238 msgid "" "Begin by downloading and unpacking the source tarball, and turning it into a " "Mercurial repository." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:1243 msgid "Continue by creating a patch stack and making your changes." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:1248 msgid "" "Let's say a few weeks or months pass, and your package author releases a new " "version. First, bring their changes into the repository." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:1254 msgid "" "The pipeline starting with <command role=\"hg-cmd\">hg locate</command> above " "deletes all files in the working directory, so that <command role=\"hg-cmd" "\">hg commit</command>'s <option role=\"hg-opt-commit\">--addremove</option> " "option can actually tell which files have really been removed in the newer " "version of the source." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:1262 msgid "Finally, you can apply your patches on top of the new tree." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch12-mq.xml:1269 msgid "Combining entire patches" msgstr "组合全部的补丁" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:1271 msgid "" "MQ provides a command, <command role=\"hg-ext-mq\">qfold</command> that lets " "you combine entire patches. This <quote>folds</quote> the patches you name, " "in the order you name them, into the topmost applied patch, and concatenates " "their descriptions onto the end of its description. The patches that you " "fold must be unapplied before you fold them." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:1279 msgid "" "The order in which you fold patches matters. If your topmost applied patch " "is <literal>foo</literal>, and you <command role=\"hg-ext-mq\">qfold</" "command> <literal>bar</literal> and <literal>quux</literal> into it, you will " "end up with a patch that has the same effect as if you applied first " "<literal>foo</literal>, then <literal>bar</literal>, followed by " "<literal>quux</literal>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch12-mq.xml:1290 msgid "Merging part of one patch into another" msgstr "合并补丁的部分内容到其它补丁" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:1292 msgid "" "Merging <emphasis>part</emphasis> of one patch into another is more difficult " "than combining entire patches." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:1296 msgid "" "If you want to move changes to entire files, you can use <command>filterdiff</" "command>'s <option role=\"cmd-opt-filterdiff\">-i</option> and <option role=" "\"cmd-opt-filterdiff\">-x</option> options to choose the modifications to " "snip out of one patch, concatenating its output onto the end of the patch you " "want to merge into. You usually won't need to modify the patch you've merged " "the changes from. Instead, MQ will report some rejected hunks when you " "<command role=\"hg-ext-mq\">qpush</command> it (from the hunks you moved into " "the other patch), and you can simply <command role=\"hg-ext-mq\">qrefresh</" "command> the patch to drop the duplicate hunks." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:1309 msgid "" "If you have a patch that has multiple hunks modifying a file, and you only " "want to move a few of those hunks, the job becomes more messy, but you can " "still partly automate it. Use <command>lsdiff -nvv</command> to print some " "metadata about the patch." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:1317 msgid "This command prints three different kinds of number:" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch12-mq.xml:1320 msgid "" "(in the first column) a <emphasis>file number</emphasis> to identify each " "file modified in the patch;" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch12-mq.xml:1324 msgid "" "(on the next line, indented) the line number within a modified file where a " "hunk starts; and" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch12-mq.xml:1327 msgid "" "(on the same line) a <emphasis>hunk number</emphasis> to identify that hunk." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:1331 msgid "" "You'll have to use some visual inspection, and reading of the patch, to " "identify the file and hunk numbers you'll want, but you can then pass them to " "to <command>filterdiff</command>'s <option role=\"cmd-opt-filterdiff\">--" "files</option> and <option role=\"cmd-opt-filterdiff\">--hunks</option> " "options, to select exactly the file and hunk you want to extract." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch12-mq.xml:1339 msgid "" "Once you have this hunk, you can concatenate it onto the end of your " "destination patch and continue with the remainder of <xref linkend=\"sec:mq:" "combine\"/>." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch12-mq.xml:1346 msgid "Differences between quilt and MQ" msgstr "MQ 与 quilt 的区别" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:1348 msgid "" "If you are already familiar with quilt, MQ provides a similar command set. " "There are a few differences in the way that it works." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch12-mq.xml:1352 msgid "" "You will already have noticed that most quilt commands have MQ counterparts " "that simply begin with a <quote><literal>q</literal></quote>. The exceptions " "are quilt's <literal>add</literal> and <literal>remove</literal> commands, " "the counterparts for which are the normal Mercurial <command role=\"hg-cmd" "\">hg add</command> and <command role=\"hg-cmd\">hg remove</command> " "commands. There is no MQ equivalent of the quilt <literal>edit</literal> " "command." msgstr "" #. type: Content of: <book><chapter><title> #: ../en/ch13-mq-collab.xml:5 msgid "Advanced uses of Mercurial Queues" msgstr "MQ 的高级用法" #. type: Content of: <book><chapter><para> #: ../en/ch13-mq-collab.xml:7 msgid "" "While it's easy to pick up straightforward uses of Mercurial Queues, use of a " "little discipline and some of MQ's less frequently used capabilities makes it " "possible to work in complicated development environments." msgstr "" #. type: Content of: <book><chapter><para> #: ../en/ch13-mq-collab.xml:12 msgid "" "In this chapter, I will use as an example a technique I have used to manage " "the development of an Infiniband device driver for the Linux kernel. The " "driver in question is large (at least as drivers go), with 25,000 lines of " "code spread across 35 source files. It is maintained by a small team of " "developers." msgstr "" #. type: Content of: <book><chapter><para> #: ../en/ch13-mq-collab.xml:18 msgid "" "While much of the material in this chapter is specific to Linux, the same " "principles apply to any code base for which you're not the primary owner, and " "upon which you need to do a lot of development." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch13-mq-collab.xml:24 msgid "The problem of many targets" msgstr "多个目标的问题" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch13-mq-collab.xml:26 msgid "" "The Linux kernel changes rapidly, and has never been internally stable; " "developers frequently make drastic changes between releases. This means that " "a version of the driver that works well with a particular released version of " "the kernel will not even <emphasis>compile</emphasis> correctly against, " "typically, any other version." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch13-mq-collab.xml:33 msgid "" "To maintain a driver, we have to keep a number of distinct versions of Linux " "in mind." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch13-mq-collab.xml:36 msgid "" "One target is the main Linux kernel development tree. Maintenance of the code " "is in this case partly shared by other developers in the kernel community, " "who make <quote>drive-by</quote> modifications to the driver as they develop " "and refine kernel subsystems." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch13-mq-collab.xml:42 msgid "" "We also maintain a number of <quote>backports</quote> to older versions of " "the Linux kernel, to support the needs of customers who are running older " "Linux distributions that do not incorporate our drivers. (To " "<emphasis>backport</emphasis> a piece of code is to modify it to work in an " "older version of its target environment than the version it was developed " "for.)" msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch13-mq-collab.xml:50 msgid "" "Finally, we make software releases on a schedule that is necessarily not " "aligned with those used by Linux distributors and kernel developers, so that " "we can deliver new features to customers without forcing them to upgrade " "their entire kernels or distributions." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch13-mq-collab.xml:58 msgid "Tempting approaches that don't work well" msgstr "工作不好的诱人方法" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch13-mq-collab.xml:60 msgid "" "There are two <quote>standard</quote> ways to maintain a piece of software " "that has to target many different environments." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch13-mq-collab.xml:64 msgid "" "The first is to maintain a number of branches, each intended for a single " "target. The trouble with this approach is that you must maintain iron " "discipline in the flow of changes between repositories. A new feature or bug " "fix must start life in a <quote>pristine</quote> repository, then percolate " "out to every backport repository. Backport changes are more limited in the " "branches they should propagate to; a backport change that is applied to a " "branch where it doesn't belong will probably stop the driver from compiling." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch13-mq-collab.xml:74 msgid "" "The second is to maintain a single source tree filled with conditional " "statements that turn chunks of code on or off depending on the intended " "target. Because these <quote>ifdefs</quote> are not allowed in the Linux " "kernel tree, a manual or automatic process must be followed to strip them out " "and yield a clean tree. A code base maintained in this fashion rapidly " "becomes a rat's nest of conditional blocks that are difficult to understand " "and maintain." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch13-mq-collab.xml:83 msgid "" "Neither of these approaches is well suited to a situation where you don't " "<quote>own</quote> the canonical copy of a source tree. In the case of a " "Linux driver that is distributed with the standard kernel, Linus's tree " "contains the copy of the code that will be treated by the world as " "canonical. The upstream version of <quote>my</quote> driver can be modified " "by people I don't know, without me even finding out about it until after the " "changes show up in Linus's tree." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch13-mq-collab.xml:93 msgid "" "These approaches have the added weakness of making it difficult to generate " "well-formed patches to submit upstream." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch13-mq-collab.xml:97 msgid "" "In principle, Mercurial Queues seems like a good candidate to manage a " "development scenario such as the above. While this is indeed the case, MQ " "contains a few added features that make the job more pleasant." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch13-mq-collab.xml:105 msgid "Conditionally applying patches with guards" msgstr "有条件的应用补丁" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch13-mq-collab.xml:107 msgid "" "Perhaps the best way to maintain sanity with so many targets is to be able to " "choose specific patches to apply for a given situation. MQ provides a " "feature called <quote>guards</quote> (which originates with quilt's " "<literal>guards</literal> command) that does just this. To start off, let's " "create a simple repository for experimenting in." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch13-mq-collab.xml:116 msgid "" "This gives us a tiny repository that contains two patches that don't have any " "dependencies on each other, because they touch different files." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch13-mq-collab.xml:120 msgid "" "The idea behind conditional application is that you can <quote>tag</quote> a " "patch with a <emphasis>guard</emphasis>, which is simply a text string of " "your choosing, then tell MQ to select specific guards to use when applying " "patches. MQ will then either apply, or skip over, a guarded patch, depending " "on the guards that you have selected." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch13-mq-collab.xml:127 msgid "" "A patch can have an arbitrary number of guards; each one is " "<emphasis>positive</emphasis> (<quote>apply this patch if this guard is " "selected</quote>) or <emphasis>negative</emphasis> (<quote>skip this patch if " "this guard is selected</quote>). A patch with no guards is always applied." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch13-mq-collab.xml:135 msgid "Controlling the guards on a patch" msgstr "控制补丁的应用条件" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch13-mq-collab.xml:137 msgid "" "The <command role=\"hg-ext-mq\">qguard</command> command lets you determine " "which guards should apply to a patch, or display the guards that are already " "in effect. Without any arguments, it displays the guards on the current " "topmost patch." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch13-mq-collab.xml:144 msgid "" "To set a positive guard on a patch, prefix the name of the guard with a " "<quote><literal>+</literal></quote>." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch13-mq-collab.xml:149 msgid "" "To set a negative guard on a patch, prefix the name of the guard with a " "<quote><literal>-</literal></quote>." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch13-mq-collab.xml:155 msgid "" "Notice that we prefixed the arguments to the <command>hg qguard</command> " "command with a <literal>--</literal> here, so that Mercurial would not " "interpret the text <literal>-quux</literal> as an option." msgstr "" #. type: Content of: <book><chapter><sect1><note><title> #: ../en/ch13-mq-collab.xml:161 msgid "Setting vs. modifying" msgstr "" #. type: Content of: <book><chapter><sect1><note><para> #: ../en/ch13-mq-collab.xml:163 msgid "" "The <command role=\"hg-ext-mq\">qguard</command> command <emphasis>sets</" "emphasis> the guards on a patch; it doesn't <emphasis>modify</emphasis> " "them. What this means is that if you run <command role=\"hg-cmd\">hg qguard " "+a +b</command> on a patch, then <command role=\"hg-cmd\">hg qguard +c</" "command> on the same patch, the <emphasis>only</emphasis> guard that will be " "set on it afterwards is <literal>+c</literal>." msgstr "" # #. type: Content of: <book><chapter><sect1><para> #: ../en/ch13-mq-collab.xml:172 msgid "" "Mercurial stores guards in the <filename role=\"special\">series</filename> " "file; the form in which they are stored is easy both to understand and to " "edit by hand. (In other words, you don't have to use the <command role=\"hg-" "ext-mq\">qguard</command> command if you don't want to; it's okay to simply " "edit the <filename role=\"special\">series</filename> file.)" msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch13-mq-collab.xml:184 msgid "Selecting the guards to use" msgstr "选择使用的条件" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch13-mq-collab.xml:186 msgid "" "The <command role=\"hg-ext-mq\">qselect</command> command determines which " "guards are active at a given time. The effect of this is to determine which " "patches MQ will apply the next time you run <command role=\"hg-ext-mq" "\">qpush</command>. It has no other effect; in particular, it doesn't do " "anything to patches that are already applied." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch13-mq-collab.xml:193 msgid "" "With no arguments, the <command role=\"hg-ext-mq\">qselect</command> command " "lists the guards currently in effect, one per line of output. Each argument " "is treated as the name of a guard to apply." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch13-mq-collab.xml:200 msgid "" "In case you're interested, the currently selected guards are stored in the " "<filename role=\"special\">guards</filename> file." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch13-mq-collab.xml:205 msgid "" "We can see the effect the selected guards have when we run <command role=\"hg-" "ext-mq\">qpush</command>." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch13-mq-collab.xml:210 msgid "" "A guard cannot start with a <quote><literal>+</literal></quote> or " "<quote><literal>-</literal></quote> character. The name of a guard must not " "contain white space, but most other characters are acceptable. If you try to " "use a guard with an invalid name, MQ will complain:" msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch13-mq-collab.xml:219 msgid "Changing the selected guards changes the patches that are applied." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch13-mq-collab.xml:224 msgid "" "You can see in the example below that negative guards take precedence over " "positive guards." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch13-mq-collab.xml:231 msgid "MQ's rules for applying patches" msgstr "MQ 应用补丁的规则" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch13-mq-collab.xml:233 msgid "" "The rules that MQ uses when deciding whether to apply a patch are as follows." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch13-mq-collab.xml:236 msgid "A patch that has no guards is always applied." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch13-mq-collab.xml:239 msgid "" "If the patch has any negative guard that matches any currently selected " "guard, the patch is skipped." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch13-mq-collab.xml:242 msgid "" "If the patch has any positive guard that matches any currently selected " "guard, the patch is applied." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch13-mq-collab.xml:245 msgid "" "If the patch has positive or negative guards, but none matches any currently " "selected guard, the patch is skipped." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch13-mq-collab.xml:252 msgid "Trimming the work environment" msgstr "修剪工作环境" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch13-mq-collab.xml:254 msgid "" "In working on the device driver I mentioned earlier, I don't apply the " "patches to a normal Linux kernel tree. Instead, I use a repository that " "contains only a snapshot of the source files and headers that are relevant to " "Infiniband development. This repository is 1% the size of a kernel " "repository, so it's easier to work with." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch13-mq-collab.xml:261 msgid "" "I then choose a <quote>base</quote> version on top of which the patches are " "applied. This is a snapshot of the Linux kernel tree as of a revision of my " "choosing. When I take the snapshot, I record the changeset ID from the " "kernel repository in the commit message. Since the snapshot preserves the " "<quote>shape</quote> and content of the relevant parts of the kernel tree, I " "can apply my patches on top of either my tiny repository or a normal kernel " "tree." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch13-mq-collab.xml:270 msgid "" "Normally, the base tree atop which the patches apply should be a snapshot of " "a very recent upstream tree. This best facilitates the development of " "patches that can easily be submitted upstream with few or no modifications." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch13-mq-collab.xml:277 msgid "Dividing up the <filename role=\"special\">series</filename> file" msgstr "分类补丁<filename role=\"special\">系列</filename>" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch13-mq-collab.xml:280 msgid "" "I categorise the patches in the <filename role=\"special\">series</filename> " "file into a number of logical groups. Each section of like patches begins " "with a block of comments that describes the purpose of the patches that " "follow." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch13-mq-collab.xml:286 msgid "" "The sequence of patch groups that I maintain follows. The ordering of these " "groups is important; I'll describe why after I introduce the groups." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch13-mq-collab.xml:290 msgid "" "The <quote>accepted</quote> group. Patches that the development team has " "submitted to the maintainer of the Infiniband subsystem, and which he has " "accepted, but which are not present in the snapshot that the tiny repository " "is based on. These are <quote>read only</quote> patches, present only to " "transform the tree into a similar state as it is in the upstream maintainer's " "repository." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch13-mq-collab.xml:298 msgid "" "The <quote>rework</quote> group. Patches that I have submitted, but that the " "upstream maintainer has requested modifications to before he will accept them." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch13-mq-collab.xml:303 msgid "" "The <quote>pending</quote> group. Patches that I have not yet submitted to " "the upstream maintainer, but which we have finished working on. These will be " "<quote>read only</quote> for a while. If the upstream maintainer accepts " "them upon submission, I'll move them to the end of the <quote>accepted</" "quote> group. If he requests that I modify any, I'll move them to the " "beginning of the <quote>rework</quote> group." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch13-mq-collab.xml:312 msgid "" "The <quote>in progress</quote> group. Patches that are actively being " "developed, and should not be submitted anywhere yet." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch13-mq-collab.xml:316 msgid "" "The <quote>backport</quote> group. Patches that adapt the source tree to " "older versions of the kernel tree." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch13-mq-collab.xml:320 msgid "" "The <quote>do not ship</quote> group. Patches that for some reason should " "never be submitted upstream. For example, one such patch might change " "embedded driver identification strings to make it easier to distinguish, in " "the field, between an out-of-tree version of the driver and a version shipped " "by a distribution vendor." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch13-mq-collab.xml:328 msgid "" "Now to return to the reasons for ordering groups of patches in this way. We " "would like the lowest patches in the stack to be as stable as possible, so " "that we will not need to rework higher patches due to changes in context. " "Putting patches that will never be changed first in the <filename role=" "\"special\">series</filename> file serves this purpose." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch13-mq-collab.xml:336 msgid "" "We would also like the patches that we know we'll need to modify to be " "applied on top of a source tree that resembles the upstream tree as closely " "as possible. This is why we keep accepted patches around for a while." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch13-mq-collab.xml:341 msgid "" "The <quote>backport</quote> and <quote>do not ship</quote> patches float at " "the end of the <filename role=\"special\">series</filename> file. The " "backport patches must be applied on top of all other patches, and the " "<quote>do not ship</quote> patches might as well stay out of harm's way." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch13-mq-collab.xml:350 msgid "Maintaining the patch series" msgstr "维护补丁系列" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch13-mq-collab.xml:352 msgid "" "In my work, I use a number of guards to control which patches are to be " "applied." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch13-mq-collab.xml:356 msgid "" "<quote>Accepted</quote> patches are guarded with <literal>accepted</" "literal>. I enable this guard most of the time. When I'm applying the " "patches on top of a tree where the patches are already present, I can turn " "this patch off, and the patches that follow it will apply cleanly." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch13-mq-collab.xml:363 msgid "" "Patches that are <quote>finished</quote>, but not yet submitted, have no " "guards. If I'm applying the patch stack to a copy of the upstream tree, I " "don't need to enable any guards in order to get a reasonably safe source tree." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch13-mq-collab.xml:369 msgid "" "Those patches that need reworking before being resubmitted are guarded with " "<literal>rework</literal>." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch13-mq-collab.xml:373 msgid "" "For those patches that are still under development, I use <literal>devel</" "literal>." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch13-mq-collab.xml:376 msgid "" "A backport patch may have several guards, one for each version of the kernel " "to which it applies. For example, a patch that backports a piece of code to " "2.6.9 will have a <literal>2.6.9</literal> guard." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch13-mq-collab.xml:381 msgid "" "This variety of guards gives me considerable flexibility in determining what " "kind of source tree I want to end up with. For most situations, the " "selection of appropriate guards is automated during the build process, but I " "can manually tune the guards to use for less common circumstances." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch13-mq-collab.xml:388 msgid "The art of writing backport patches" msgstr "编写向后移植补丁的艺术" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch13-mq-collab.xml:390 msgid "" "Using MQ, writing a backport patch is a simple process. All such a patch has " "to do is modify a piece of code that uses a kernel feature not present in the " "older version of the kernel, so that the driver continues to work correctly " "under that older version." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch13-mq-collab.xml:396 msgid "" "A useful goal when writing a good backport patch is to make your code look as " "if it was written for the older version of the kernel you're targeting. The " "less obtrusive the patch, the easier it will be to understand and maintain. " "If you're writing a collection of backport patches to avoid the <quote>rat's " "nest</quote> effect of lots of <literal>#ifdef</literal>s (hunks of source " "code that are only used conditionally) in your code, don't introduce version-" "dependent <literal>#ifdef</literal>s into the patches. Instead, write " "several patches, each of which makes unconditional changes, and control their " "application using guards." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch13-mq-collab.xml:409 msgid "" "There are two reasons to divide backport patches into a distinct group, away " "from the <quote>regular</quote> patches whose effects they modify. The first " "is that intermingling the two makes it more difficult to use a tool like the " "<literal role=\"hg-ext\">patchbomb</literal> extension to automate the " "process of submitting the patches to an upstream maintainer. The second is " "that a backport patch could perturb the context in which a subsequent regular " "patch is applied, making it impossible to apply the regular patch cleanly " "<emphasis>without</emphasis> the earlier backport patch already being applied." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch13-mq-collab.xml:424 msgid "Useful tips for developing with MQ" msgstr "使用 MQ 开发的技巧" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch13-mq-collab.xml:427 msgid "Organising patches in directories" msgstr "将补丁放到几个目录中" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch13-mq-collab.xml:429 msgid "" "If you're working on a substantial project with MQ, it's not difficult to " "accumulate a large number of patches. For example, I have one patch " "repository that contains over 250 patches." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch13-mq-collab.xml:434 msgid "" "If you can group these patches into separate logical categories, you can if " "you like store them in different directories; MQ has no problems with patch " "names that contain path separators." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch13-mq-collab.xml:441 msgid "Viewing the history of a patch" msgstr "察看补丁的历史" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch13-mq-collab.xml:443 msgid "" "If you're developing a set of patches over a long time, it's a good idea to " "maintain them in a repository, as discussed in <xref linkend=\"sec:mq:repo\"/" ">. If you do so, you'll quickly discover that using the <command role=\"hg-" "cmd\">hg diff</command> command to look at the history of changes to a patch " "is unworkable. This is in part because you're looking at the second " "derivative of the real code (a diff of a diff), but also because MQ adds " "noise to the process by modifying time stamps and directory names when it " "updates a patch." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch13-mq-collab.xml:455 msgid "" "However, you can use the <literal role=\"hg-ext\">extdiff</literal> " "extension, which is bundled with Mercurial, to turn a diff of two versions of " "a patch into something readable. To do this, you will need a third-party " "package called <literal role=\"package\">patchutils</literal> <citation>web:" "patchutils</citation>. This provides a command named <command>interdiff</" "command>, which shows the differences between two diffs as a diff. Used on " "two versions of the same diff, it generates a diff that represents the diff " "from the first to the second version." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch13-mq-collab.xml:466 msgid "" "You can enable the <literal role=\"hg-ext\">extdiff</literal> extension in " "the usual way, by adding a line to the <literal role=\"rc-extensions" "\">extensions</literal> section of your <filename role=\"special\">~/.hgrc</" "filename>." msgstr "" # #. &example.hg-interdiff; #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch13-mq-collab.xml:473 msgid "" "The <command>interdiff</command> command expects to be passed the names of " "two files, but the <literal role=\"hg-ext\">extdiff</literal> extension " "passes the program it runs a pair of directories, each of which can contain " "an arbitrary number of files. We thus need a small program that will run " "<command>interdiff</command> on each pair of files in these two directories. " "This program is available as <filename role=\"special\">hg-interdiff</" "filename> in the <filename class=\"directory\">examples</filename> directory " "of the source code repository that accompanies this book." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch13-mq-collab.xml:485 msgid "" "With the <filename role=\"special\">hg-interdiff</filename> program in your " "shell's search path, you can run it as follows, from inside an MQ patch " "directory:" msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch13-mq-collab.xml:489 msgid "" "Since you'll probably want to use this long-winded command a lot, you can get " "<literal role=\"hg-ext\">hgext</literal> to make it available as a normal " "Mercurial command, again by editing your <filename role=\"special\">~/.hgrc</" "filename>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch13-mq-collab.xml:496 msgid "" "This directs <literal role=\"hg-ext\">hgext</literal> to make an " "<literal>interdiff</literal> command available, so you can now shorten the " "previous invocation of <command role=\"hg-ext-extdiff\">extdiff</command> to " "something a little more wieldy." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><note><para> #: ../en/ch13-mq-collab.xml:504 msgid "" "The <command>interdiff</command> command works well only if the underlying " "files against which versions of a patch are generated remain the same. If " "you create a patch, modify the underlying files, and then regenerate the " "patch, <command>interdiff</command> may not produce useful output." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch13-mq-collab.xml:512 msgid "" "The <literal role=\"hg-ext\">extdiff</literal> extension is useful for more " "than merely improving the presentation of MQ patches. To read more about it, " "go to <xref linkend=\"sec:hgext:extdiff\"/>." msgstr "" #. type: Content of: <book><chapter><title> #: ../en/ch14-hgext.xml:5 msgid "Adding functionality with extensions" msgstr "使用扩展增加功能" #. type: Content of: <book><chapter><para> #: ../en/ch14-hgext.xml:7 msgid "" "While the core of Mercurial is quite complete from a functionality " "standpoint, it's deliberately shorn of fancy features. This approach of " "preserving simplicity keeps the software easy to deal with for both " "maintainers and users." msgstr "" #. type: Content of: <book><chapter><para> #: ../en/ch14-hgext.xml:12 msgid "" "However, Mercurial doesn't box you in with an inflexible command set: you can " "add features to it as <emphasis>extensions</emphasis> (sometimes known as " "<emphasis>plugins</emphasis>). We've already discussed a few of these " "extensions in earlier chapters." msgstr "" #. type: Content of: <book><chapter><itemizedlist><listitem><para> #: ../en/ch14-hgext.xml:18 msgid "" "<xref linkend=\"sec:tour-merge:fetch\"/> covers the <literal role=\"hg-ext" "\">fetch</literal> extension; this combines pulling new changes and merging " "them with local changes into a single command, <command role=\"hg-ext-fetch" "\">fetch</command>." msgstr "" #. type: Content of: <book><chapter><itemizedlist><listitem><para> #: ../en/ch14-hgext.xml:24 msgid "" "In <xref linkend=\"chap:hook\"/>, we covered several extensions that are " "useful for hook-related functionality: <literal role=\"hg-ext\">acl</literal> " "adds access control lists; <literal role=\"hg-ext\">bugzilla</literal> adds " "integration with the Bugzilla bug tracking system; and <literal role=\"hg-ext" "\">notify</literal> sends notification emails on new changes." msgstr "" #. type: Content of: <book><chapter><itemizedlist><listitem><para> #: ../en/ch14-hgext.xml:33 msgid "" "The Mercurial Queues patch management extension is so invaluable that it " "merits two chapters and an appendix all to itself. <xref linkend=\"chap:mq\"/" "> covers the basics; <xref linkend=\"chap:mq-collab\"/> discusses advanced " "topics; and <xref linkend=\"chap:mqref\"/> goes into detail on each command." msgstr "" #. type: Content of: <book><chapter><para> #: ../en/ch14-hgext.xml:43 msgid "" "In this chapter, we'll cover some of the other extensions that are available " "for Mercurial, and briefly touch on some of the machinery you'll need to know " "about if you want to write an extension of your own." msgstr "" #. type: Content of: <book><chapter><itemizedlist><listitem><para> #: ../en/ch14-hgext.xml:48 msgid "" "In <xref linkend=\"sec:hgext:inotify\"/>, we'll discuss the possibility of " "<emphasis>huge</emphasis> performance improvements using the <literal role=" "\"hg-ext\">inotify</literal> extension." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch14-hgext.xml:55 msgid "" "Improve performance with the <literal role=\"hg-ext\">inotify</literal> " "extension" msgstr "使用扩展 <literal role=\"hg-ext\">inotify</literal> 以提高性能" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch14-hgext.xml:58 msgid "" "Are you interested in having some of the most common Mercurial operations run " "as much as a hundred times faster? Read on!" msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch14-hgext.xml:62 msgid "" "Mercurial has great performance under normal circumstances. For example, " "when you run the <command role=\"hg-cmd\">hg status</command> command, " "Mercurial has to scan almost every directory and file in your repository so " "that it can display file status. Many other Mercurial commands need to do " "the same work behind the scenes; for example, the <command role=\"hg-cmd\">hg " "diff</command> command uses the status machinery to avoid doing an expensive " "comparison operation on files that obviously haven't changed." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch14-hgext.xml:72 msgid "" "Because obtaining file status is crucial to good performance, the authors of " "Mercurial have optimised this code to within an inch of its life. However, " "there's no avoiding the fact that when you run <command role=\"hg-cmd\">hg " "status</command>, Mercurial is going to have to perform at least one " "expensive system call for each managed file to determine whether it's changed " "since the last time Mercurial checked. For a sufficiently large repository, " "this can take a long time." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch14-hgext.xml:82 msgid "" "To put a number on the magnitude of this effect, I created a repository " "containing 150,000 managed files. I timed <command role=\"hg-cmd\">hg " "status</command> as taking ten seconds to run, even when <emphasis>none</" "emphasis> of those files had been modified." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch14-hgext.xml:88 msgid "" "Many modern operating systems contain a file notification facility. If a " "program signs up to an appropriate service, the operating system will notify " "it every time a file of interest is created, modified, or deleted. On Linux " "systems, the kernel component that does this is called <literal>inotify</" "literal>." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch14-hgext.xml:95 msgid "" "Mercurial's <literal role=\"hg-ext\">inotify</literal> extension talks to the " "kernel's <literal>inotify</literal> component to optimise <command role=\"hg-" "cmd\">hg status</command> commands. The extension has two components. A " "daemon sits in the background and receives notifications from the " "<literal>inotify</literal> subsystem. It also listens for connections from a " "regular Mercurial command. The extension modifies Mercurial's behavior so " "that instead of scanning the filesystem, it queries the daemon. Since the " "daemon has perfect information about the state of the repository, it can " "respond with a result instantaneously, avoiding the need to scan every " "directory and file in the repository." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch14-hgext.xml:108 msgid "" "Recall the ten seconds that I measured plain Mercurial as taking to run " "<command role=\"hg-cmd\">hg status</command> on a 150,000 file repository. " "With the <literal role=\"hg-ext\">inotify</literal> extension enabled, the " "time dropped to 0.1 seconds, a factor of <emphasis>one hundred</emphasis> " "faster." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch14-hgext.xml:115 msgid "Before we continue, please pay attention to some caveats." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch14-hgext.xml:118 msgid "" "The <literal role=\"hg-ext\">inotify</literal> extension is Linux-specific. " "Because it interfaces directly to the Linux kernel's <literal>inotify</" "literal> subsystem, it does not work on other operating systems." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch14-hgext.xml:123 msgid "" "It should work on any Linux distribution that was released after early 2005. " "Older distributions are likely to have a kernel that lacks <literal>inotify</" "literal>, or a version of <literal>glibc</literal> that does not have the " "necessary interfacing support." msgstr "" #. type: Content of: <book><chapter><sect1><itemizedlist><listitem><para> #: ../en/ch14-hgext.xml:130 msgid "" "Not all filesystems are suitable for use with the <literal role=\"hg-ext" "\">inotify</literal> extension. Network filesystems such as NFS are a non-" "starter, for example, particularly if you're running Mercurial on several " "systems, all mounting the same network filesystem. The kernel's " "<literal>inotify</literal> system has no way of knowing about changes made on " "another system. Most local filesystems (e.g. ext3, XFS, ReiserFS) should " "work fine." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch14-hgext.xml:141 msgid "" "The <literal role=\"hg-ext\">inotify</literal> extension is not yet shipped " "with Mercurial as of May 2007, so it's a little more involved to set up than " "other extensions. But the performance improvement is worth it!" msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch14-hgext.xml:146 msgid "" "The extension currently comes in two parts: a set of patches to the Mercurial " "source code, and a library of Python bindings to the <literal>inotify</" "literal> subsystem." msgstr "" #. type: Content of: <book><chapter><sect1><note><para> #: ../en/ch14-hgext.xml:150 msgid "" "There are <emphasis>two</emphasis> Python <literal>inotify</literal> binding " "libraries. One of them is called <literal>pyinotify</literal>, and is " "packaged by some Linux distributions as <literal>python-inotify</literal>. " "This is <emphasis>not</emphasis> the one you'll need, as it is too buggy and " "inefficient to be practical." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch14-hgext.xml:157 msgid "" "To get going, it's best to already have a functioning copy of Mercurial " "installed." msgstr "" #. type: Content of: <book><chapter><sect1><note><para> #: ../en/ch14-hgext.xml:160 msgid "" "If you follow the instructions below, you'll be <emphasis>replacing</" "emphasis> and overwriting any existing installation of Mercurial that you " "might already have, using the latest <quote>bleeding edge</quote> Mercurial " "code. Don't say you weren't warned!" msgstr "" #. type: Content of: <book><chapter><sect1><orderedlist><listitem><para> #: ../en/ch14-hgext.xml:167 msgid "" "Clone the Python <literal>inotify</literal> binding repository. Build and " "install it." msgstr "" #. type: Content of: <book><chapter><sect1><orderedlist><listitem><para> #: ../en/ch14-hgext.xml:174 msgid "" "Clone the <filename class=\"directory\">crew</filename> Mercurial " "repository. Clone the <literal role=\"hg-ext\">inotify</literal> patch " "repository so that Mercurial Queues will be able to apply patches to your " "cope of the <filename class=\"directory\">crew</filename> repository." msgstr "" #. type: Content of: <book><chapter><sect1><orderedlist><listitem><para> #: ../en/ch14-hgext.xml:184 msgid "" "Make sure that you have the Mercurial Queues extension, <literal role=\"hg-ext" "\">mq</literal>, enabled. If you've never used MQ, read <xref linkend=\"sec:" "mq:start\"/> to get started quickly." msgstr "" #. type: Content of: <book><chapter><sect1><orderedlist><listitem><para> #: ../en/ch14-hgext.xml:190 msgid "" "Go into the <filename class=\"directory\">inotify</filename> repo, and apply " "all of the <literal role=\"hg-ext\">inotify</literal> patches using the " "<option role=\"hg-ext-mq-cmd-qpush-opt\">hg -a</option> option to the " "<command role=\"hg-ext-mq\">qpush</command> command." msgstr "" #. type: Content of: <book><chapter><sect1><orderedlist><listitem><para> #: ../en/ch14-hgext.xml:199 msgid "" "If you get an error message from <command role=\"hg-ext-mq\">qpush</command>, " "you should not continue. Instead, ask for help." msgstr "" #. type: Content of: <book><chapter><sect1><orderedlist><listitem><para> #: ../en/ch14-hgext.xml:203 msgid "Build and install the patched version of Mercurial." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch14-hgext.xml:209 msgid "" "Once you've build a suitably patched version of Mercurial, all you need to do " "to enable the <literal role=\"hg-ext\">inotify</literal> extension is add an " "entry to your <filename role=\"special\">~/.hgrc</filename>." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch14-hgext.xml:214 msgid "" "When the <literal role=\"hg-ext\">inotify</literal> extension is enabled, " "Mercurial will automatically and transparently start the status daemon the " "first time you run a command that needs status in a repository. It runs one " "status daemon per repository." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch14-hgext.xml:220 msgid "" "The status daemon is started silently, and runs in the background. If you " "look at a list of running processes after you've enabled the <literal role=" "\"hg-ext\">inotify</literal> extension and run a few commands in different " "repositories, you'll thus see a few <literal>hg</literal> processes sitting " "around, waiting for updates from the kernel and queries from Mercurial." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch14-hgext.xml:228 msgid "" "The first time you run a Mercurial command in a repository when you have the " "<literal role=\"hg-ext\">inotify</literal> extension enabled, it will run " "with about the same performance as a normal Mercurial command. This is " "because the status daemon needs to perform a normal status scan so that it " "has a baseline against which to apply later updates from the kernel. " "However, <emphasis>every</emphasis> subsequent command that does any kind of " "status check should be noticeably faster on repositories of even fairly " "modest size. Better yet, the bigger your repository is, the greater a " "performance advantage you'll see. The <literal role=\"hg-ext\">inotify</" "literal> daemon makes status operations almost instantaneous on repositories " "of all sizes!" msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch14-hgext.xml:242 msgid "" "If you like, you can manually start a status daemon using the <command role=" "\"hg-ext-inotify\">inserve</command> command. This gives you slightly finer " "control over how the daemon ought to run. This command will of course only " "be available when the <literal role=\"hg-ext\">inotify</literal> extension is " "enabled." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch14-hgext.xml:249 msgid "" "When you're using the <literal role=\"hg-ext\">inotify</literal> extension, " "you should notice <emphasis>no difference at all</emphasis> in Mercurial's " "behavior, with the sole exception of status-related commands running a whole " "lot faster than they used to. You should specifically expect that commands " "will not print different output; neither should they give different results. " "If either of these situations occurs, please report a bug." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch14-hgext.xml:260 msgid "" "Flexible diff support with the <literal role=\"hg-ext\">extdiff</literal> " "extension" msgstr "使用扩展 <literal role=\"hg-ext\">extdiff</literal> 以扩展差异支持" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch14-hgext.xml:263 msgid "" "Mercurial's built-in <command role=\"hg-cmd\">hg diff</command> command " "outputs plaintext unified diffs." msgstr "" "Mercurial 内置命令 <command role=\"hg-cmd\">hg diff</command> 的输出与统一差异" "不同。" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch14-hgext.xml:268 msgid "" "If you would like to use an external tool to display modifications, you'll " "want to use the <literal role=\"hg-ext\">extdiff</literal> extension. This " "will let you use, for example, a graphical diff tool." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch14-hgext.xml:273 msgid "" "The <literal role=\"hg-ext\">extdiff</literal> extension is bundled with " "Mercurial, so it's easy to set up. In the <literal role=\"rc-extensions" "\">extensions</literal> section of your <filename role=\"special\">~/.hgrc</" "filename>, simply add a one-line entry to enable the extension." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch14-hgext.xml:280 msgid "" "This introduces a command named <command role=\"hg-ext-extdiff\">extdiff</" "command>, which by default uses your system's <command>diff</command> command " "to generate a unified diff in the same form as the built-in <command role=" "\"hg-cmd\">hg diff</command> command." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch14-hgext.xml:288 msgid "" "The result won't be exactly the same as with the built-in <command role=\"hg-" "cmd\">hg diff</command> variations, because the output of <command>diff</" "command> varies from one system to another, even when passed the same options." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch14-hgext.xml:293 msgid "" "As the <quote><literal>making snapshot</literal></quote> lines of output " "above imply, the <command role=\"hg-ext-extdiff\">extdiff</command> command " "works by creating two snapshots of your source tree. The first snapshot is " "of the source revision; the second, of the target revision or working " "directory. The <command role=\"hg-ext-extdiff\">extdiff</command> command " "generates these snapshots in a temporary directory, passes the name of each " "directory to an external diff viewer, then deletes the temporary directory. " "For efficiency, it only snapshots the directories and files that have changed " "between the two revisions." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch14-hgext.xml:306 msgid "" "Snapshot directory names have the same base name as your repository. If your " "repository path is <filename class=\"directory\">/quux/bar/foo</filename>, " "then <filename class=\"directory\">foo</filename> will be the name of each " "snapshot directory. Each snapshot directory name has its changeset ID " "appended, if appropriate. If a snapshot is of revision " "<literal>a631aca1083f</literal>, the directory will be named <filename class=" "\"directory\">foo.a631aca1083f</filename>. A snapshot of the working " "directory won't have a changeset ID appended, so it would just be <filename " "class=\"directory\">foo</filename> in this example. To see what this looks " "like in practice, look again at the <command role=\"hg-ext-extdiff\">extdiff</" "command> example above. Notice that the diff has the snapshot directory " "names embedded in its header." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch14-hgext.xml:322 msgid "" "The <command role=\"hg-ext-extdiff\">extdiff</command> command accepts two " "important options. The <option role=\"hg-ext-extdiff-cmd-extdiff-opt\">hg -p</" "option> option lets you choose a program to view differences with, instead of " "<command>diff</command>. With the <option role=\"hg-ext-extdiff-cmd-extdiff-" "opt\">hg -o</option> option, you can change the options that <command role=" "\"hg-ext-extdiff\">extdiff</command> passes to the program (by default, these " "options are <quote><literal>-Npru</literal></quote>, which only make sense if " "you're running <command>diff</command>). In other respects, the <command " "role=\"hg-ext-extdiff\">extdiff</command> command acts similarly to the built-" "in <command role=\"hg-cmd\">hg diff</command> command: you use the same " "option names, syntax, and arguments to specify the revisions you want, the " "files you want, and so on." msgstr "" # #. type: Content of: <book><chapter><sect1><para> #: ../en/ch14-hgext.xml:339 msgid "" "As an example, here's how to run the normal system <command>diff</command> " "command, getting it to generate context diffs (using the <option role=\"cmd-" "opt-diff\">-c</option> option) instead of unified diffs, and five lines of " "context instead of the default three (passing <literal>5</literal> as the " "argument to the <option role=\"cmd-opt-diff\">-C</option> option)." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch14-hgext.xml:348 msgid "" "Launching a visual diff tool is just as easy. Here's how to launch the " "<command>kdiff3</command> viewer." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch14-hgext.xml:352 msgid "" "If your diff viewing command can't deal with directories, you can easily work " "around this with a little scripting. For an example of such scripting in " "action with the <literal role=\"hg-ext\">mq</literal> extension and the " "<command>interdiff</command> command, see <xref linkend=\"mq-collab:tips:" "interdiff\"/>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch14-hgext.xml:360 msgid "Defining command aliases" msgstr "定义命令的别名" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch14-hgext.xml:362 msgid "" "It can be cumbersome to remember the options to both the <command role=\"hg-" "ext-extdiff\">extdiff</command> command and the diff viewer you want to use, " "so the <literal role=\"hg-ext\">extdiff</literal> extension lets you define " "<emphasis>new</emphasis> commands that will invoke your diff viewer with " "exactly the right options." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch14-hgext.xml:369 msgid "" "All you need to do is edit your <filename role=\"special\">~/.hgrc</" "filename>, and add a section named <literal role=\"rc-extdiff\">extdiff</" "literal>. Inside this section, you can define multiple commands. Here's how " "to add a <literal>kdiff3</literal> command. Once you've defined this, you " "can type <quote><literal>hg kdiff3</literal></quote> and the <literal role=" "\"hg-ext\">extdiff</literal> extension will run <command>kdiff3</command> for " "you." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch14-hgext.xml:379 msgid "" "If you leave the right hand side of the definition empty, as above, the " "<literal role=\"hg-ext\">extdiff</literal> extension uses the name of the " "command you defined as the name of the external program to run. But these " "names don't have to be the same. Here, we define a command named " "<quote><literal>hg wibble</literal></quote>, which runs <command>kdiff3</" "command>." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch14-hgext.xml:389 msgid "" "You can also specify the default options that you want to invoke your diff " "viewing program with. The prefix to use is <quote><literal>opts.</literal></" "quote>, followed by the name of the command to which the options apply. This " "example defines a <quote><literal>hg vimdiff</literal></quote> command that " "runs the <command>vim</command> editor's <literal>DirDiff</literal> extension." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch14-hgext.xml:403 msgid "" "Cherrypicking changes with the <literal role=\"hg-ext\">transplant</literal> " "extension" msgstr "使用扩展 <literal role=\"hg-ext\">transplant</literal> 以挑选修改" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch14-hgext.xml:406 msgid "Need to have a long chat with Brendan about this." msgstr "" #. type: Content of: <book><chapter><sect1><title> #: ../en/ch14-hgext.xml:410 msgid "" "Send changes via email with the <literal role=\"hg-ext\">patchbomb</literal> " "extension" msgstr "" "使用扩展 <literal role=\"hg-ext\">patchbomb</literal> 通过 email 发送修改" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch14-hgext.xml:413 msgid "" "Many projects have a culture of <quote>change review</quote>, in which people " "send their modifications to a mailing list for others to read and comment on " "before they commit the final version to a shared repository. Some projects " "have people who act as gatekeepers; they apply changes from other people to a " "repository to which those others don't have access." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch14-hgext.xml:421 msgid "" "Mercurial makes it easy to send changes over email for review or application, " "via its <literal role=\"hg-ext\">patchbomb</literal> extension. The " "extension is so named because changes are formatted as patches, and it's " "usual to send one changeset per email message. Sending a long series of " "changes by email is thus much like <quote>bombing</quote> the recipient's " "inbox, hence <quote>patchbomb</quote>." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch14-hgext.xml:429 msgid "" "As usual, the basic configuration of the <literal role=\"hg-ext\">patchbomb</" "literal> extension takes just one or two lines in your <filename role=" "\"special\"> /.hgrc</filename>." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch14-hgext.xml:435 msgid "" "Once you've enabled the extension, you will have a new command available, " "named <command role=\"hg-ext-patchbomb\">email</command>." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch14-hgext.xml:439 msgid "" "The safest and best way to invoke the <command role=\"hg-ext-patchbomb" "\">email</command> command is to <emphasis>always</emphasis> run it first " "with the <option role=\"hg-ext-patchbomb-cmd-email-opt\">hg -n</option> " "option. This will show you what the command <emphasis>would</emphasis> send, " "without actually sending anything. Once you've had a quick glance over the " "changes and verified that you are sending the right ones, you can rerun the " "same command, with the <option role=\"hg-ext-patchbomb-cmd-email-opt\">hg -n</" "option> option removed." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch14-hgext.xml:450 msgid "" "The <command role=\"hg-ext-patchbomb\">email</command> command accepts the " "same kind of revision syntax as every other Mercurial command. For example, " "this command will send every revision between 7 and <literal>tip</literal>, " "inclusive." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch14-hgext.xml:455 msgid "" "You can also specify a <emphasis>repository</emphasis> to compare with. If " "you provide a repository but no revisions, the <command role=\"hg-ext-" "patchbomb\">email</command> command will send all revisions in the local " "repository that are not present in the remote repository. If you " "additionally specify revisions or a branch name (the latter using the <option " "role=\"hg-ext-patchbomb-cmd-email-opt\">hg -b</option> option), this will " "constrain the revisions sent." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch14-hgext.xml:464 msgid "" "It's perfectly safe to run the <command role=\"hg-ext-patchbomb\">email</" "command> command without the names of the people you want to send to: if you " "do this, it will just prompt you for those values interactively. (If you're " "using a Linux or Unix-like system, you should have enhanced " "<literal>readline</literal>-style editing capabilities when entering those " "headers, too, which is useful.)" msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch14-hgext.xml:472 msgid "" "When you are sending just one revision, the <command role=\"hg-ext-patchbomb" "\">email</command> command will by default use the first line of the " "changeset description as the subject of the single email message it sends." msgstr "" #. type: Content of: <book><chapter><sect1><para> #: ../en/ch14-hgext.xml:477 msgid "" "If you send multiple revisions, the <command role=\"hg-ext-patchbomb\">email</" "command> command will usually send one message per changeset. It will " "preface the series with an introductory message, in which you should describe " "the purpose of the series of changes you're sending." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><title> #: ../en/ch14-hgext.xml:484 msgid "Changing the behavior of patchbombs" msgstr "修改 patchbomb 的行为" #. type: Content of: <book><chapter><sect1><sect2><para> #: ../en/ch14-hgext.xml:486 msgid "" "Not every project has exactly the same conventions for sending changes in " "email; the <literal role=\"hg-ext\">patchbomb</literal> extension tries to " "accommodate a number of variations through command line options." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch14-hgext.xml:492 msgid "" "You can write a subject for the introductory message on the command line " "using the <option role=\"hg-ext-patchbomb-cmd-email-opt\">hg -s</option> " "option. This takes one argument, the text of the subject to use." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch14-hgext.xml:498 msgid "" "To change the email address from which the messages originate, use the " "<option role=\"hg-ext-patchbomb-cmd-email-opt\">hg -f</option> option. This " "takes one argument, the email address to use." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch14-hgext.xml:504 msgid "" "The default behavior is to send unified diffs (see <xref linkend=\"sec:mq:" "patch\"/> for a description of the format), one per message. You can send a " "binary bundle instead with the <option role=\"hg-ext-patchbomb-cmd-email-opt" "\">hg -b</option> option." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch14-hgext.xml:512 msgid "" "Unified diffs are normally prefaced with a metadata header. You can omit " "this, and send unadorned diffs, with the <option role=\"hg-ext-patchbomb-cmd-" "email-opt\">hg --plain</option> option." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch14-hgext.xml:518 msgid "" "Diffs are normally sent <quote>inline</quote>, in the same body part as the " "description of a patch. This makes it easiest for the largest number of " "readers to quote and respond to parts of a diff, as some mail clients will " "only quote the first MIME body part in a message. If you'd prefer to send the " "description and the diff in separate body parts, use the <option role=\"hg-" "ext-patchbomb-cmd-email-opt\">hg -a</option> option." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch14-hgext.xml:528 msgid "" "Instead of sending mail messages, you can write them to an <literal>mbox</" "literal>-format mail folder using the <option role=\"hg-ext-patchbomb-cmd-" "email-opt\">hg -m</option> option. That option takes one argument, the name " "of the file to write to." msgstr "" #. type: Content of: <book><chapter><sect1><sect2><itemizedlist><listitem><para> #: ../en/ch14-hgext.xml:535 msgid "" "If you would like to add a <command>diffstat</command>-format summary to each " "patch, and one to the introductory message, use the <option role=\"hg-ext-" "patchbomb-cmd-email-opt\">hg -d</option> option. The <command>diffstat</" "command> command displays a table containing the name of each file patched, " "the number of lines affected, and a histogram showing how much each file is " "modified. This gives readers a qualitative glance at how complex a patch is." msgstr ""