CINXE.COM
PEP 374 – Choosing a distributed VCS for the Python project | peps.python.org
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="color-scheme" content="light dark"> <title>PEP 374 – Choosing a distributed VCS for the Python project | peps.python.org</title> <link rel="shortcut icon" href="../_static/py.png"> <link rel="canonical" href="https://peps.python.org/pep-0374/"> <link rel="stylesheet" href="../_static/style.css" type="text/css"> <link rel="stylesheet" href="../_static/mq.css" type="text/css"> <link rel="stylesheet" href="../_static/pygments.css" type="text/css" media="(prefers-color-scheme: light)" id="pyg-light"> <link rel="stylesheet" href="../_static/pygments_dark.css" type="text/css" media="(prefers-color-scheme: dark)" id="pyg-dark"> <link rel="alternate" type="application/rss+xml" title="Latest PEPs" href="https://peps.python.org/peps.rss"> <meta property="og:title" content='PEP 374 – Choosing a distributed VCS for the Python project | peps.python.org'> <meta property="og:description" content="Python Enhancement Proposals (PEPs)"> <meta property="og:type" content="website"> <meta property="og:url" content="https://peps.python.org/pep-0374/"> <meta property="og:site_name" content="Python Enhancement Proposals (PEPs)"> <meta property="og:image" content="https://peps.python.org/_static/og-image.png"> <meta property="og:image:alt" content="Python PEPs"> <meta property="og:image:width" content="200"> <meta property="og:image:height" content="200"> <meta name="description" content="Python Enhancement Proposals (PEPs)"> <meta name="theme-color" content="#3776ab"> </head> <body> <svg xmlns="http://www.w3.org/2000/svg" style="display: none;"> <symbol id="svg-sun-half" viewBox="0 0 24 24" pointer-events="all"> <title>Following system colour scheme</title> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="9"></circle> <path d="M12 3v18m0-12l4.65-4.65M12 14.3l7.37-7.37M12 19.6l8.85-8.85"></path> </svg> </symbol> <symbol id="svg-moon" viewBox="0 0 24 24" pointer-events="all"> <title>Selected dark colour scheme</title> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path stroke="none" d="M0 0h24v24H0z" fill="none"></path> <path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path> </svg> </symbol> <symbol id="svg-sun" viewBox="0 0 24 24" pointer-events="all"> <title>Selected light colour scheme</title> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="5"></circle> <line x1="12" y1="1" x2="12" y2="3"></line> <line x1="12" y1="21" x2="12" y2="23"></line> <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line> <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line> <line x1="1" y1="12" x2="3" y2="12"></line> <line x1="21" y1="12" x2="23" y2="12"></line> <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line> <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line> </svg> </symbol> </svg> <script> document.documentElement.dataset.colour_scheme = localStorage.getItem("colour_scheme") || "auto" </script> <section id="pep-page-section"> <header> <h1>Python Enhancement Proposals</h1> <ul class="breadcrumbs"> <li><a href="https://www.python.org/" title="The Python Programming Language">Python</a> » </li> <li><a href="../pep-0000/">PEP Index</a> » </li> <li>PEP 374</li> </ul> <button id="colour-scheme-cycler" onClick="setColourScheme(nextColourScheme())"> <svg aria-hidden="true" class="colour-scheme-icon-when-auto"><use href="#svg-sun-half"></use></svg> <svg aria-hidden="true" class="colour-scheme-icon-when-dark"><use href="#svg-moon"></use></svg> <svg aria-hidden="true" class="colour-scheme-icon-when-light"><use href="#svg-sun"></use></svg> <span class="visually-hidden">Toggle light / dark / auto colour theme</span> </button> </header> <article> <section id="pep-content"> <h1 class="page-title">PEP 374 – Choosing a distributed VCS for the Python project</h1> <dl class="rfc2822 field-list simple"> <dt class="field-odd">Author<span class="colon">:</span></dt> <dd class="field-odd">Brett Cannon <brett at python.org>, Stephen J. Turnbull <stephen at xemacs.org>, Alexandre Vassalotti <alexandre at peadrop.com>, Barry Warsaw <barry at python.org>, Dirkjan Ochtman <dirkjan at ochtman.nl></dd> <dt class="field-even">Status<span class="colon">:</span></dt> <dd class="field-even"><abbr title="Accepted and implementation complete, or no longer active">Final</abbr></dd> <dt class="field-odd">Type<span class="colon">:</span></dt> <dd class="field-odd"><abbr title="Normative PEP describing or proposing a change to a Python community process, workflow or governance">Process</abbr></dd> <dt class="field-even">Created<span class="colon">:</span></dt> <dd class="field-even">07-Nov-2008</dd> <dt class="field-odd">Post-History<span class="colon">:</span></dt> <dd class="field-odd">07-Nov-2008, 22-Jan-2009</dd> </dl> <hr class="docutils" /> <section id="contents"> <details><summary>Table of Contents</summary><ul class="simple"> <li><a class="reference internal" href="#rationale">Rationale</a></li> <li><a class="reference internal" href="#terminology">Terminology</a></li> <li><a class="reference internal" href="#typical-workflow">Typical Workflow</a></li> <li><a class="reference internal" href="#contenders">Contenders</a></li> <li><a class="reference internal" href="#interoperability">Interoperability</a></li> <li><a class="reference internal" href="#usage-scenarios">Usage Scenarios</a><ul> <li><a class="reference internal" href="#initial-setup">Initial Setup</a><ul> <li><a class="reference internal" href="#svn">svn</a></li> <li><a class="reference internal" href="#bzr">bzr</a></li> <li><a class="reference internal" href="#hg">hg</a></li> <li><a class="reference internal" href="#id1">git</a></li> </ul> </li> <li><a class="reference internal" href="#one-off-checkout">One-Off Checkout</a><ul> <li><a class="reference internal" href="#id2">svn</a></li> <li><a class="reference internal" href="#id3">bzr</a></li> <li><a class="reference internal" href="#id4">hg</a></li> <li><a class="reference internal" href="#id5">git</a></li> </ul> </li> <li><a class="reference internal" href="#backing-out-changes">Backing Out Changes</a><ul> <li><a class="reference internal" href="#id6">svn</a></li> <li><a class="reference internal" href="#id7">bzr</a></li> <li><a class="reference internal" href="#id8">hg</a></li> <li><a class="reference internal" href="#id9">git</a></li> </ul> </li> <li><a class="reference internal" href="#patch-review">Patch Review</a><ul> <li><a class="reference internal" href="#id10">svn</a></li> <li><a class="reference internal" href="#id11">bzr</a></li> <li><a class="reference internal" href="#id12">hg</a></li> <li><a class="reference internal" href="#id13">git</a></li> </ul> </li> <li><a class="reference internal" href="#backport">Backport</a><ul> <li><a class="reference internal" href="#id14">svn</a></li> <li><a class="reference internal" href="#id15">bzr</a></li> <li><a class="reference internal" href="#id16">hg</a></li> <li><a class="reference internal" href="#id17">git</a></li> </ul> </li> <li><a class="reference internal" href="#coordinated-development-of-a-new-feature">Coordinated Development of a New Feature</a><ul> <li><a class="reference internal" href="#id18">svn</a></li> </ul> </li> <li><a class="reference internal" href="#separation-of-issue-dependencies">Separation of Issue Dependencies</a><ul> <li><a class="reference internal" href="#id19">svn</a></li> <li><a class="reference internal" href="#id20">bzr</a></li> <li><a class="reference internal" href="#id21">hg</a></li> <li><a class="reference internal" href="#id22">git</a></li> </ul> </li> <li><a class="reference internal" href="#doing-a-python-release">Doing a Python Release</a><ul> <li><a class="reference internal" href="#id23">bzr</a></li> <li><a class="reference internal" href="#id24">hg</a></li> <li><a class="reference internal" href="#id25">git</a></li> </ul> </li> </ul> </li> <li><a class="reference internal" href="#platform-tool-support">Platform/Tool Support</a><ul> <li><a class="reference internal" href="#operating-systems">Operating Systems</a></li> <li><a class="reference internal" href="#crlf-lf-support">CRLF -> LF Support</a></li> <li><a class="reference internal" href="#case-insensitive-filesystem-support">Case-insensitive filesystem support</a></li> <li><a class="reference internal" href="#tools">Tools</a></li> </ul> </li> <li><a class="reference internal" href="#usage-on-top-of-subversion">Usage On Top Of Subversion</a></li> <li><a class="reference internal" href="#server-support">Server Support</a></li> <li><a class="reference internal" href="#development">Development</a></li> <li><a class="reference internal" href="#special-features">Special Features</a><ul> <li><a class="reference internal" href="#id26">bzr</a></li> <li><a class="reference internal" href="#id27">hg</a></li> <li><a class="reference internal" href="#id28">git</a></li> </ul> </li> <li><a class="reference internal" href="#tests-impressions">Tests/Impressions</a><ul> <li><a class="reference internal" href="#barrier-to-entry">Barrier to Entry</a></li> <li><a class="reference internal" href="#performance-of-basic-information-functionality">Performance of basic information functionality</a></li> <li><a class="reference internal" href="#figuring-out-what-command-to-use-from-built-in-help">Figuring out what command to use from built-in help</a></li> <li><a class="reference internal" href="#updating-a-checkout">Updating a checkout</a></li> </ul> </li> <li><a class="reference internal" href="#decision">Decision</a><ul> <li><a class="reference internal" href="#why-mercurial-over-subversion">Why Mercurial over Subversion</a></li> <li><a class="reference internal" href="#why-mercurial-over-other-dvcss">Why Mercurial over other DVCSs</a></li> </ul> </li> <li><a class="reference internal" href="#transition-plan">Transition Plan</a></li> <li><a class="reference internal" href="#copyright">Copyright</a></li> </ul> </details></section> <section id="rationale"> <h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2> <p>Python has been using a centralized version control system (VCS; first CVS, now Subversion) for years to great effect. Having a master copy of the official version of Python provides people with a single place to always get the official Python source code. It has also allowed for the storage of the history of the language, mostly for help with development, but also for posterity. And of course the V in VCS is very helpful when developing.</p> <p>But a centralized version control system has its drawbacks. First and foremost, in order to have the benefits of version control with Python in a seamless fashion, one must be a “core developer” (i.e. someone with commit privileges on the master copy of Python). People who are not core developers but who wish to work with Python’s revision tree, e.g. anyone writing a patch for Python or creating a custom version, do not have direct tool support for revisions. This can be quite a limitation, since these non-core developers cannot easily do basic tasks such as reverting changes to a previously saved state, creating branches, publishing one’s changes with full revision history, etc. For non-core developers, the last safe tree state is one the Python developers happen to set, and this prevents safe development. This second-class citizenship is a hindrance to people who wish to contribute to Python with a patch of any complexity and want a way to incrementally save their progress to make their development lives easier.</p> <p>There is also the issue of having to be online to be able to commit one’s work. Because centralized VCSs keep a central copy that stores all revisions, one must have Internet access in order for their revisions to be stored; no Net, no commit. This can be annoying if you happen to be traveling and lack any Internet. There is also the situation of someone wishing to contribute to Python but having a bad Internet connection where committing is time-consuming and expensive and it might work out better to do it in a single step.</p> <p>Another drawback to a centralized VCS is that a common use case is for a developer to revise patches in response to review comments. This is more difficult with a centralized model because there’s no place to contain intermediate work. It’s either all checked in or none of it is checked in. In the centralized VCS, it’s also very difficult to track changes to the trunk as they are committed, while you’re working on your feature or bug fix branch. This increases the risk that such branches will grow stale, out-dated, or that merging them into the trunk will generate too may conflicts to be easily resolved.</p> <p>Lastly, there is the issue of maintenance of Python. At any one time there is at least one major version of Python under development (at the time of this writing there are two). For each major version of Python under development there is at least the maintenance version of the last minor version and the in-development minor version (e.g. with 2.6 just released, that means that both 2.6 and 2.7 are being worked on). Once a release is done, a branch is created between the code bases where changes in one version do not (but could) belong in the other version. As of right now there is no natural support for this branch in time in central VCSs; you must use tools that simulate the branching. Tracking merges is similarly painful for developers, as revisions often need to be merged between four active branches (e.g. 2.6 maintenance, 3.0 maintenance, 2.7 development, 3.1 development). In this case, VCSs such as Subversion only handle this through arcane third party tools.</p> <p>Distributed VCSs (DVCSs) solve all of these problems. While one can keep a master copy of a revision tree, anyone is free to copy that tree for their own use. This gives everyone the power to commit changes to their copy, online or offline. It also more naturally ties into the idea of branching in the history of a revision tree for maintenance and the development of new features bound for Python. DVCSs also provide a great many additional features that centralized VCSs don’t or can’t provide.</p> <p>This PEP explores the possibility of changing Python’s use of Subversion to any of the currently popular DVCSs, in order to gain the benefits outlined above. This PEP does not guarantee that a switch to a DVCS will occur at the conclusion of this PEP. It is quite possible that no clear winner will be found and that svn will continue to be used. If this happens, this PEP will be revisited and revised in the future as the state of DVCSs evolves.</p> </section> <section id="terminology"> <h2><a class="toc-backref" href="#terminology" role="doc-backlink">Terminology</a></h2> <p>Agreeing on a common terminology is surprisingly difficult, primarily because each VCS uses these terms when describing subtly different tasks, objects, and concepts. Where possible, we try to provide a generic definition of the concepts, but you should consult the individual system’s glossaries for details. Here are some basic references for terminology, from some of the standard web-based references on each VCS. You can also refer to glossaries for each DVCS:</p> <ul class="simple"> <li>Subversion : <a class="reference external" href="http://svnbook.red-bean.com/en/1.5/svn.basic.html">http://svnbook.red-bean.com/en/1.5/svn.basic.html</a></li> <li>Bazaar : <a class="reference external" href="http://bazaar-vcs.org/BzrGlossary">http://bazaar-vcs.org/BzrGlossary</a></li> <li>Mercurial : <a class="reference external" href="http://www.selenic.com/mercurial/wiki/index.cgi/UnderstandingMercurial">http://www.selenic.com/mercurial/wiki/index.cgi/UnderstandingMercurial</a></li> <li>git : <a class="reference external" href="http://book.git-scm.com/1_the_git_object_model.html">http://book.git-scm.com/1_the_git_object_model.html</a></li> </ul> <dl class="simple"> <dt>branch</dt><dd>A line of development; a collection of revisions, ordered by time.</dd> <dt>checkout/working copy/working tree</dt><dd>A tree of code the developer can edit, linked to a branch.</dd> <dt>index</dt><dd>A “staging area” where a revision is built (unique to git).</dd> <dt>repository</dt><dd>A collection of revisions, organized into branches.</dd> <dt>clone</dt><dd>A complete copy of a branch or repository.</dd> <dt>commit</dt><dd>To record a revision in a repository.</dd> <dt>merge</dt><dd>Applying all the changes and history from one branch/repository to another.</dd> <dt>pull</dt><dd>To update a checkout/clone from the original branch/repository, which can be remote or local</dd> <dt>push/publish</dt><dd>To copy a revision, and all revisions it depends on, from a one repository to another.</dd> <dt>cherry-pick</dt><dd>To merge one or more specific revisions from one branch to another, possibly in a different repository, possibly without its dependent revisions.</dd> <dt>rebase</dt><dd>To “detach” a branch, and move it to a new branch point; move commits to the beginning of a branch instead of where they happened in time.</dd> </dl> </section> <section id="typical-workflow"> <h2><a class="toc-backref" href="#typical-workflow" role="doc-backlink">Typical Workflow</a></h2> <p>At the moment, the typical workflow for a Python core developer is:</p> <ul class="simple"> <li>Edit code in a checkout until it is stable enough to commit/push.</li> <li>Commit to the master repository.</li> </ul> <p>It is a rather simple workflow, but it has drawbacks. For one, because any work that involves the repository takes time thanks to the network, commits/pushes tend to not necessarily be as atomic as possible. There is also the drawback of there not being a necessarily cheap way to create new checkouts beyond a recursive copy of the checkout directory.</p> <p>A DVCS would lead to a workflow more like this:</p> <ul class="simple"> <li>Branch off of a local clone of the master repository.</li> <li>Edit code, committing in atomic pieces.</li> <li>Merge the branch into the mainline, and</li> <li>Push all commits to the master repository.</li> </ul> <p>While there are more possible steps, the workflow is much more independent of the master repository than is currently possible. By being able to commit locally at the speed of your disk, a core developer is able to do atomic commits much more frequently, minimizing having commits that do multiple things to the code. Also by using a branch, the changes are isolated (if desired) from other changes being made by other developers. Because branches are cheap, it is easy to create and maintain many smaller branches that address one specific issue, e.g. one bug or one new feature. More sophisticated features of DVCSs allow the developer to more easily track long running development branches as the official mainline progresses.</p> </section> <section id="contenders"> <h2><a class="toc-backref" href="#contenders" role="doc-backlink">Contenders</a></h2> <table class="docutils align-default"> <thead> <tr class="row-odd"><th class="head">Name</th> <th class="head">Short Name</th> <th class="head">Version</th> <th class="head">2.x Trunk Mirror</th> <th class="head">3.x Trunk Mirror</th> </tr> </thead> <tbody> <tr class="row-even"><td><a class="reference external" href="http://bazaar-vcs.org/">Bazaar</a></td> <td>bzr</td> <td>1.12</td> <td><a class="reference external" href="http://code.python.org/python/trunk">http://code.python.org/python/trunk</a></td> <td><a class="reference external" href="http://code.python.org/python/3.0">http://code.python.org/python/3.0</a></td> </tr> <tr class="row-odd"><td><a class="reference external" href="http://www.selenic.com/mercurial/">Mercurial</a></td> <td>hg</td> <td>1.2.0</td> <td><a class="reference external" href="http://code.python.org/hg/trunk/">http://code.python.org/hg/trunk/</a></td> <td><a class="reference external" href="http://code.python.org/hg/branches/py3k/">http://code.python.org/hg/branches/py3k/</a></td> </tr> <tr class="row-even"><td><a class="reference external" href="http://www.git-scm.com/">git</a></td> <td>N/A</td> <td>1.6.1</td> <td>git://code.python.org/python/trunk</td> <td>git://code.python.org/python/branches/py3k</td> </tr> </tbody> </table> <p>This PEP does not consider darcs, arch, or monotone. The main problem with these DVCSs is that they are simply not popular enough to bother supporting when they do not provide some very compelling features that the other DVCSs provide. Arch and darcs also have significant performance problems which seem unlikely to be addressed in the near future.</p> </section> <section id="interoperability"> <h2><a class="toc-backref" href="#interoperability" role="doc-backlink">Interoperability</a></h2> <p>For those who have already decided which DVCSs they want to use, and are willing to maintain local mirrors themselves, all three DVCSs support interchange via the git “fast-import” changeset format. git does so natively, of course, and native support for Bazaar is under active development, and getting good early reviews as of mid-February 2009. Mercurial has idiosyncratic support for importing via its <em>hg convert</em> command, and <a class="reference external" href="http://repo.or.cz/r/fast-export.git/.git/description">third-party fast-import support</a> is available for exporting. Also, the <a class="reference external" href="http://progetti.arstecnica.it/tailor/">Tailor</a> tool supports automatic maintenance of mirrors based on an official repository in any of the candidate formats with a local mirror in any format.</p> </section> <section id="usage-scenarios"> <h2><a class="toc-backref" href="#usage-scenarios" role="doc-backlink">Usage Scenarios</a></h2> <p>Probably the best way to help decide on whether/which DVCS should replace Subversion is to see what it takes to perform some real-world usage scenarios that developers (core and non-core) have to work with. Each usage scenario outlines what it is, a bullet list of what the basic steps are (which can vary slightly per VCS), and how to perform the usage scenario in the various VCSs (including Subversion).</p> <p>Each VCS had a single author in charge of writing implementations for each scenario (unless otherwise noted).</p> <table class="docutils align-default"> <thead> <tr class="row-odd"><th class="head">Name</th> <th class="head">VCS</th> </tr> </thead> <tbody> <tr class="row-even"><td>Brett</td> <td>svn</td> </tr> <tr class="row-odd"><td>Barry</td> <td>bzr</td> </tr> <tr class="row-even"><td>Alexandre</td> <td>hg</td> </tr> <tr class="row-odd"><td>Stephen</td> <td>git</td> </tr> </tbody> </table> <section id="initial-setup"> <h3><a class="toc-backref" href="#initial-setup" role="doc-backlink">Initial Setup</a></h3> <p>Some DVCSs have some perks if you do some initial setup upfront. This section covers what can be done before any of the usage scenarios are run in order to take better advantage of the tools.</p> <p>All of the DVCSs support configuring your project identification. Unlike the centralized systems, they use your email address to identify your commits. (Access control is generally done by mechanisms external to the DVCS, such as ssh or console login). This identity may be associated with a full name.</p> <p>All of the DVCSs will query the system to get some approximation to this information, but that may not be what you want. They also support setting this information on a per-user basis, and on a per-project basis. Convenience commands to set these attributes vary, but all allow direct editing of configuration files.</p> <p>Some VCSs support end-of-line (EOL) conversions on checkout/checkin.</p> <section id="svn"> <h4><a class="toc-backref" href="#svn" role="doc-backlink">svn</a></h4> <p>None required, but it is recommended you follow the <a class="reference external" href="http://www.python.org/dev/faq/#what-configuration-settings-should-i-use">guidelines</a> in the dev FAQ.</p> </section> <section id="bzr"> <h4><a class="toc-backref" href="#bzr" role="doc-backlink">bzr</a></h4> <p>No setup is required, but for much quicker and space-efficient local branching, you should create a shared repository to hold all your Python branches. A shared repository is really just a parent directory containing a .bzr directory. When bzr commits a revision, it searches from the local directory on up the file system for a .bzr directory to hold the revision. By sharing revisions across multiple branches, you cut down on the amount of disk space used. Do this:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">cd</span> <span class="o">~/</span><span class="n">projects</span> <span class="n">bzr</span> <span class="n">init</span><span class="o">-</span><span class="n">repo</span> <span class="n">python</span> <span class="n">cd</span> <span class="n">python</span> </pre></div> </div> <p>Now, all your Python branches should be created inside of <code class="docutils literal notranslate"><span class="pre">~/projects/python</span></code>.</p> <p>There are also some settings you can put in your <code class="docutils literal notranslate"><span class="pre">~/.bzr/bazaar.conf</span></code> and <code class="docutils literal notranslate"><span class="pre">~/.bzr/locations.conf</span></code> file to set up defaults for interacting with Python code. None of them are required, although some are recommended. E.g. I would suggest gpg signing all commits, but that might be too high a barrier for developers. Also, you can set up default push locations depending on where you want to push branches by default. If you have write access to the master branches, that push location could be code.python.org. Otherwise, it might be a free Bazaar code hosting service such as Launchpad. If Bazaar is chosen, we should decide what the policies and recommendations are.</p> <p>At a minimum, I would set up your email address:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">bzr</span> <span class="n">whoami</span> <span class="s2">"Firstname Lastname <email.address@example.com>"</span> </pre></div> </div> <p>As with hg and git below, there are ways to set your email address (or really, just about any parameter) on a per-repository basis. You do this with settings in your <code class="docutils literal notranslate"><span class="pre">$HOME/.bazaar/locations.conf</span></code> file, which has an ini-style format as does the other DVCSs. See the Bazaar documentation for details, which mostly aren’t relevant for this discussion.</p> </section> <section id="hg"> <h4><a class="toc-backref" href="#hg" role="doc-backlink">hg</a></h4> <p>Minimally, you should set your user name. To do so, create the file <code class="docutils literal notranslate"><span class="pre">.hgrc</span></code> in your home directory and add the following:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">[</span><span class="n">ui</span><span class="p">]</span> <span class="n">username</span> <span class="o">=</span> <span class="n">Firstname</span> <span class="n">Lastname</span> <span class="o"><</span><span class="n">email</span><span class="o">.</span><span class="n">address</span><span class="nd">@example</span><span class="o">.</span><span class="n">com</span><span class="o">></span> </pre></div> </div> <p>If you are using Windows and your tools do not support Unix-style newlines, you can enable automatic newline translation by adding to your configuration:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">[</span><span class="n">extensions</span><span class="p">]</span> <span class="n">win32text</span> <span class="o">=</span> </pre></div> </div> <p>These options can also be set locally to a given repository by customizing <code class="docutils literal notranslate"><span class="pre"><repo>/.hg/hgrc</span></code>, instead of <code class="docutils literal notranslate"><span class="pre">~/.hgrc</span></code>.</p> </section> <section id="id1"> <h4><a class="toc-backref" href="#id1" role="doc-backlink">git</a></h4> <p>None needed. However, git supports a number of features that can smooth your work, with a little preparation. git supports setting defaults at the workspace, user, and system levels. The system level is out of scope of this PEP. The user configuration file is <code class="docutils literal notranslate"><span class="pre">$HOME/.gitconfig</span></code> on Unix-like systems, and the workspace configuration file is <code class="docutils literal notranslate"><span class="pre">$REPOSITORY/.git/config</span></code>.</p> <p>You can use the <code class="docutils literal notranslate"><span class="pre">git-config</span></code> tool to set preferences for user.name and user.email either globally (for your system login account) or locally (to a given git working copy), or you can edit the configuration files (which have the same format as shown in the Mercurial section above).:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># my full name doesn't change</span> <span class="c1"># note "--global" flag means per user</span> <span class="c1"># (system-wide configuration is set with "--system")</span> <span class="n">git</span> <span class="n">config</span> <span class="o">--</span><span class="k">global</span> <span class="n">user</span><span class="o">.</span><span class="n">name</span> <span class="s1">'Firstname Lastname'</span> <span class="c1"># but use my Pythonic email address</span> <span class="n">cd</span> <span class="o">/</span><span class="n">path</span><span class="o">/</span><span class="n">to</span><span class="o">/</span><span class="n">python</span><span class="o">/</span><span class="n">repository</span> <span class="n">git</span> <span class="n">config</span> <span class="n">user</span><span class="o">.</span><span class="n">email</span> <span class="n">email</span><span class="o">.</span><span class="n">address</span><span class="nd">@python</span><span class="o">.</span><span class="n">example</span><span class="o">.</span><span class="n">com</span> </pre></div> </div> <p>If you are using Windows, you probably want to set the core.autocrlf and core.safecrlf preferences to true using <code class="docutils literal notranslate"><span class="pre">git-config</span></code>.:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># check out files with CRLF line endings rather than Unix-style LF only</span> <span class="n">git</span> <span class="n">config</span> <span class="o">--</span><span class="k">global</span> <span class="n">core</span><span class="o">.</span><span class="n">autocrlf</span> <span class="n">true</span> <span class="c1"># scream if a transformation would be ambiguous</span> <span class="c1"># (eg, a working file contains both naked LF and CRLF)</span> <span class="c1"># and check them back in with the reverse transformation</span> <span class="n">git</span> <span class="n">config</span> <span class="o">--</span><span class="k">global</span> <span class="n">core</span><span class="o">.</span><span class="n">safecrlf</span> <span class="n">true</span> </pre></div> </div> <p>Although the repository will usually contain a .gitignore file specifying file names that rarely if ever should be registered in the VCS, you may have personal conventions (e.g., always editing log messages in a temporary file named “.msg”) that you may wish to specify.:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># tell git where my personal ignores are</span> <span class="n">git</span> <span class="n">config</span> <span class="o">--</span><span class="k">global</span> <span class="n">core</span><span class="o">.</span><span class="n">excludesfile</span> <span class="o">~/.</span><span class="n">gitignore</span> <span class="c1"># I use .msg for my long commit logs, and Emacs makes backups in</span> <span class="c1"># files ending with ~</span> <span class="c1"># these are globs, not regular expressions</span> <span class="n">echo</span> <span class="s1">'*~'</span> <span class="o">>></span> <span class="o">~/.</span><span class="n">gitignore</span> <span class="n">echo</span> <span class="s1">'.msg'</span> <span class="o">>></span> <span class="o">~/.</span><span class="n">gitignore</span> </pre></div> </div> <p>If you use multiple branches, as with the other VCSes, you can save a lot of space by putting all objects in a common object store. This also can save download time, if the origins of the branches were in different repositories, because objects are shared across branches in your repository even if they were not present in the upstream repositories. git is very space- and time-efficient and applies a number of optimizations automatically, so this configuration is optional. (Examples are omitted.)</p> </section> </section> <section id="one-off-checkout"> <h3><a class="toc-backref" href="#one-off-checkout" role="doc-backlink">One-Off Checkout</a></h3> <p>As a non-core developer, I want to create and publish a one-off patch that fixes a bug, so that a core developer can review it for inclusion in the mainline.</p> <ul class="simple"> <li>Checkout/branch/clone trunk.</li> <li>Edit some code.</li> <li>Generate a patch (based on what is best supported by the VCS, e.g. branch history).</li> <li>Receive reviewer comments and address the issues.</li> <li>Generate a second patch for the core developer to commit.</li> </ul> <section id="id2"> <h4><a class="toc-backref" href="#id2" role="doc-backlink">svn</a></h4> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">svn</span> <span class="n">checkout</span> <span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">svn</span><span class="o">.</span><span class="n">python</span><span class="o">.</span><span class="n">org</span><span class="o">/</span><span class="n">projects</span><span class="o">/</span><span class="n">python</span><span class="o">/</span><span class="n">trunk</span> <span class="n">cd</span> <span class="n">trunk</span> <span class="c1"># Edit some code.</span> <span class="n">echo</span> <span class="s2">"The cake is a lie!"</span> <span class="o">></span> <span class="n">README</span> <span class="c1"># Since svn lacks support for local commits, we fake it with patches.</span> <span class="n">svn</span> <span class="n">diff</span> <span class="o">>></span> <span class="n">commit</span><span class="o">-</span><span class="mf">1.</span><span class="n">diff</span> <span class="n">svn</span> <span class="n">diff</span> <span class="o">>></span> <span class="n">patch</span><span class="o">-</span><span class="mf">1.</span><span class="n">diff</span> <span class="c1"># Upload the patch-1 to bugs.python.org.</span> <span class="c1"># Receive reviewer comments.</span> <span class="c1"># Edit some code.</span> <span class="n">echo</span> <span class="s2">"The cake is real!"</span> <span class="o">></span> <span class="n">README</span> <span class="c1"># Since svn lacks support for local commits, we fake it with patches.</span> <span class="n">svn</span> <span class="n">diff</span> <span class="o">>></span> <span class="n">commit</span><span class="o">-</span><span class="mf">2.</span><span class="n">diff</span> <span class="n">svn</span> <span class="n">diff</span> <span class="o">>></span> <span class="n">patch</span><span class="o">-</span><span class="mf">2.</span><span class="n">diff</span> <span class="c1"># Upload patch-2 to bugs.python.org</span> </pre></div> </div> </section> <section id="id3"> <h4><a class="toc-backref" href="#id3" role="doc-backlink">bzr</a></h4> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">bzr</span> <span class="n">branch</span> <span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">code</span><span class="o">.</span><span class="n">python</span><span class="o">.</span><span class="n">org</span><span class="o">/</span><span class="n">python</span><span class="o">/</span><span class="n">trunk</span> <span class="n">cd</span> <span class="n">trunk</span> <span class="c1"># Edit some code.</span> <span class="n">bzr</span> <span class="n">commit</span> <span class="o">-</span><span class="n">m</span> <span class="s1">'Stuff I did'</span> <span class="n">bzr</span> <span class="n">send</span> <span class="o">-</span><span class="n">o</span> <span class="n">bundle</span> <span class="c1"># Upload bundle to bugs.python.org</span> <span class="c1"># Receive reviewer comments</span> <span class="c1"># Edit some code</span> <span class="n">bzr</span> <span class="n">commit</span> <span class="o">-</span><span class="n">m</span> <span class="s1">'Respond to reviewer comments'</span> <span class="n">bzr</span> <span class="n">send</span> <span class="o">-</span><span class="n">o</span> <span class="n">bundle</span> <span class="c1"># Upload updated bundle to bugs.python.org</span> </pre></div> </div> <p>The <code class="docutils literal notranslate"><span class="pre">bundle</span></code> file is like a super-patch. It can be read by <code class="docutils literal notranslate"><span class="pre">patch(1)</span></code> but it contains additional metadata so that it can be fed to <code class="docutils literal notranslate"><span class="pre">bzr</span> <span class="pre">merge</span></code> to produce a fully usable branch completely with history. See <a class="reference internal" href="#patch-review">Patch Review</a> section below.</p> </section> <section id="id4"> <h4><a class="toc-backref" href="#id4" role="doc-backlink">hg</a></h4> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">hg</span> <span class="n">clone</span> <span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">code</span><span class="o">.</span><span class="n">python</span><span class="o">.</span><span class="n">org</span><span class="o">/</span><span class="n">hg</span><span class="o">/</span><span class="n">trunk</span> <span class="n">cd</span> <span class="n">trunk</span> <span class="c1"># Edit some code.</span> <span class="n">hg</span> <span class="n">commit</span> <span class="o">-</span><span class="n">m</span> <span class="s2">"Stuff I did"</span> <span class="n">hg</span> <span class="n">outgoing</span> <span class="o">-</span><span class="n">p</span> <span class="o">></span> <span class="n">fixes</span><span class="o">.</span><span class="n">patch</span> <span class="c1"># Upload patch to bugs.python.org</span> <span class="c1"># Receive reviewer comments</span> <span class="c1"># Edit some code</span> <span class="n">hg</span> <span class="n">commit</span> <span class="o">-</span><span class="n">m</span> <span class="s2">"Address reviewer comments."</span> <span class="n">hg</span> <span class="n">outgoing</span> <span class="o">-</span><span class="n">p</span> <span class="o">></span> <span class="n">additional</span><span class="o">-</span><span class="n">fixes</span><span class="o">.</span><span class="n">patch</span> <span class="c1"># Upload patch to bugs.python.org</span> </pre></div> </div> <p>While <code class="docutils literal notranslate"><span class="pre">hg</span> <span class="pre">outgoing</span></code> does not have the flag for it, most Mercurial commands support git’s extended patch format through a <code class="docutils literal notranslate"><span class="pre">--git</span></code> command. This can be set in one’s <code class="docutils literal notranslate"><span class="pre">.hgrc</span></code> file so that all commands that generate a patch use the extended format.</p> </section> <section id="id5"> <h4><a class="toc-backref" href="#id5" role="doc-backlink">git</a></h4> <p>The patches could be created with <code class="docutils literal notranslate"><span class="pre">git</span> <span class="pre">diff</span> <span class="pre">master</span> <span class="pre">></span> <span class="pre">stuff-i-did.patch</span></code>, too, but <code class="docutils literal notranslate"><span class="pre">git</span> <span class="pre">format-patch</span> <span class="pre">|</span> <span class="pre">git</span> <span class="pre">am</span></code> knows some tricks (empty files, renames, etc) that ordinary patch can’t handle. git grabs “Stuff I did” out of the commit message to create the file name 0001-Stuff-I-did.patch. See Patch Review below for a description of the git-format-patch format.</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># Get the mainline code.</span> <span class="n">git</span> <span class="n">clone</span> <span class="n">git</span><span class="p">:</span><span class="o">//</span><span class="n">code</span><span class="o">.</span><span class="n">python</span><span class="o">.</span><span class="n">org</span><span class="o">/</span><span class="n">python</span><span class="o">/</span><span class="n">trunk</span> <span class="n">cd</span> <span class="n">trunk</span> <span class="c1"># Edit some code.</span> <span class="n">git</span> <span class="n">commit</span> <span class="o">-</span><span class="n">a</span> <span class="o">-</span><span class="n">m</span> <span class="s1">'Stuff I did.'</span> <span class="c1"># Create patch for my changes (i.e, relative to master).</span> <span class="n">git</span> <span class="nb">format</span><span class="o">-</span><span class="n">patch</span> <span class="n">master</span> <span class="n">git</span> <span class="n">tag</span> <span class="n">stuff</span><span class="o">-</span><span class="n">v1</span> <span class="c1"># Upload 0001-Stuff-I-did.patch to bugs.python.org.</span> <span class="c1"># Time passes ... receive reviewer comments.</span> <span class="c1"># Edit more code.</span> <span class="n">git</span> <span class="n">commit</span> <span class="o">-</span><span class="n">a</span> <span class="o">-</span><span class="n">m</span> <span class="s1">'Address reviewer comments.'</span> <span class="c1"># Make an add-on patch to apply on top of the original.</span> <span class="n">git</span> <span class="nb">format</span><span class="o">-</span><span class="n">patch</span> <span class="n">stuff</span><span class="o">-</span><span class="n">v1</span> <span class="c1"># Upload 0001-Address-reviewer-comments.patch to bugs.python.org.</span> </pre></div> </div> </section> </section> <section id="backing-out-changes"> <h3><a class="toc-backref" href="#backing-out-changes" role="doc-backlink">Backing Out Changes</a></h3> <p>As a core developer, I want to undo a change that was not ready for inclusion in the mainline.</p> <ul class="simple"> <li>Back out the unwanted change.</li> <li>Push patch to server.</li> </ul> <section id="id6"> <h4><a class="toc-backref" href="#id6" role="doc-backlink">svn</a></h4> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># Assume the change to revert is in revision 40</span> <span class="n">svn</span> <span class="n">merge</span> <span class="o">-</span><span class="n">c</span> <span class="o">-</span><span class="mi">40</span> <span class="o">.</span> <span class="c1"># Resolve conflicts, if any.</span> <span class="n">svn</span> <span class="n">commit</span> <span class="o">-</span><span class="n">m</span> <span class="s2">"Reverted revision 40"</span> </pre></div> </div> </section> <section id="id7"> <h4><a class="toc-backref" href="#id7" role="doc-backlink">bzr</a></h4> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># Assume the change to revert is in revision 40</span> <span class="n">bzr</span> <span class="n">merge</span> <span class="o">-</span><span class="n">r</span> <span class="mf">40..39</span> <span class="c1"># Resolve conflicts, if any.</span> <span class="n">bzr</span> <span class="n">commit</span> <span class="o">-</span><span class="n">m</span> <span class="s2">"Reverted revision 40"</span> </pre></div> </div> <p>Note that if the change you want revert is the last one that was made, you can just use <code class="docutils literal notranslate"><span class="pre">bzr</span> <span class="pre">uncommit</span></code>.</p> </section> <section id="id8"> <h4><a class="toc-backref" href="#id8" role="doc-backlink">hg</a></h4> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># Assume the change to revert is in revision 9150dd9c6d30</span> <span class="n">hg</span> <span class="n">backout</span> <span class="o">--</span><span class="n">merge</span> <span class="o">-</span><span class="n">r</span> <span class="mi">9150</span><span class="n">dd9c6d30</span> <span class="c1"># Resolve conflicts, if any.</span> <span class="n">hg</span> <span class="n">commit</span> <span class="o">-</span><span class="n">m</span> <span class="s2">"Reverted changeset 9150dd9c6d30"</span> <span class="n">hg</span> <span class="n">push</span> </pre></div> </div> <p>Note, you can use “hg rollback” and “hg strip” to revert changes you committed in your local repository, but did not yet push to other repositories.</p> </section> <section id="id9"> <h4><a class="toc-backref" href="#id9" role="doc-backlink">git</a></h4> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># Assume the change to revert is the grandfather of a revision tagged "newhotness".</span> <span class="n">git</span> <span class="n">revert</span> <span class="n">newhotness</span><span class="o">~</span><span class="mi">2</span> <span class="c1"># Resolve conflicts if any. If there are no conflicts, the commit</span> <span class="c1"># will be done automatically by "git revert", which prompts for a log.</span> <span class="n">git</span> <span class="n">commit</span> <span class="o">-</span><span class="n">m</span> <span class="s2">"Reverted changeset 9150dd9c6d30."</span> <span class="n">git</span> <span class="n">push</span> </pre></div> </div> </section> </section> <section id="patch-review"> <h3><a class="toc-backref" href="#patch-review" role="doc-backlink">Patch Review</a></h3> <p>As a core developer, I want to review patches submitted by other people, so that I can make sure that only approved changes are added to Python.</p> <p>Core developers have to review patches as submitted by other people. This requires applying the patch, testing it, and then tossing away the changes. The assumption can be made that a core developer already has a checkout/branch/clone of the trunk.</p> <ul class="simple"> <li>Branch off of trunk.</li> <li>Apply patch w/o any comments as generated by the patch submitter.</li> <li>Push patch to server.</li> <li>Delete now-useless branch.</li> </ul> <section id="id10"> <h4><a class="toc-backref" href="#id10" role="doc-backlink">svn</a></h4> <p>Subversion does not exactly fit into this development style very well as there are no such thing as a “branch” as has been defined in this PEP. Instead a developer either needs to create another checkout for testing a patch or create a branch on the server. Up to this point, core developers have not taken the “branch on the server” approach to dealing with individual patches. For this scenario the assumption will be the developer creates a local checkout of the trunk to work with.:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">cp</span> <span class="o">-</span><span class="n">r</span> <span class="n">trunk</span> <span class="n">issue0000</span> <span class="n">cd</span> <span class="n">issue0000</span> <span class="n">patch</span> <span class="o">-</span><span class="n">p0</span> <span class="o"><</span> <span class="n">__patch__</span> <span class="c1"># Review patch.</span> <span class="n">svn</span> <span class="n">commit</span> <span class="o">-</span><span class="n">m</span> <span class="s2">"Some patch."</span> <span class="n">cd</span> <span class="o">..</span> <span class="n">rm</span> <span class="o">-</span><span class="n">r</span> <span class="n">issue0000</span> </pre></div> </div> <p>Another option is to only have a single checkout running at any one time and use <code class="docutils literal notranslate"><span class="pre">svn</span> <span class="pre">diff</span></code> along with <code class="docutils literal notranslate"><span class="pre">svn</span> <span class="pre">revert</span> <span class="pre">-R</span></code> to store away independent changes you may have made.</p> </section> <section id="id11"> <h4><a class="toc-backref" href="#id11" role="doc-backlink">bzr</a></h4> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">bzr</span> <span class="n">branch</span> <span class="n">trunk</span> <span class="n">issueNNNN</span> <span class="c1"># Download `patch` bundle from Roundup</span> <span class="n">bzr</span> <span class="n">merge</span> <span class="n">patch</span> <span class="c1"># Review patch</span> <span class="n">bzr</span> <span class="n">commit</span> <span class="o">-</span><span class="n">m</span><span class="s1">'Patch NNN by So N. So'</span> <span class="o">--</span><span class="n">fixes</span> <span class="n">python</span><span class="p">:</span><span class="n">NNNN</span> <span class="n">bzr</span> <span class="n">push</span> <span class="n">bzr</span><span class="o">+</span><span class="n">ssh</span><span class="p">:</span><span class="o">//</span><span class="n">me</span><span class="nd">@code</span><span class="o">.</span><span class="n">python</span><span class="o">.</span><span class="n">org</span><span class="o">/</span><span class="n">trunk</span> <span class="n">rm</span> <span class="o">-</span><span class="n">rf</span> <span class="o">../</span><span class="n">issueNNNN</span> </pre></div> </div> <p>Alternatively, since you’re probably going to commit these changes to the trunk, you could just do a checkout. That would give you a local working tree while the branch (i.e. all revisions) would continue to live on the server. This is similar to the svn model and might allow you to more quickly review the patch. There’s no need for the push in this case.:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">bzr</span> <span class="n">checkout</span> <span class="n">trunk</span> <span class="n">issueNNNN</span> <span class="c1"># Download `patch` bundle from Roundup</span> <span class="n">bzr</span> <span class="n">merge</span> <span class="n">patch</span> <span class="c1"># Review patch</span> <span class="n">bzr</span> <span class="n">commit</span> <span class="o">-</span><span class="n">m</span><span class="s1">'Patch NNNN by So N. So'</span> <span class="o">--</span><span class="n">fixes</span> <span class="n">python</span><span class="p">:</span><span class="n">NNNN</span> <span class="n">rm</span> <span class="o">-</span><span class="n">rf</span> <span class="o">../</span><span class="n">issueNNNN</span> </pre></div> </div> </section> <section id="id12"> <h4><a class="toc-backref" href="#id12" role="doc-backlink">hg</a></h4> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">hg</span> <span class="n">clone</span> <span class="n">trunk</span> <span class="n">issue0000</span> <span class="n">cd</span> <span class="n">issue0000</span> <span class="c1"># If the patch was generated using hg export, the user name of the</span> <span class="c1"># submitter is automatically recorded. Otherwise,</span> <span class="c1"># use hg import --no-commit submitted.diff and commit with</span> <span class="c1"># hg commit -u "Firstname Lastname <email.address@example.com>"</span> <span class="n">hg</span> <span class="kn">import</span> <span class="nn">submitted.diff</span> <span class="c1"># Review patch.</span> <span class="n">hg</span> <span class="n">push</span> <span class="n">ssh</span><span class="p">:</span><span class="o">//</span><span class="n">alexandre</span><span class="nd">@code</span><span class="o">.</span><span class="n">python</span><span class="o">.</span><span class="n">org</span><span class="o">/</span><span class="n">hg</span><span class="o">/</span><span class="n">trunk</span><span class="o">/</span> </pre></div> </div> </section> <section id="id13"> <h4><a class="toc-backref" href="#id13" role="doc-backlink">git</a></h4> <p>We assume a patch created by git-format-patch. This is a Unix mbox file containing one or more patches, each formatted as an <span class="target" id="index-0"></span><a class="rfc reference external" href="https://datatracker.ietf.org/doc/html/rfc2822.html"><strong>RFC 2822</strong></a> message. git-am interprets each message as a commit as follows. The author of the patch is taken from the From: header, the date from the Date header. The commit log is created by concatenating the content of the subject line, a blank line, and the message body up to the start of the patch.:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">cd</span> <span class="n">trunk</span> <span class="c1"># Create a branch in case we don't like the patch.</span> <span class="c1"># This checkout takes zero time, since the workspace is left in</span> <span class="c1"># the same state as the master branch.</span> <span class="n">git</span> <span class="n">checkout</span> <span class="o">-</span><span class="n">b</span> <span class="n">patch</span><span class="o">-</span><span class="n">review</span> <span class="c1"># Download patch from bugs.python.org to submitted.patch.</span> <span class="n">git</span> <span class="n">am</span> <span class="o"><</span> <span class="n">submitted</span><span class="o">.</span><span class="n">patch</span> <span class="c1"># Review and approve patch.</span> <span class="c1"># Merge into master and push.</span> <span class="n">git</span> <span class="n">checkout</span> <span class="n">master</span> <span class="n">git</span> <span class="n">merge</span> <span class="n">patch</span><span class="o">-</span><span class="n">review</span> <span class="n">git</span> <span class="n">push</span> </pre></div> </div> </section> </section> <section id="backport"> <h3><a class="toc-backref" href="#backport" role="doc-backlink">Backport</a></h3> <p>As a core developer, I want to apply a patch to 2.6, 2.7, 3.0, and 3.1 so that I can fix a problem in all three versions.</p> <p>Thanks to always having the cutting-edge and the latest release version under development, Python currently has four branches being worked on simultaneously. That makes it important for a change to propagate easily through various branches.</p> <section id="id14"> <h4><a class="toc-backref" href="#id14" role="doc-backlink">svn</a></h4> <p>Because of Python’s use of svnmerge, changes start with the trunk (2.7) and then get merged to the release version of 2.6. To get the change into the 3.x series, the change is merged into 3.1, fixed up, and then merged into 3.0 (2.7 -> 2.6; 2.7 -> 3.1 -> 3.0).</p> <p>This is in contrast to a port-forward strategy where the patch would have been added to 2.6 and then pulled forward into newer versions (2.6 -> 2.7 -> 3.0 -> 3.1).</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># Assume patch applied to 2.7 in revision 0000.</span> <span class="n">cd</span> <span class="n">release26</span><span class="o">-</span><span class="n">maint</span> <span class="n">svnmerge</span> <span class="n">merge</span> <span class="o">-</span><span class="n">r</span> <span class="mi">0000</span> <span class="c1"># Resolve merge conflicts and make sure patch works.</span> <span class="n">svn</span> <span class="n">commit</span> <span class="o">-</span><span class="n">F</span> <span class="n">svnmerge</span><span class="o">-</span><span class="n">commit</span><span class="o">-</span><span class="n">message</span><span class="o">.</span><span class="n">txt</span> <span class="c1"># revision 0001.</span> <span class="n">cd</span> <span class="o">../</span><span class="n">py3k</span> <span class="n">svnmerge</span> <span class="n">merge</span> <span class="o">-</span><span class="n">r</span> <span class="mi">0000</span> <span class="c1"># Same as for 2.6, except Misc/NEWS changes are reverted.</span> <span class="n">svn</span> <span class="n">revert</span> <span class="n">Misc</span><span class="o">/</span><span class="n">NEWS</span> <span class="n">svn</span> <span class="n">commit</span> <span class="o">-</span><span class="n">F</span> <span class="n">svnmerge</span><span class="o">-</span><span class="n">commit</span><span class="o">-</span><span class="n">message</span><span class="o">.</span><span class="n">txt</span> <span class="c1"># revision 0002.</span> <span class="n">cd</span> <span class="o">../</span><span class="n">release30</span><span class="o">-</span><span class="n">maint</span> <span class="n">svnmerge</span> <span class="n">merge</span> <span class="o">-</span><span class="n">r</span> <span class="mi">0002</span> <span class="n">svn</span> <span class="n">commit</span> <span class="o">-</span><span class="n">F</span> <span class="n">svnmerge</span><span class="o">-</span><span class="n">commit</span><span class="o">-</span><span class="n">message</span><span class="o">.</span><span class="n">txt</span> <span class="c1"># revision 0003.</span> </pre></div> </div> </section> <section id="id15"> <h4><a class="toc-backref" href="#id15" role="doc-backlink">bzr</a></h4> <p>Bazaar is pretty straightforward here, since it supports cherry picking revisions manually. In the example below, we could have given a revision id instead of a revision number, but that’s usually not necessary. Martin Pool suggests “We’d generally recommend doing the fix first in the oldest supported branch, and then merging it forward to the later releases.”:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># Assume patch applied to 2.7 in revision 0000</span> <span class="n">cd</span> <span class="n">release26</span><span class="o">-</span><span class="n">maint</span> <span class="n">bzr</span> <span class="n">merge</span> <span class="o">../</span><span class="n">trunk</span> <span class="o">-</span><span class="n">c</span> <span class="mi">0000</span> <span class="c1"># Resolve conflicts and make sure patch works</span> <span class="n">bzr</span> <span class="n">commit</span> <span class="o">-</span><span class="n">m</span> <span class="s1">'Back port patch NNNN'</span> <span class="n">bzr</span> <span class="n">push</span> <span class="n">bzr</span><span class="o">+</span><span class="n">ssh</span><span class="p">:</span><span class="o">//</span><span class="n">me</span><span class="nd">@code</span><span class="o">.</span><span class="n">python</span><span class="o">.</span><span class="n">org</span><span class="o">/</span><span class="n">trunk</span> <span class="n">cd</span> <span class="o">../</span><span class="n">py3k</span> <span class="n">bzr</span> <span class="n">merge</span> <span class="o">../</span><span class="n">trunk</span> <span class="o">-</span><span class="n">r</span> <span class="mi">0000</span> <span class="c1"># Same as for 2.6 except Misc/NEWS changes are reverted</span> <span class="n">bzr</span> <span class="n">revert</span> <span class="n">Misc</span><span class="o">/</span><span class="n">NEWS</span> <span class="n">bzr</span> <span class="n">commit</span> <span class="o">-</span><span class="n">m</span> <span class="s1">'Forward port patch NNNN'</span> <span class="n">bzr</span> <span class="n">push</span> <span class="n">bzr</span><span class="o">+</span><span class="n">ssh</span><span class="p">:</span><span class="o">//</span><span class="n">me</span><span class="nd">@code</span><span class="o">.</span><span class="n">python</span><span class="o">.</span><span class="n">org</span><span class="o">/</span><span class="n">py3k</span> </pre></div> </div> </section> <section id="id16"> <h4><a class="toc-backref" href="#id16" role="doc-backlink">hg</a></h4> <p>Mercurial, like other DVCS, does not well support the current workflow used by Python core developers to backport patches. Right now, bug fixes are first applied to the development mainline (i.e., trunk), then back-ported to the maintenance branches and forward-ported, as necessary, to the py3k branch. This workflow requires the ability to cherry-pick individual changes. Mercurial’s transplant extension provides this ability. Here is an example of the scenario using this workflow:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">cd</span> <span class="n">release26</span><span class="o">-</span><span class="n">maint</span> <span class="c1"># Assume patch applied to 2.7 in revision 0000</span> <span class="n">hg</span> <span class="n">transplant</span> <span class="o">-</span><span class="n">s</span> <span class="o">../</span><span class="n">trunk</span> <span class="mi">0000</span> <span class="c1"># Resolve conflicts, if any.</span> <span class="n">cd</span> <span class="o">../</span><span class="n">py3k</span> <span class="n">hg</span> <span class="n">pull</span> <span class="o">../</span><span class="n">trunk</span> <span class="n">hg</span> <span class="n">merge</span> <span class="n">hg</span> <span class="n">revert</span> <span class="n">Misc</span><span class="o">/</span><span class="n">NEWS</span> <span class="n">hg</span> <span class="n">commit</span> <span class="o">-</span><span class="n">m</span> <span class="s2">"Merged trunk"</span> <span class="n">hg</span> <span class="n">push</span> </pre></div> </div> <p>In the above example, transplant acts much like the current svnmerge command. When transplant is invoked without the revision, the command launches an interactive loop useful for transplanting multiple changes. Another useful feature is the –filter option which can be used to modify changesets programmatically (e.g., it could be used for removing changes to Misc/NEWS automatically).</p> <p>Alternatively to the traditional workflow, we could avoid transplanting changesets by committing bug fixes to the oldest supported release, then merge these fixes upward to the more recent branches.</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">cd</span> <span class="n">release25</span><span class="o">-</span><span class="n">maint</span> <span class="n">hg</span> <span class="kn">import</span> <span class="nn">fix_some_bug.diff</span> <span class="c1"># Review patch and run test suite. Revert if failure.</span> <span class="n">hg</span> <span class="n">push</span> <span class="n">cd</span> <span class="o">../</span><span class="n">release26</span><span class="o">-</span><span class="n">maint</span> <span class="n">hg</span> <span class="n">pull</span> <span class="o">../</span><span class="n">release25</span><span class="o">-</span><span class="n">maint</span> <span class="n">hg</span> <span class="n">merge</span> <span class="c1"># Resolve conflicts, if any. Then, review patch and run test suite.</span> <span class="n">hg</span> <span class="n">commit</span> <span class="o">-</span><span class="n">m</span> <span class="s2">"Merged patches from release25-maint."</span> <span class="n">hg</span> <span class="n">push</span> <span class="n">cd</span> <span class="o">../</span><span class="n">trunk</span> <span class="n">hg</span> <span class="n">pull</span> <span class="o">../</span><span class="n">release26</span><span class="o">-</span><span class="n">maint</span> <span class="n">hg</span> <span class="n">merge</span> <span class="c1"># Resolve conflicts, if any, then review.</span> <span class="n">hg</span> <span class="n">commit</span> <span class="o">-</span><span class="n">m</span> <span class="s2">"Merged patches from release26-maint."</span> <span class="n">hg</span> <span class="n">push</span> </pre></div> </div> <p>Although this approach makes the history non-linear and slightly more difficult to follow, it encourages fixing bugs across all supported releases. Furthermore, it scales better when there is many changes to backport, because we do not need to seek the specific revision IDs to merge.</p> </section> <section id="id17"> <h4><a class="toc-backref" href="#id17" role="doc-backlink">git</a></h4> <p>In git I would have a workspace which contains all of the relevant master repository branches. git cherry-pick doesn’t work across repositories; you need to have the branches in the same repository.</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># Assume patch applied to 2.7 in revision release27~3 (4th patch back from tip).</span> <span class="n">cd</span> <span class="n">integration</span> <span class="n">git</span> <span class="n">checkout</span> <span class="n">release26</span> <span class="n">git</span> <span class="n">cherry</span><span class="o">-</span><span class="n">pick</span> <span class="n">release27</span><span class="o">~</span><span class="mi">3</span> <span class="c1"># If there are conflicts, resolve them, and commit those changes.</span> <span class="c1"># git commit -a -m "Resolve conflicts."</span> <span class="c1"># Run test suite. If fixes are necessary, record as a separate commit.</span> <span class="c1"># git commit -a -m "Fix code causing test failures."</span> <span class="n">git</span> <span class="n">checkout</span> <span class="n">master</span> <span class="n">git</span> <span class="n">cherry</span><span class="o">-</span><span class="n">pick</span> <span class="n">release27</span><span class="o">~</span><span class="mi">3</span> <span class="c1"># Do any conflict resolution and test failure fixups.</span> <span class="c1"># Revert Misc/NEWS changes.</span> <span class="n">git</span> <span class="n">checkout</span> <span class="n">HEAD</span><span class="o">^</span> <span class="o">--</span> <span class="n">Misc</span><span class="o">/</span><span class="n">NEWS</span> <span class="n">git</span> <span class="n">commit</span> <span class="o">-</span><span class="n">m</span> <span class="s1">'Revert cherry-picked Misc/NEWS changes.'</span> <span class="n">Misc</span><span class="o">/</span><span class="n">NEWS</span> <span class="c1"># Push both ports.</span> <span class="n">git</span> <span class="n">push</span> <span class="n">release26</span> <span class="n">master</span> </pre></div> </div> <p>If you are regularly merging (rather than cherry-picking) from a given branch, then you can block a given commit from being accidentally merged in the future by merging, then reverting it. This does not prevent a cherry-pick from pulling in the unwanted patch, and this technique requires blocking everything that you don’t want merged. I’m not sure if this differs from svn on this point.</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">cd</span> <span class="n">trunk</span> <span class="c1"># Merge in the alpha tested code.</span> <span class="n">git</span> <span class="n">merge</span> <span class="n">experimental</span><span class="o">-</span><span class="n">branch</span> <span class="c1"># We don't want the 3rd-to-last commit from the experimental-branch,</span> <span class="c1"># and we don't want it to ever be merged.</span> <span class="c1"># The notation "^N" means Nth parent of the current commit. Thus HEAD^2^1^1</span> <span class="c1"># means the first parent of the first parent of the second parent of HEAD.</span> <span class="n">git</span> <span class="n">revert</span> <span class="n">HEAD</span><span class="o">^</span><span class="mi">2</span><span class="o">^</span><span class="mi">1</span><span class="o">^</span><span class="mi">1</span> <span class="c1"># Propagate the merge and the prohibition to the public repository.</span> <span class="n">git</span> <span class="n">push</span> </pre></div> </div> </section> </section> <section id="coordinated-development-of-a-new-feature"> <h3><a class="toc-backref" href="#coordinated-development-of-a-new-feature" role="doc-backlink">Coordinated Development of a New Feature</a></h3> <p>Sometimes core developers end up working on a major feature with several developers. As a core developer, I want to be able to publish feature branches to a common public location so that I can collaborate with other developers.</p> <p>This requires creating a branch on a server that other developers can access. All of the DVCSs support creating new repositories on hosts where the developer is already able to commit, with appropriate configuration of the repository host. This is similar in concept to the existing sandbox in svn, although details of repository initialization may differ.</p> <p>For non-core developers, there are various more-or-less public-access repository-hosting services. Bazaar has <a class="reference external" href="http://www.launchpad.net/">Launchpad</a>, Mercurial has <a class="reference external" href="http://www.bitbucket.org/">bitbucket.org</a>, and git has <a class="reference external" href="http://www.github.com/">GitHub</a>. All also have easy-to-use CGI interfaces for developers who maintain their own servers.</p> <ul class="simple"> <li>Branch trunk.</li> <li>Pull from branch on the server.</li> <li>Pull from trunk.</li> <li>Push merge to trunk.</li> </ul> <section id="id18"> <h4><a class="toc-backref" href="#id18" role="doc-backlink">svn</a></h4> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># Create branch.</span> <span class="n">svn</span> <span class="n">copy</span> <span class="n">svn</span><span class="o">+</span><span class="n">ssh</span><span class="p">:</span><span class="o">//</span><span class="n">pythondev</span><span class="nd">@svn</span><span class="o">.</span><span class="n">python</span><span class="o">.</span><span class="n">org</span><span class="o">/</span><span class="n">python</span><span class="o">/</span><span class="n">trunk</span> <span class="n">svn</span><span class="o">+</span><span class="n">ssh</span><span class="p">:</span><span class="o">//</span><span class="n">pythondev</span><span class="nd">@svn</span><span class="o">.</span><span class="n">python</span><span class="o">.</span><span class="n">org</span><span class="o">/</span><span class="n">python</span><span class="o">/</span><span class="n">branches</span><span class="o">/</span><span class="n">NewHotness</span> <span class="n">svn</span> <span class="n">checkout</span> <span class="n">svn</span><span class="o">+</span><span class="n">ssh</span><span class="p">:</span><span class="o">//</span><span class="n">pythondev</span><span class="nd">@svn</span><span class="o">.</span><span class="n">python</span><span class="o">.</span><span class="n">org</span><span class="o">/</span><span class="n">python</span><span class="o">/</span><span class="n">branches</span><span class="o">/</span><span class="n">NewHotness</span> <span class="n">cd</span> <span class="n">NewHotness</span> <span class="n">svnmerge</span> <span class="n">init</span> <span class="n">svn</span> <span class="n">commit</span> <span class="o">-</span><span class="n">m</span> <span class="s2">"Initialize svnmerge."</span> <span class="c1"># Pull in changes from other developers.</span> <span class="n">svn</span> <span class="n">update</span> <span class="c1"># Pull in trunk and merge to the branch.</span> <span class="n">svnmerge</span> <span class="n">merge</span> <span class="n">svn</span> <span class="n">commit</span> <span class="o">-</span><span class="n">F</span> <span class="n">svnmerge</span><span class="o">-</span><span class="n">commit</span><span class="o">-</span><span class="n">message</span><span class="o">.</span><span class="n">txt</span> </pre></div> </div> <p>This scenario is incomplete as the decision for what DVCS to go with was made before the work was complete.</p> </section> </section> <section id="separation-of-issue-dependencies"> <h3><a class="toc-backref" href="#separation-of-issue-dependencies" role="doc-backlink">Separation of Issue Dependencies</a></h3> <p>Sometimes, while working on an issue, it becomes apparent that the problem being worked on is actually a compound issue of various smaller issues. Being able to take the current work and then begin working on a separate issue is very helpful to separate out issues into individual units of work instead of compounding them into a single, large unit.</p> <ul class="simple"> <li>Create a branch A (e.g. urllib has a bug).</li> <li>Edit some code.</li> <li>Create a new branch B that branch A depends on (e.g. the urllib bug exposes a socket bug).</li> <li>Edit some code in branch B.</li> <li>Commit branch B.</li> <li>Edit some code in branch A.</li> <li>Commit branch A.</li> <li>Clean up.</li> </ul> <section id="id19"> <h4><a class="toc-backref" href="#id19" role="doc-backlink">svn</a></h4> <p>To make up for svn’s lack of cheap branching, it has a changelist option to associate a file with a single changelist. This is not as powerful as being able to associate at the commit level. There is also no way to express dependencies between changelists.</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">cp</span> <span class="o">-</span><span class="n">r</span> <span class="n">trunk</span> <span class="n">issue0000</span> <span class="n">cd</span> <span class="n">issue0000</span> <span class="c1"># Edit some code.</span> <span class="n">echo</span> <span class="s2">"The cake is a lie!"</span> <span class="o">></span> <span class="n">README</span> <span class="n">svn</span> <span class="n">changelist</span> <span class="n">A</span> <span class="n">README</span> <span class="c1"># Edit some other code.</span> <span class="n">echo</span> <span class="s2">"I own Python!"</span> <span class="o">></span> <span class="n">LICENSE</span> <span class="n">svn</span> <span class="n">changelist</span> <span class="n">B</span> <span class="n">LICENSE</span> <span class="n">svn</span> <span class="n">ci</span> <span class="o">-</span><span class="n">m</span> <span class="s2">"Tell it how it is."</span> <span class="o">--</span><span class="n">changelist</span> <span class="n">B</span> <span class="c1"># Edit changelist A some more.</span> <span class="n">svn</span> <span class="n">ci</span> <span class="o">-</span><span class="n">m</span> <span class="s2">"Speak the truth."</span> <span class="o">--</span><span class="n">changelist</span> <span class="n">A</span> <span class="n">cd</span> <span class="o">..</span> <span class="n">rm</span> <span class="o">-</span><span class="n">rf</span> <span class="n">issue0000</span> </pre></div> </div> </section> <section id="id20"> <h4><a class="toc-backref" href="#id20" role="doc-backlink">bzr</a></h4> <p>Here’s an approach that uses bzr shelf (now a standard part of bzr) to squirrel away some changes temporarily while you take a detour to fix the socket bugs.</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">bzr</span> <span class="n">branch</span> <span class="n">trunk</span> <span class="n">bug</span><span class="o">-</span><span class="mi">0000</span> <span class="n">cd</span> <span class="n">bug</span><span class="o">-</span><span class="mi">0000</span> <span class="c1"># Edit some code. Dang, we need to fix the socket module.</span> <span class="n">bzr</span> <span class="n">shelve</span> <span class="o">--</span><span class="nb">all</span> <span class="c1"># Edit some code.</span> <span class="n">bzr</span> <span class="n">commit</span> <span class="o">-</span><span class="n">m</span> <span class="s2">"Socket module fixes"</span> <span class="c1"># Detour over, now resume fixing urllib</span> <span class="n">bzr</span> <span class="n">unshelve</span> <span class="c1"># Edit some code</span> </pre></div> </div> <p>Another approach uses the loom plugin. Looms can greatly simplify working on dependent branches because they automatically take care of the stacking dependencies for you. Imagine looms as a stack of dependent branches (called “threads” in loom parlance), with easy ways to move up and down the stack of threads, merge changes up the stack to descendant threads, create diffs between threads, etc. Occasionally, you may need or want to export your loom threads into separate branches, either for review or commit. Higher threads incorporate all the changes in the lower threads, automatically.</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">bzr</span> <span class="n">branch</span> <span class="n">trunk</span> <span class="n">bug</span><span class="o">-</span><span class="mi">0000</span> <span class="n">cd</span> <span class="n">bug</span><span class="o">-</span><span class="mi">0000</span> <span class="n">bzr</span> <span class="n">loomify</span> <span class="o">--</span><span class="n">base</span> <span class="n">trunk</span> <span class="n">bzr</span> <span class="n">create</span><span class="o">-</span><span class="n">thread</span> <span class="n">fix</span><span class="o">-</span><span class="n">urllib</span> <span class="c1"># Edit some code. Dang, we need to fix the socket module first.</span> <span class="n">bzr</span> <span class="n">commit</span> <span class="o">-</span><span class="n">m</span> <span class="s2">"Checkpointing my work so far"</span> <span class="n">bzr</span> <span class="n">down</span><span class="o">-</span><span class="n">thread</span> <span class="n">bzr</span> <span class="n">create</span><span class="o">-</span><span class="n">thread</span> <span class="n">fix</span><span class="o">-</span><span class="n">socket</span> <span class="c1"># Edit some code</span> <span class="n">bzr</span> <span class="n">commit</span> <span class="o">-</span><span class="n">m</span> <span class="s2">"Socket module fixes"</span> <span class="n">bzr</span> <span class="n">up</span><span class="o">-</span><span class="n">thread</span> <span class="c1"># Manually resolve conflicts if necessary</span> <span class="n">bzr</span> <span class="n">commit</span> <span class="o">-</span><span class="n">m</span> <span class="s1">'Merge in socket fixes'</span> <span class="c1"># Edit me some more code</span> <span class="n">bzr</span> <span class="n">commit</span> <span class="o">-</span><span class="n">m</span> <span class="s2">"Now that socket is fixed, complete the urllib fixes"</span> <span class="n">bzr</span> <span class="n">record</span> <span class="n">done</span> </pre></div> </div> <p>For bonus points, let’s say someone else fixes the socket module in exactly the same way you just did. Perhaps this person even grabbed your fix-socket thread and applied just that to the trunk. You’d like to be able to merge their changes into your loom and delete your now-redundant fix-socket thread.</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">bzr</span> <span class="n">down</span><span class="o">-</span><span class="n">thread</span> <span class="n">trunk</span> <span class="c1"># Get all new revisions to the trunk. If you've done things</span> <span class="c1"># correctly, this will succeed without conflict.</span> <span class="n">bzr</span> <span class="n">pull</span> <span class="n">bzr</span> <span class="n">up</span><span class="o">-</span><span class="n">thread</span> <span class="c1"># See? The fix-socket thread is now identical to the trunk</span> <span class="n">bzr</span> <span class="n">commit</span> <span class="o">-</span><span class="n">m</span> <span class="s1">'Merge in trunk changes'</span> <span class="n">bzr</span> <span class="n">diff</span> <span class="o">-</span><span class="n">r</span> <span class="n">thread</span><span class="p">:</span> <span class="o">|</span> <span class="n">wc</span> <span class="o">-</span><span class="n">l</span> <span class="c1"># returns 0</span> <span class="n">bzr</span> <span class="n">combine</span><span class="o">-</span><span class="n">thread</span> <span class="n">bzr</span> <span class="n">up</span><span class="o">-</span><span class="n">thread</span> <span class="c1"># Resolve any conflicts</span> <span class="n">bzr</span> <span class="n">commit</span> <span class="o">-</span><span class="n">m</span> <span class="s1">'Merge trunk'</span> <span class="c1"># Now our top-thread has an up-to-date trunk and just the urllib fix.</span> </pre></div> </div> </section> <section id="id21"> <h4><a class="toc-backref" href="#id21" role="doc-backlink">hg</a></h4> <p>One approach is to use the shelve extension; this extension is not included with Mercurial, but it is easy to install. With shelve, you can select changes to put temporarily aside.</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">hg</span> <span class="n">clone</span> <span class="n">trunk</span> <span class="n">issue0000</span> <span class="n">cd</span> <span class="n">issue0000</span> <span class="c1"># Edit some code (e.g. urllib).</span> <span class="n">hg</span> <span class="n">shelve</span> <span class="c1"># Select changes to put aside</span> <span class="c1"># Edit some other code (e.g. socket).</span> <span class="n">hg</span> <span class="n">commit</span> <span class="n">hg</span> <span class="n">unshelve</span> <span class="c1"># Complete initial fix.</span> <span class="n">hg</span> <span class="n">commit</span> <span class="n">cd</span> <span class="o">../</span><span class="n">trunk</span> <span class="n">hg</span> <span class="n">pull</span> <span class="o">../</span><span class="n">issue0000</span> <span class="n">hg</span> <span class="n">merge</span> <span class="n">hg</span> <span class="n">commit</span> <span class="n">rm</span> <span class="o">-</span><span class="n">rf</span> <span class="o">../</span><span class="n">issue0000</span> </pre></div> </div> <p>Several other way to approach this scenario with Mercurial. Alexander Solovyov presented a few <a class="reference external" href="http://selenic.com/pipermail/mercurial/2009-January/023710.html">alternative approaches</a> on Mercurial’s mailing list.</p> </section> <section id="id22"> <h4><a class="toc-backref" href="#id22" role="doc-backlink">git</a></h4> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">cd</span> <span class="n">trunk</span> <span class="c1"># Edit some code in urllib.</span> <span class="c1"># Discover a bug in socket, want to fix that first.</span> <span class="c1"># So save away our current work.</span> <span class="n">git</span> <span class="n">stash</span> <span class="c1"># Edit some code, commit some changes.</span> <span class="n">git</span> <span class="n">commit</span> <span class="o">-</span><span class="n">a</span> <span class="o">-</span><span class="n">m</span> <span class="s2">"Completed fix of socket."</span> <span class="c1"># Restore the in-progress work on urllib.</span> <span class="n">git</span> <span class="n">stash</span> <span class="n">apply</span> <span class="c1"># Edit me some more code, commit some more fixes.</span> <span class="n">git</span> <span class="n">commit</span> <span class="o">-</span><span class="n">a</span> <span class="o">-</span><span class="n">m</span> <span class="s2">"Complete urllib fixes."</span> <span class="c1"># And push both patches to the public repository.</span> <span class="n">git</span> <span class="n">push</span> </pre></div> </div> <p>Bonus points: suppose you took your time, and someone else fixes socket in the same way you just did, and landed that in the trunk. In that case, your push will fail because your branch is not up-to-date. If the fix was a one-liner, there’s a very good chance that it’s <em>exactly</em> the same, character for character. git would notice that, and you are done; git will silently merge them.</p> <p>Suppose we’re not so lucky:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># Update your branch.</span> <span class="n">git</span> <span class="n">pull</span> <span class="n">git</span><span class="p">:</span><span class="o">//</span><span class="n">code</span><span class="o">.</span><span class="n">python</span><span class="o">.</span><span class="n">org</span><span class="o">/</span><span class="n">public</span><span class="o">/</span><span class="n">trunk</span> <span class="n">master</span> <span class="c1"># git has fetched all the necessary data, but reports that the</span> <span class="c1"># merge failed. We discover the nearly-duplicated patch.</span> <span class="c1"># Neither our version of the master branch nor the workspace has</span> <span class="c1"># been touched. Revert our socket patch and pull again:</span> <span class="n">git</span> <span class="n">revert</span> <span class="n">HEAD</span><span class="o">^</span> <span class="n">git</span> <span class="n">pull</span> <span class="n">git</span><span class="p">:</span><span class="o">//</span><span class="n">code</span><span class="o">.</span><span class="n">python</span><span class="o">.</span><span class="n">org</span><span class="o">/</span><span class="n">public</span><span class="o">/</span><span class="n">trunk</span> <span class="n">master</span> </pre></div> </div> <p>Like Bazaar and Mercurial, git has extensions to manage stacks of patches. You can use the original Quilt by Andrew Morton, or there is StGit (“stacked git”) which integrates patch-tracking for large sets of patches into the VCS in a way similar to Mercurial Queues or Bazaar looms.</p> </section> </section> <section id="doing-a-python-release"> <h3><a class="toc-backref" href="#doing-a-python-release" role="doc-backlink">Doing a Python Release</a></h3> <p>How does <a class="pep reference internal" href="../pep-0101/" title="PEP 101 – Doing Python Releases 101">PEP 101</a> change when using a DVCS?</p> <section id="id23"> <h4><a class="toc-backref" href="#id23" role="doc-backlink">bzr</a></h4> <p>It will change, but not substantially so. When doing the maintenance branch, we’ll just push to the new location instead of doing an svn cp. Tags are totally different, since in svn they are directory copies, but in bzr (and I’m guessing hg), they are just symbolic names for revisions on a particular branch. The release.py script will have to change to use bzr commands instead. It’s possible that because DVCS (in particular, bzr) does cherry picking and merging well enough that we’ll be able to create the maint branches sooner. It would be a useful exercise to try to do a release off the bzr/hg mirrors.</p> </section> <section id="id24"> <h4><a class="toc-backref" href="#id24" role="doc-backlink">hg</a></h4> <p>Clearly, details specific to Subversion in <a class="pep reference internal" href="../pep-0101/" title="PEP 101 – Doing Python Releases 101">PEP 101</a> and in the release script will need to be updated. In particular, release tagging and maintenance branches creation process will have to be modified to use Mercurial’s features; this will simplify and streamline certain aspects of the release process. For example, tagging and re-tagging a release will become a trivial operation since a tag, in Mercurial, is simply a symbolic name for a given revision.</p> </section> <section id="id25"> <h4><a class="toc-backref" href="#id25" role="doc-backlink">git</a></h4> <p>It will change, but not substantially so. When doing the maintenance branch, we’ll just git push to the new location instead of doing an svn cp. Tags are totally different, since in svn they are directory copies, but in git they are just symbolic names for revisions, as are branches. (The difference between a tag and a branch is that tags refer to a particular commit, and will never change unless you use git tag -f to force them to move. The checked-out branch, on the other hand, is automatically updated by git commit.) The release.py script will have to change to use git commands instead. With git I would create a (local) maintenance branch as soon as the release engineer is chosen. Then I’d “git pull” until I didn’t like a patch, when it would be “git pull; git revert ugly-patch”, until it started to look like the sensible thing is to fork off, and start doing “git cherry-pick” on the good patches.</p> </section> </section> </section> <section id="platform-tool-support"> <h2><a class="toc-backref" href="#platform-tool-support" role="doc-backlink">Platform/Tool Support</a></h2> <section id="operating-systems"> <h3><a class="toc-backref" href="#operating-systems" role="doc-backlink">Operating Systems</a></h3> <table class="docutils align-default"> <thead> <tr class="row-odd"><th class="head">DVCS</th> <th class="head">Windows</th> <th class="head">OS X</th> <th class="head">UNIX</th> </tr> </thead> <tbody> <tr class="row-even"><td>bzr</td> <td>yes (installer) w/ tortoise</td> <td>yes (installer, fink or MacPorts)</td> <td>yes (various package formats)</td> </tr> <tr class="row-odd"><td>hg</td> <td>yes (third-party installer) w/ tortoise</td> <td>yes (third-party installer, fink or MacPorts)</td> <td>yes (various package formats)</td> </tr> <tr class="row-even"><td>git</td> <td>yes (third-party installer)</td> <td>yes (third-party installer, fink or MacPorts)</td> <td>yes (.deb or .rpm)</td> </tr> </tbody> </table> <p>As the above table shows, all three DVCSs are available on all three major OS platforms. But what it also shows is that Bazaar is the only DVCS that directly supports Windows with a binary installer while Mercurial and git require you to rely on a third-party for binaries. Both bzr and hg have a tortoise version while git does not.</p> <p>Bazaar and Mercurial also has the benefit of being available in pure Python with optional extensions available for performance.</p> </section> <section id="crlf-lf-support"> <h3><a class="toc-backref" href="#crlf-lf-support" role="doc-backlink">CRLF -> LF Support</a></h3> <dl class="simple"> <dt>bzr</dt><dd>My understanding is that support for this is being worked on as I type, landing in a version RSN. I will try to dig up details.</dd> <dt>hg</dt><dd>Supported via the win32text extension.</dd> <dt>git</dt><dd>I can’t say from personal experience, but it looks like there’s pretty good support via the core.autocrlf and core.safecrlf configuration attributes.</dd> </dl> </section> <section id="case-insensitive-filesystem-support"> <h3><a class="toc-backref" href="#case-insensitive-filesystem-support" role="doc-backlink">Case-insensitive filesystem support</a></h3> <dl class="simple"> <dt>bzr</dt><dd>Should be OK. I share branches between Linux and OS X all the time. I’ve done case changes (e.g. <code class="docutils literal notranslate"><span class="pre">bzr</span> <span class="pre">mv</span> <span class="pre">Mailman</span> <span class="pre">mailman</span></code>) and as long as I did it on Linux (obviously), when I pulled in the changes on OS X everything was hunky dory.</dd> <dt>hg</dt><dd>Mercurial uses a case safe repository mechanism and detects case folding collisions.</dd> <dt>git</dt><dd>Since OS X preserves case, you can do case changes there too. git does not have a problem with renames in either direction. However, case-insensitive filesystem support is usually taken to mean complaining about collisions on case-sensitive files systems. git does not do that.</dd> </dl> </section> <section id="tools"> <h3><a class="toc-backref" href="#tools" role="doc-backlink">Tools</a></h3> <p>In terms of code review tools such as <a class="reference external" href="http://www.review-board.org/">Review Board</a> and <a class="reference external" href="http://code.google.com/p/rietveld/">Rietveld</a>, the former supports all three while the latter supports hg and git but not bzr. Bazaar does not yet have an online review board, but it has several ways to manage email based reviews and trunk merging. There’s <a class="reference external" href="http://code.aaronbentley.com/bundlebuggy/">Bundle Buggy</a>, <a class="reference external" href="http://bazaar-vcs.org/PatchQueueManager">Patch Queue Manager</a> (PQM), and <a class="reference external" href="https://launchpad.net/+tour/code-review">Launchpad’s code reviews</a>.</p> <p>All three have some web site online that provides basic hosting support for people who want to put a repository online. Bazaar has Launchpad, Mercurial has bitbucket.org, and git has GitHub. Google Code also has instructions on how to use git with the service, both to hold a repository and how to act as a read-only mirror.</p> <p>All three also <a class="reference external" href="http://buildbot.net/repos/release/docs/buildbot.html#How-Different-VC-Systems-Specify-Sources">appear to be supported</a> by <a class="reference external" href="http://buildbot.net">Buildbot</a>.</p> </section> </section> <section id="usage-on-top-of-subversion"> <h2><a class="toc-backref" href="#usage-on-top-of-subversion" role="doc-backlink">Usage On Top Of Subversion</a></h2> <table class="docutils align-default"> <thead> <tr class="row-odd"><th class="head">DVCS</th> <th class="head">svn support</th> </tr> </thead> <tbody> <tr class="row-even"><td>bzr</td> <td><a class="reference external" href="http://bazaar-vcs.org/BzrForeignBranches/Subversion">bzr-svn</a> (third-party)</td> </tr> <tr class="row-odd"><td>hg</td> <td><a class="reference external" href="http://www.selenic.com/mercurial/wiki/index.cgi/WorkingWithSubversion">multiple third-parties</a></td> </tr> <tr class="row-even"><td>git</td> <td><a class="reference external" href="http://www.kernel.org/pub/software/scm/git/docs/git-svn.html">git-svn</a></td> </tr> </tbody> </table> <p>All three DVCSs have svn support, although git is the only one to come with that support out-of-the-box.</p> </section> <section id="server-support"> <h2><a class="toc-backref" href="#server-support" role="doc-backlink">Server Support</a></h2> <table class="docutils align-default"> <thead> <tr class="row-odd"><th class="head">DVCS</th> <th class="head">Web page interface</th> </tr> </thead> <tbody> <tr class="row-even"><td>bzr</td> <td><a class="reference external" href="https://launchpad.net/loggerhead">loggerhead</a></td> </tr> <tr class="row-odd"><td>hg</td> <td><a class="reference external" href="http://www.selenic.com/mercurial/wiki/index.cgi/HgWebDirStepByStep">hgweb</a></td> </tr> <tr class="row-even"><td>git</td> <td><a class="reference external" href="http://git.or.cz/gitwiki/Gitweb">gitweb</a></td> </tr> </tbody> </table> <p>All three DVCSs support various hooks on the client and server side for e.g. pre/post-commit verifications.</p> </section> <section id="development"> <h2><a class="toc-backref" href="#development" role="doc-backlink">Development</a></h2> <p>All three projects are under active development. Git seems to be on a monthly release schedule. Bazaar is on a time-released monthly schedule. Mercurial is on a 4-month, timed release schedule.</p> </section> <section id="special-features"> <h2><a class="toc-backref" href="#special-features" role="doc-backlink">Special Features</a></h2> <section id="id26"> <h3><a class="toc-backref" href="#id26" role="doc-backlink">bzr</a></h3> <p>Martin Pool adds: “bzr has a stable Python scripting interface, with a distinction between public and private interfaces and a deprecation window for APIs that are changing. Some plugins are listed in <a class="reference external" href="https://edge.launchpad.net/bazaar">https://edge.launchpad.net/bazaar</a> and <a class="reference external" href="http://bazaar-vcs.org/Documentation">http://bazaar-vcs.org/Documentation</a>”.</p> </section> <section id="id27"> <h3><a class="toc-backref" href="#id27" role="doc-backlink">hg</a></h3> <p>Alexander Solovyov comments:</p> <blockquote> <div>Mercurial has easy to use extensive API with hooks for main events and ability to extend commands. Also there is the mq (mercurial queues) extension, distributed with Mercurial, which simplifies work with patches.</div></blockquote> </section> <section id="id28"> <h3><a class="toc-backref" href="#id28" role="doc-backlink">git</a></h3> <p>git has a cvsserver mode, ie, you can check out a tree from git using CVS. You can even commit to the tree, but features like merging are absent, and branches are handled as CVS modules, which is likely to shock a veteran CVS user.</p> </section> </section> <section id="tests-impressions"> <h2><a class="toc-backref" href="#tests-impressions" role="doc-backlink">Tests/Impressions</a></h2> <p>As I (Brett Cannon) am left with the task of making the final decision of which/any DVCS to go with and not my co-authors, I felt it only fair to write down what tests I ran and my impressions as I evaluate the various tools so as to be as transparent as possible.</p> <section id="barrier-to-entry"> <h3><a class="toc-backref" href="#barrier-to-entry" role="doc-backlink">Barrier to Entry</a></h3> <p>The amount of time and effort it takes to get a checkout of Python’s repository is critical. If the difficulty or time is too great then a person wishing to contribute to Python may very well give up. That cannot be allowed to happen.</p> <p>I measured the checking out of the 2.x trunk as if I was a non-core developer. Timings were done using the <code class="docutils literal notranslate"><span class="pre">time</span></code> command in zsh and space was calculated with <code class="docutils literal notranslate"><span class="pre">du</span> <span class="pre">-c</span> <span class="pre">-h</span></code>.</p> <table class="docutils align-default"> <thead> <tr class="row-odd"><th class="head">DVCS</th> <th class="head">San Francisco</th> <th class="head">Vancouver</th> <th class="head">Space</th> </tr> </thead> <tbody> <tr class="row-even"><td>svn</td> <td>1:04</td> <td>2:59</td> <td>139 M</td> </tr> <tr class="row-odd"><td>bzr</td> <td>10:45</td> <td>16:04</td> <td>276 M</td> </tr> <tr class="row-even"><td>hg</td> <td>2:30</td> <td>5:24</td> <td>171 M</td> </tr> <tr class="row-odd"><td>git</td> <td>2:54</td> <td>5:28</td> <td>134 M</td> </tr> </tbody> </table> <p>When comparing these numbers to svn, it is important to realize that it is not a 1:1 comparison. Svn does not pull down the entire revision history like all of the DVCSs do. That means svn can perform an initial checkout much faster than the DVCS purely based on the fact that it has less information to download for the network.</p> </section> <section id="performance-of-basic-information-functionality"> <h3><a class="toc-backref" href="#performance-of-basic-information-functionality" role="doc-backlink">Performance of basic information functionality</a></h3> <p>To see how the tools did for performing a command that required querying the history, the log for the <code class="docutils literal notranslate"><span class="pre">README</span></code> file was timed.</p> <table class="docutils align-default"> <thead> <tr class="row-odd"><th class="head">DVCS</th> <th class="head">Time</th> </tr> </thead> <tbody> <tr class="row-even"><td>bzr</td> <td>4.5 s</td> </tr> <tr class="row-odd"><td>hg</td> <td>1.1 s</td> </tr> <tr class="row-even"><td>git</td> <td>1.5 s</td> </tr> </tbody> </table> <p>One thing of note during this test was that git took longer than the other three tools to figure out how to get the log without it using a pager. While the pager use is a nice touch in general, not having it automatically turn on took some time (turns out the main <code class="docutils literal notranslate"><span class="pre">git</span></code> command has a <code class="docutils literal notranslate"><span class="pre">--no-pager</span></code> flag to disable use of the pager).</p> </section> <section id="figuring-out-what-command-to-use-from-built-in-help"> <h3><a class="toc-backref" href="#figuring-out-what-command-to-use-from-built-in-help" role="doc-backlink">Figuring out what command to use from built-in help</a></h3> <p>I ended up trying to find out what the command was to see what URL the repository was cloned from. To do this I used nothing more than the help provided by the tool itself or its man pages.</p> <p>Bzr was the easiest: <code class="docutils literal notranslate"><span class="pre">bzr</span> <span class="pre">info</span></code>. Running <code class="docutils literal notranslate"><span class="pre">bzr</span> <span class="pre">help</span></code> didn’t show what I wanted, but mentioned <code class="docutils literal notranslate"><span class="pre">bzr</span> <span class="pre">help</span> <span class="pre">commands</span></code>. That list had the command with a description that made sense.</p> <p>Git was the second easiest. The command <code class="docutils literal notranslate"><span class="pre">git</span> <span class="pre">help</span></code> didn’t show much and did not have a way of listing all commands. That is when I viewed the man page. Reading through the various commands I discovered <code class="docutils literal notranslate"><span class="pre">git</span> <span class="pre">remote</span></code>. The command itself spit out nothing more than <code class="docutils literal notranslate"><span class="pre">origin</span></code>. Trying <code class="docutils literal notranslate"><span class="pre">git</span> <span class="pre">remote</span> <span class="pre">origin</span></code> said it was an error and printed out the command usage. That is when I noticed <code class="docutils literal notranslate"><span class="pre">git</span> <span class="pre">remote</span> <span class="pre">show</span></code>. Running <code class="docutils literal notranslate"><span class="pre">git</span> <span class="pre">remote</span> <span class="pre">show</span> <span class="pre">origin</span></code> gave me the information I wanted.</p> <p>For hg, I never found the information I wanted on my own. It turns out I wanted <code class="docutils literal notranslate"><span class="pre">hg</span> <span class="pre">paths</span></code>, but that was not obvious from the description of “show definition of symbolic path names” as printed by <code class="docutils literal notranslate"><span class="pre">hg</span> <span class="pre">help</span></code> (it should be noted that reporting this in the PEP did lead to the Mercurial developers to clarify the wording to make the use of the <code class="docutils literal notranslate"><span class="pre">hg</span> <span class="pre">paths</span></code> command clearer).</p> </section> <section id="updating-a-checkout"> <h3><a class="toc-backref" href="#updating-a-checkout" role="doc-backlink">Updating a checkout</a></h3> <p>To see how long it takes to update an outdated repository I timed both updating a repository 700 commits behind and 50 commits behind (three weeks stale and 1 week stale, respectively).</p> <table class="docutils align-default"> <thead> <tr class="row-odd"><th class="head">DVCS</th> <th class="head">700 commits</th> <th class="head">50 commits</th> </tr> </thead> <tbody> <tr class="row-even"><td>bzr</td> <td>39 s</td> <td>7 s</td> </tr> <tr class="row-odd"><td>hg</td> <td>17 s</td> <td>3 s</td> </tr> <tr class="row-even"><td>git</td> <td>N/A</td> <td>4 s</td> </tr> </tbody> </table> <div class="admonition note"> <p class="admonition-title">Note</p> <p>Git lacks a value for the <em>700 commits</em> scenario as it does not seem to allow checking out a repository at a specific revision.</p> </div> <p>Git deserves special mention for its output from <code class="docutils literal notranslate"><span class="pre">git</span> <span class="pre">pull</span></code>. It not only lists the delta change information for each file but also color-codes the information.</p> </section> </section> <section id="decision"> <h2><a class="toc-backref" href="#decision" role="doc-backlink">Decision</a></h2> <p>At PyCon 2009 the decision was made to go with Mercurial.</p> <section id="why-mercurial-over-subversion"> <h3><a class="toc-backref" href="#why-mercurial-over-subversion" role="doc-backlink">Why Mercurial over Subversion</a></h3> <p>While svn has served the development team well, it needs to be admitted that svn does not serve the needs of non-committers as well as a DVCS does. Because svn only provides its features such as version control, branching, etc. to people with commit privileges on the repository it can be a hindrance for people who lack commit privileges. But DVCSs have no such limitation as anyone can create a local branch of Python and perform their own local commits without the burden that comes with cloning the entire svn repository. Allowing anyone to have the same workflow as the core developers was the key reason to switch from svn to hg.</p> <p>Orthogonal to the benefits of allowing anyone to easily commit locally to their own branches is offline, fast operations. Because hg stores all data locally there is no need to send requests to a server remotely and instead work off of the local disk. This improves response times tremendously. It also allows for offline usage for when one lacks an Internet connection. But this benefit is minor and considered simply a side-effect benefit instead of a driving factor for switching off of Subversion.</p> </section> <section id="why-mercurial-over-other-dvcss"> <h3><a class="toc-backref" href="#why-mercurial-over-other-dvcss" role="doc-backlink">Why Mercurial over other DVCSs</a></h3> <p>Git was not chosen for three key reasons (see the <a class="reference external" href="http://pycon.blip.tv/file/1947231/">PyCon 2009 lightning talk</a> where Brett Cannon lists these exact reasons; talk started at 3:45). First, git’s Windows support is the weakest out of the three DVCSs being considered which is unacceptable as Python needs to support development on any platform it runs on. Since Python runs on Windows and some people do develop on the platform it needs solid support. And while git’s support is improving, as of this moment it is the weakest by a large enough margin to warrant considering it a problem.</p> <p>Second, and just as important as the first issue, is that the Python core developers liked git the least out of the three DVCS options by a wide margin. If you look at the following table you will see the results of a survey taken of the core developers and how by a large margin git is the least favorite version control system.</p> <table class="docutils align-default"> <thead> <tr class="row-odd"><th class="head">DVCS</th> <th class="head">++</th> <th class="head">equal</th> <th class="head">–</th> <th class="head">Uninformed</th> </tr> </thead> <tbody> <tr class="row-even"><td>git</td> <td>5</td> <td>1</td> <td>8</td> <td>13</td> </tr> <tr class="row-odd"><td>bzr</td> <td>10</td> <td>3</td> <td>2</td> <td>12</td> </tr> <tr class="row-even"><td>hg</td> <td>15</td> <td>1</td> <td>1</td> <td>10</td> </tr> </tbody> </table> <p>Lastly, all things being equal (which they are not as shown by the previous two issues), it is preferable to use and support a tool written in Python and not one written in C and shell. We are pragmatic enough to not choose a tool simply because it is written in Python, but we do see the usefulness in promoting tools that do use it when it is reasonable to do so as it is in this case.</p> <p>As for why Mercurial was chosen over Bazaar, it came down to popularity. As the core developer survey shows, hg was preferred over bzr. But the community also appears to prefer hg as was shown at PyCon after git’s removal from consideration was announced. Many people came up to Brett and said in various ways that they wanted hg to be chosen. While no one said they did not want bzr chosen, no one said they did either.</p> <p>Based on all of this information, Guido and Brett decided Mercurial was to be the next version control system for Python.</p> </section> </section> <section id="transition-plan"> <h2><a class="toc-backref" href="#transition-plan" role="doc-backlink">Transition Plan</a></h2> <p><a class="pep reference internal" href="../pep-0385/" title="PEP 385 – Migrating from Subversion to Mercurial">PEP 385</a> outlines the transition from svn to hg.</p> </section> <section id="copyright"> <h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2> <p>This document has been placed in the public domain.</p> </section> </section> <hr class="docutils" /> <p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0374.rst">https://github.com/python/peps/blob/main/peps/pep-0374.rst</a></p> <p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0374.rst">2023-09-09 17:39:29 GMT</a></p> </article> <nav id="pep-sidebar"> <h2>Contents</h2> <ul> <li><a class="reference internal" href="#rationale">Rationale</a></li> <li><a class="reference internal" href="#terminology">Terminology</a></li> <li><a class="reference internal" href="#typical-workflow">Typical Workflow</a></li> <li><a class="reference internal" href="#contenders">Contenders</a></li> <li><a class="reference internal" href="#interoperability">Interoperability</a></li> <li><a class="reference internal" href="#usage-scenarios">Usage Scenarios</a><ul> <li><a class="reference internal" href="#initial-setup">Initial Setup</a><ul> <li><a class="reference internal" href="#svn">svn</a></li> <li><a class="reference internal" href="#bzr">bzr</a></li> <li><a class="reference internal" href="#hg">hg</a></li> <li><a class="reference internal" href="#id1">git</a></li> </ul> </li> <li><a class="reference internal" href="#one-off-checkout">One-Off Checkout</a><ul> <li><a class="reference internal" href="#id2">svn</a></li> <li><a class="reference internal" href="#id3">bzr</a></li> <li><a class="reference internal" href="#id4">hg</a></li> <li><a class="reference internal" href="#id5">git</a></li> </ul> </li> <li><a class="reference internal" href="#backing-out-changes">Backing Out Changes</a><ul> <li><a class="reference internal" href="#id6">svn</a></li> <li><a class="reference internal" href="#id7">bzr</a></li> <li><a class="reference internal" href="#id8">hg</a></li> <li><a class="reference internal" href="#id9">git</a></li> </ul> </li> <li><a class="reference internal" href="#patch-review">Patch Review</a><ul> <li><a class="reference internal" href="#id10">svn</a></li> <li><a class="reference internal" href="#id11">bzr</a></li> <li><a class="reference internal" href="#id12">hg</a></li> <li><a class="reference internal" href="#id13">git</a></li> </ul> </li> <li><a class="reference internal" href="#backport">Backport</a><ul> <li><a class="reference internal" href="#id14">svn</a></li> <li><a class="reference internal" href="#id15">bzr</a></li> <li><a class="reference internal" href="#id16">hg</a></li> <li><a class="reference internal" href="#id17">git</a></li> </ul> </li> <li><a class="reference internal" href="#coordinated-development-of-a-new-feature">Coordinated Development of a New Feature</a><ul> <li><a class="reference internal" href="#id18">svn</a></li> </ul> </li> <li><a class="reference internal" href="#separation-of-issue-dependencies">Separation of Issue Dependencies</a><ul> <li><a class="reference internal" href="#id19">svn</a></li> <li><a class="reference internal" href="#id20">bzr</a></li> <li><a class="reference internal" href="#id21">hg</a></li> <li><a class="reference internal" href="#id22">git</a></li> </ul> </li> <li><a class="reference internal" href="#doing-a-python-release">Doing a Python Release</a><ul> <li><a class="reference internal" href="#id23">bzr</a></li> <li><a class="reference internal" href="#id24">hg</a></li> <li><a class="reference internal" href="#id25">git</a></li> </ul> </li> </ul> </li> <li><a class="reference internal" href="#platform-tool-support">Platform/Tool Support</a><ul> <li><a class="reference internal" href="#operating-systems">Operating Systems</a></li> <li><a class="reference internal" href="#crlf-lf-support">CRLF -> LF Support</a></li> <li><a class="reference internal" href="#case-insensitive-filesystem-support">Case-insensitive filesystem support</a></li> <li><a class="reference internal" href="#tools">Tools</a></li> </ul> </li> <li><a class="reference internal" href="#usage-on-top-of-subversion">Usage On Top Of Subversion</a></li> <li><a class="reference internal" href="#server-support">Server Support</a></li> <li><a class="reference internal" href="#development">Development</a></li> <li><a class="reference internal" href="#special-features">Special Features</a><ul> <li><a class="reference internal" href="#id26">bzr</a></li> <li><a class="reference internal" href="#id27">hg</a></li> <li><a class="reference internal" href="#id28">git</a></li> </ul> </li> <li><a class="reference internal" href="#tests-impressions">Tests/Impressions</a><ul> <li><a class="reference internal" href="#barrier-to-entry">Barrier to Entry</a></li> <li><a class="reference internal" href="#performance-of-basic-information-functionality">Performance of basic information functionality</a></li> <li><a class="reference internal" href="#figuring-out-what-command-to-use-from-built-in-help">Figuring out what command to use from built-in help</a></li> <li><a class="reference internal" href="#updating-a-checkout">Updating a checkout</a></li> </ul> </li> <li><a class="reference internal" href="#decision">Decision</a><ul> <li><a class="reference internal" href="#why-mercurial-over-subversion">Why Mercurial over Subversion</a></li> <li><a class="reference internal" href="#why-mercurial-over-other-dvcss">Why Mercurial over other DVCSs</a></li> </ul> </li> <li><a class="reference internal" href="#transition-plan">Transition Plan</a></li> <li><a class="reference internal" href="#copyright">Copyright</a></li> </ul> <br> <a id="source" href="https://github.com/python/peps/blob/main/peps/pep-0374.rst">Page Source (GitHub)</a> </nav> </section> <script src="../_static/colour_scheme.js"></script> <script src="../_static/wrap_tables.js"></script> <script src="../_static/sticky_banner.js"></script> </body> </html>