# HG changeset patch # User Pierre-Yves David # Date 1348175699 -7200 # Node ID 5a0a01c4c7c2260d3f1328bab3adf792b7805f04 # Parent 53d7e34133377bceade8815d081ee511a28a210e# Parent dc107acd0bd294d57f10b4b6baca55715b4cee9b merge stable into default diff -r 53d7e3413337 -r 5a0a01c4c7c2 .hgignore --- a/.hgignore Fri Aug 24 11:49:21 2012 +0200 +++ b/.hgignore Thu Sep 20 23:14:59 2012 +0200 @@ -11,3 +11,6 @@ \.err$ ^tests/easy_run.sh$ ^build/ +^MANIFEST$ +^docs/tutorials/.*\.rst$ +\.ico$ diff -r 53d7e3413337 -r 5a0a01c4c7c2 .hgtags --- a/.hgtags Fri Aug 24 11:49:21 2012 +0200 +++ b/.hgtags Thu Sep 20 23:14:59 2012 +0200 @@ -8,3 +8,7 @@ 18a0d96ed559089edf90206c469f3f8c26681c64 0.7 18a0d96ed559089edf90206c469f3f8c26681c64 0.7 1b2757c1bd918509184f6c1d06b2329a847e31b0 0.7 +b18b000363550f02f413aed008f8e306318c608c 1.0.0 +ca5bb72d14aeb6e6053e3a53c064a2b7dc8010e5 1.0.1 +b1bdcb4506defef0e857e2710633f7686d8034a5 1.0.2 +5559e5a4b656978c592d364f242edc62369d7e84 1.0.2 diff -r 53d7e3413337 -r 5a0a01c4c7c2 COPYING --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/COPYING Thu Sep 20 23:14:59 2012 +0200 @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff -r 53d7e3413337 -r 5a0a01c4c7c2 MANIFEST.in --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MANIFEST.in Thu Sep 20 23:14:59 2012 +0200 @@ -0,0 +1,16 @@ +recursive-include docs/figures *.svg +include docs/figures/hgview-example.png +include docs/*.rst +include docs/*.py +include docs/tutorials/*.t +include docs/makefile +include docs/static/*.svg +include hgext/__init__.py +include hgext/evolve.py +include setup.py +include README +include COPYING +include tests/*.t +include tests/*.py +exclude tests/test-oldconvert.t +exclude tests/test-qsync.t diff -r 53d7e3413337 -r 5a0a01c4c7c2 Makefile --- a/Makefile Fri Aug 24 11:49:21 2012 +0200 +++ b/Makefile Thu Sep 20 23:14:59 2012 +0200 @@ -1,5 +1,7 @@ PYTHON=python HG=`which hg` +VERSION=$(shell python setup.py --version) + help: @echo 'Commonly used make targets:' @@ -24,4 +26,13 @@ all-version-tests: tests-1.3.1 tests-1.4.3 tests-1.5.4 \ tests-1.6.4 tests-1.7.5 tests-1.8 tests-tip +deb-prepare: + python setup.py sdist --dist-dir .. + mv -f ../hg-evolve-$(VERSION).tar.gz ../mercurial-evolve_$(VERSION).orig.tar.gz + tar xf ../mercurial-evolve_$(VERSION).orig.tar.gz + rm -rf ../mercurial-evolve_$(VERSION).orig + mv hg-evolve-$(VERSION) ../mercurial-evolve_$(VERSION).orig + cp -r debian/ ../mercurial-evolve_$(VERSION).orig/ + @cd ../mercurial-evolve_$(VERSION).orig && echo 'debian build directory ready at' `pwd` + .PHONY: tests all-version-tests diff -r 53d7e3413337 -r 5a0a01c4c7c2 README --- a/README Fri Aug 24 11:49:21 2012 +0200 +++ b/README Thu Sep 20 23:14:59 2012 +0200 @@ -2,22 +2,25 @@ Mutable History For Mercurial ============================= -:obsolete: + +Extends Mercurial feature related to Changeset Evolution - Introduce an ``obsolete`` concept that tracks new versions of rewritten - changesets. +This extension provides several commands to mutate history and deal with +issues it may raise. -:evolve: +It also: - A collection of commands to rewrite the mutable part of the history. - - + - enables the "Changeset Obsolescence" feature of mercurial, + - alters core commands and extensions that rewrite history to use + this feature, + - improves some aspect of the early implementation in 2.3 **These extensions are experimental and are not meant for production.** -You can quicky enable them using:: +You can quicky enable it by adding the line below to the extensions +section of you hgrc:: - ./enable.sh >> ~/.hgrc + evolve=PATH/TO/evolve.py But it's recommended to look at the doc in the first place. @@ -43,7 +46,23 @@ Changelog ================== -1.0 + -- + +- fix troubles creation reporting from rebase + +1.0.2 -- + +- fix hg fold bug +- fix hg pull --rebase +- fix detection of conflict with external tools +- adapt to core movement (caches and --amend) + +1.0.1 -- 2012-08-31 + +- documentation improvement +- fix a performance bug with hgweb + +1.0 -- 2012-08-29 - Align with Mercurial version 2.3 (drop 2.2 support). - stabilize handle killed parent diff -r 53d7e3413337 -r 5a0a01c4c7c2 debian/changelog --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debian/changelog Thu Sep 20 23:14:59 2012 +0200 @@ -0,0 +1,18 @@ +mercurial-evolve (1.0.2-1) UNRELEASED; urgency=low + + * New upstream Release + + -- Pierre-Yves David Wed, 19 Sep 2012 17:38:47 +0200 + +mercurial-evolve (1.0.1-1) UNRELEASED; urgency=low + + * New bug fix release + * remove conflicting __init__.py + + -- Pierre-Yves David Fri, 31 Aug 2012 11:31:03 +0200 + +mercurial-evolve (1.0.0-1) UNRELEASED; urgency=low + + * Initial release. + + -- Julien Cristau Fri, 24 Aug 2012 16:46:30 +0200 diff -r 53d7e3413337 -r 5a0a01c4c7c2 debian/compat --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debian/compat Thu Sep 20 23:14:59 2012 +0200 @@ -0,0 +1,1 @@ +8 diff -r 53d7e3413337 -r 5a0a01c4c7c2 debian/control --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debian/control Thu Sep 20 23:14:59 2012 +0200 @@ -0,0 +1,40 @@ +Source: mercurial-evolve +Section: vcs +Priority: optional +Maintainer: Logilab +Uploaders: + Julien Cristau , + Pierre-Yves David , +Standards-Version: 3.9.3 +Build-Depends: + mercurial (>= 2.3~), + mercurial-common (>= 2.3~), + python, + debhelper (>= 8), + python-sphinx (>= 1.0.8), + imagemagick, + librsvg2-bin, +Python-Version: >= 2.6 +Homepage: https://bitbucket.org/marmoute/mutable-history + +Package: mercurial-evolve +Architecture: all +Depends: + ${python:Depends}, + ${misc:Depends}, + mercurial (>= 2.3~), +Description: evolve extension for Mercurial + This package provides the experimental "evolve" extension for the Mercurial + DVCS. + . + This extension provides several commands to mutate history and deal with issues + it may raise. + . + It also: + - enables the "Changeset Obsolescence" feature of mercurial, + - alters core command and extension that rewrite history to use this feature, + - improves some aspects of the early implementation in Mercurial 2.3. + . + **These extensions are experimental and are not meant for production.** + + diff -r 53d7e3413337 -r 5a0a01c4c7c2 debian/copyright --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debian/copyright Thu Sep 20 23:14:59 2012 +0200 @@ -0,0 +1,15 @@ +This software was downloaded from +https://bitbucket.org/marmoute/mutable-history + +Copyright 2011 Peter Arrenbrecht + Logilab SA + Pierre-Yves David + Patrick Mezard + + +This software may be used and distributed according to the terms of the GNU +General Public License version 2 or any later version. + +On Debian systems, the complete text of the GNU General Public License version +2 can be found in `/usr/share/common-licenses/GPL-2'. + diff -r 53d7e3413337 -r 5a0a01c4c7c2 debian/docs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debian/docs Thu Sep 20 23:14:59 2012 +0200 @@ -0,0 +1,1 @@ +html diff -r 53d7e3413337 -r 5a0a01c4c7c2 debian/rules --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debian/rules Thu Sep 20 23:14:59 2012 +0200 @@ -0,0 +1,18 @@ +#!/usr/bin/make -f + +%: + dh $@ --with python2 --buildsystem=python_distutils + +build: + dh build --with python2 --buildsystem=python_distutils + $(MAKE) -C docs + +.PHONY: build + +override_dh_auto_test: + cd tests && python run-tests.py --with-hg=`which hg` + +override_dh_python2: + # avoid conflict with mercurial's own hgext/__init__.py + find debian -name __init__.py -delete + dh_python2 diff -r 53d7e3413337 -r 5a0a01c4c7c2 docs/conf.py --- a/docs/conf.py Fri Aug 24 11:49:21 2012 +0200 +++ b/docs/conf.py Thu Sep 20 23:14:59 2012 +0200 @@ -73,17 +73,17 @@ # The name of an image file (within the static path) to place at the top of # the sidebar. -#html_logo = None +html_logo = 'logo-evolve.svg' # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. -#html_favicon = None +html_favicon = 'logo-evolve.ico' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['.static'] +html_static_path = ['static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. diff -r 53d7e3413337 -r 5a0a01c4c7c2 docs/evolve-collaboration.rst --- a/docs/evolve-collaboration.rst Fri Aug 24 11:49:21 2012 +0200 +++ b/docs/evolve-collaboration.rst Thu Sep 20 23:14:59 2012 +0200 @@ -1,3 +1,5 @@ +.. Copyright 2011 Pierre-Yves David +.. Logilab SA ------------------------------------------------ Collaboration Using Evolve: A user story diff -r 53d7e3413337 -r 5a0a01c4c7c2 docs/evolve-faq.rst --- a/docs/evolve-faq.rst Fri Aug 24 11:49:21 2012 +0200 +++ b/docs/evolve-faq.rst Thu Sep 20 23:14:59 2012 +0200 @@ -1,3 +1,5 @@ +.. Copyright 2011 Pierre-Yves David +.. Logilab SA --------------------------------------------------------------------- Evolve How To @@ -19,7 +21,7 @@ `public` changesets. To understand what the result of amend will be I use the two following -aliases [#]_:: +aliases [#]_:: # diff what amend will look likes pdiff=diff --rev .^ @@ -41,7 +43,7 @@ XXX add idank example -.. [#] (added by enable.sh) +.. [#] (defined by the evolve extension for you) @@ -88,10 +90,10 @@ .. note:: those command only exist for the convenience of getting qpush and qpop feeling back. -Collapse changesets: ``amend`` +Collapse changesets: ``fold`` ------------------------------------------------------------ -you can use amend -c to collapse multiple changeset in a single one. +you can use ``hg fold`` to collapse multiple changesets in a single one. Getting changes out of a commit ------------------------------------------------------------ @@ -152,7 +154,7 @@ .. warning:: Beware that rebasing obsolete changesets will result in conflicting versions of the changesets. -Stabilize history: ``evolve`` +Resolve history troubles: ``evolve`` ------------------------------------------------------------ When you rewrite (amend) a changeset with children without rewriting @@ -191,10 +193,14 @@ View obsolete markers ------------------------------------------------------------ -hgview is the only viewer that support this feature. You need an experimental -version available here: +hgview_ is the only viewer that currently supports this feature. You +need version 1.6.2 - $ hg clone http://hg-dev.octopoid.net/hgwebdir.cgi/hgview/ +.. _hgview: http://www.logilab.org/project/hgview/ + +.. image:: figures/hgview-example.png + :scale: 50% + You can also use a debug command diff -r 53d7e3413337 -r 5a0a01c4c7c2 docs/evolve-good-practice.rst --- a/docs/evolve-good-practice.rst Fri Aug 24 11:49:21 2012 +0200 +++ b/docs/evolve-good-practice.rst Thu Sep 20 23:14:59 2012 +0200 @@ -1,3 +1,6 @@ +.. Copyright 2011 Pierre-Yves David +.. Logilab SA + ----------------------------------------- Good pratice for (early) user of evolve ----------------------------------------- diff -r 53d7e3413337 -r 5a0a01c4c7c2 docs/figures/hgview-example.png Binary file docs/figures/hgview-example.png has changed diff -r 53d7e3413337 -r 5a0a01c4c7c2 docs/from-mq.rst --- a/docs/from-mq.rst Fri Aug 24 11:49:21 2012 +0200 +++ b/docs/from-mq.rst Thu Sep 20 23:14:59 2012 +0200 @@ -1,3 +1,6 @@ +.. Copyright 2011 Pierre-Yves David +.. Logilab SA + ------------------------------------------- From MQ To Evolve, The Refugee Book ------------------------------------------- @@ -11,11 +14,12 @@ qseries ``log`` qnew ``commit`` qrefresh ``amend`` -qpop ``update`` or ``qdown`` +qpop ``update`` or ``gdown`` qpush ``update`` or ``gup`` sometimes ``evolve`` qrm ``prune`` -qfold ``amend -c`` (for now, ``collapse`` soon) +qfold ``fold`` qdiff ``odiff`` +qrecord ``/qrecord`` qfinish -- qimport -- @@ -71,13 +75,16 @@ This command takes the same options as commit, plus the switch '-e' (--edit) to edit the commit message in an editor. -The amend command also has a -c switch which allow you to make an -explicit amending commit before rewriting a changeset.:: - $ hg record -m 'feature A' - # oups, I forget some stuff - $ hg record babar.py - $ hg amend -c .^ # .^ refer to "working directoy parent, here 'feature A' +.. -c is very confusig +.. +.. The amend command also has a -c switch which allows you to make an +.. explicit amending commit before rewriting a changeset.:: +.. +.. $ hg record -m 'feature A' +.. # oups, I forgot some stuff +.. $ hg record babar.py +.. $ hg amend -c .^ # .^ refer to "working directoy parent, here 'feature A' note: refresh is an alias for amend @@ -134,26 +141,25 @@ $ hg prune +hg qrm +``````` + +:: + + $ hg fold :: + hg qfold ````````` :: - $ hg up - $ amend --edit -c - - -or later:: - - $ hg collapse # XXX not implemented - $ hg rebase --collapse # XXX not tested - + $ hg fold first::last hg qdiff ````````` -``odiff`` is an alias for `hg diff -r .^` it works as qdiff, but outside mq. +``pdiff`` is an alias for `hg diff -r .^` it works as qdiff, but outside mq. diff -r 53d7e3413337 -r 5a0a01c4c7c2 docs/index.rst --- a/docs/index.rst Fri Aug 24 11:49:21 2012 +0200 +++ b/docs/index.rst Thu Sep 20 23:14:59 2012 +0200 @@ -1,3 +1,6 @@ +.. Copyright 2011 Pierre-Yves David +.. Logilab SA + ======================================== Safe Mutable History ======================================== @@ -61,14 +64,19 @@ * Cover all mq usage but guard. -.. warning:: The evolve extention and the obsolete marker are at an experimental - stage. While using obsolete you'll likely be exposed to complex - implication of the **obsolete marker** concept. I do not recommend - non-power user to test this at this stage. +.. warning:: The evolve extension and obsolete markers are at an experimental + stage. While using obsolete you willl likely be exposed to complex + implications of the **obsolete marker** concept. I do not recommend + non-power users to test this at this stage. - XXX make sure to read the XXX section before using it. + While numbered 1.0.0, the command line API of this version should + **not** be regarded as *stable*, command behavior, name and + options may change in future release or once integrated in + mercurial. It is still an immature extension, a lot of + features are still missing but there is no high risk of + repository corruption. - Production ready version should hide such details to normal user. + Production ready version should hide such details to normal user. The evolve extension require mercurial 2.3 @@ -130,7 +138,6 @@ obs-concept obs-terms obs-implementation - obs-road-map Known limitation and bug diff -r 53d7e3413337 -r 5a0a01c4c7c2 docs/instability.rst --- a/docs/instability.rst Fri Aug 24 11:49:21 2012 +0200 +++ b/docs/instability.rst Thu Sep 20 23:14:59 2012 +0200 @@ -1,3 +1,5 @@ +.. Copyright 2011 Pierre-Yves David +.. Logilab SA ----------------------------------- The instability Principle diff -r 53d7e3413337 -r 5a0a01c4c7c2 docs/makefile --- a/docs/makefile Fri Aug 24 11:49:21 2012 +0200 +++ b/docs/makefile Thu Sep 20 23:14:59 2012 +0200 @@ -1,6 +1,11 @@ -all: tutorial +all: tutorial static/logo-evolve.ico sphinx-build . ../html/ tutorial: python test2rst.py tutorials/ + +static/logo-evolve.ico: static/logo-evolve.svg + convert -resize 36x36 static/logo-evolve.svg static/logo-evolve.ico + + diff -r 53d7e3413337 -r 5a0a01c4c7c2 docs/obs-concept.rst --- a/docs/obs-concept.rst Fri Aug 24 11:49:21 2012 +0200 +++ b/docs/obs-concept.rst Thu Sep 20 23:14:59 2012 +0200 @@ -1,3 +1,6 @@ +.. Copyright 2011 Pierre-Yves David +.. Logilab SA + ----------------------------------------------------------- Why Do We Need a New Concept ----------------------------------------------------------- diff -r 53d7e3413337 -r 5a0a01c4c7c2 docs/obs-implementation.rst --- a/docs/obs-implementation.rst Fri Aug 24 11:49:21 2012 +0200 +++ b/docs/obs-implementation.rst Thu Sep 20 23:14:59 2012 +0200 @@ -1,3 +1,5 @@ +.. Copyright 2011 Pierre-Yves David +.. Logilab SA ----------------------------------------------------- Implementation of Obsolete Marker @@ -8,100 +10,6 @@ ----------------------------------------------------- -What data should be contained in a Marker ? -```````````````````````````````````````````````````` - -There are two critical pieces of information that **must** be stored -in an obsolete Marker. - -:object: - the old obsoleted changeset - -:replacements: - list of new changeset. list size can be anything, including 0 (0..N) - -Everybody agreed on this point. - - --- - -This is probably a good idea to have an unique Identifier, for UI, transfer and -access. - - :id: same as changeset but for marker. - -The field below will depend on the way we exchange obsolete marker between -changesets. - - --- - -Having audit data will be very useful. When it gets messy you need all the -information available to understand the situation. - -I have the feeling that we are versioning history. Therefor we will probably -need the same kind of information than when versioning Files. - -:date: date of the marker creation - -:user: ui.username - -To go further: - -:description: "Optional reason for the rewrite (generated by the user)" - -:tool: the automated tool that made this - -:operation: Kind of rewritting operation that created the marker (delete, - update, split, fold, reordering), to help conflict resolution. - -Matt said this is "too complicated". I'll wait for him to meet a very hairy -situation to agree that they are needed. - -Leaving the door open to any addition data is an option too. - -How shall we store Marker on disk -````````````````````````````````````````````````````````` - -Requirement -............. - -We need to quickly load the 'object' to know the "obsolete" set. -We need quick access by object and replacements to travels along the graph. - -Common Part -............. - -The file is store in `.hg/store/obsmarkers`. It is a binary files: - -The files starts with a Format Version string - - -Minimalistic proposal -......................... - -The core of a Marker will we stored as: - -* number of replacement (8-Bytes integer) -* node id of the obsolete changeset (20-Bytes hash) -* node id of replacement changeset (20-Bytes hash x number of remplacement) - -Version with ID -......................... - -This version add a node id computed from the marker content. It will be present -*before* other data: - -* node id of the maker (20-Bytes hash) - - -Version with Metadata proposal -............................... - -An extra files is used to old metadata (date, user, etc) `.hg/store/obs-extra`:. - -The format of this field is undefined yet. This will add the following -field at the end of a marker - -* offset of the metadata in obs-extra (8-Bytes integer) How shall we exchange Marker over the Wire ? @@ -188,26 +96,11 @@ Current status ----------------------------------------------------- -An experimental implementatione exists. What have been done so far. - - -* 1-1 obsolete marker stored outside history, +Obsolete marker are partialy in core. -* compute obsolete-tip - -* obsolete marker exchange through pushkey, - -* compute obsolete, unstable, extinct and suspended set. +2.3: -* hidden extinct changesets for UI. - -* Use secret phase to remove from discovery obsolete and unstable changesets (to - be improved soon) - -* alter rebase to use obsolete markers instead of stripping. - -* Have an experimental mq-like extension to rewrite history (more on that later) - -* Have an extension to update and mq repository according evolution of - standard (more on that later) - +- storage over obsolete marker +- exchange suing pushkey +- extinct changeset are properly hidden +- extinct changeset are excluded from exchange diff -r 53d7e3413337 -r 5a0a01c4c7c2 docs/obs-terms.rst --- a/docs/obs-terms.rst Fri Aug 24 11:49:21 2012 +0200 +++ b/docs/obs-terms.rst Thu Sep 20 23:14:59 2012 +0200 @@ -1,3 +1,6 @@ +.. Copyright 2011 Pierre-Yves David +.. Logilab SA + ----------------------------------------------------------- Terminology of the obsolete concept ----------------------------------------------------------- @@ -48,7 +51,7 @@ **newest successors**.. .. note:: I'm not very happy with this naming scheme and I'm looking for a - better distinction between *direct successors* and **any successors*. + better distinction between *direct successors* and **any successors**. Possible changesets "type" --------------------------------- diff -r 53d7e3413337 -r 5a0a01c4c7c2 docs/qsync.rst --- a/docs/qsync.rst Fri Aug 24 11:49:21 2012 +0200 +++ b/docs/qsync.rst Thu Sep 20 23:14:59 2012 +0200 @@ -1,3 +1,6 @@ +.. Copyright 2011 Pierre-Yves David +.. Logilab SA + --------------------------------------------------------------------- Qsync: Mercurial to MQ exporter --------------------------------------------------------------------- diff -r 53d7e3413337 -r 5a0a01c4c7c2 docs/static/logo-evolve.svg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/static/logo-evolve.svg Thu Sep 20 23:14:59 2012 +0200 @@ -0,0 +1,622 @@ + + + +image/svg+xmlCali Mastny and Matt MackallFeb 12 2008 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +evolve + \ No newline at end of file diff -r 53d7e3413337 -r 5a0a01c4c7c2 docs/test2rst.py --- a/docs/test2rst.py Fri Aug 24 11:49:21 2012 +0200 +++ b/docs/test2rst.py Thu Sep 20 23:14:59 2012 +0200 @@ -27,7 +27,7 @@ if os.path.isdir(base): one_dir(base) else: - print one_file(base) + one_file(base) def one_dir(base): @@ -37,14 +37,12 @@ for fn in sorted(os.listdir(base)): if not fn.endswith('.t'): continue - print fn name = os.path.splitext(fn)[0] content = one_file(op.join(base, fn)) target = op.join(base, name + '.rst') #with file(doc(name + '.rst'), 'w') as f: with file(target, 'w') as f: f.write(content) - print f index += '\n ' + name diff -r 53d7e3413337 -r 5a0a01c4c7c2 docs/tutorials/tutorial.t --- a/docs/tutorials/tutorial.t Fri Aug 24 11:49:21 2012 +0200 +++ b/docs/tutorials/tutorial.t Thu Sep 20 23:14:59 2012 +0200 @@ -400,7 +400,7 @@ for simplicity shake we get the bathroom change in line again - $ hg rebase -Dr 8d39a843582d -d a2fccc2e7b08 + $ hg rebase -r 8d39a843582d -d a2fccc2e7b08 merging shopping $ hg phase --draft . $ hg log -G @@ -624,11 +624,11 @@ $ hg stabilize --dry-run move:[15] animals atop:[14] bathroom stuff - hg rebase -Dr 9ac5d0e790a2 -d ffa278c50818 + hg rebase -r 9ac5d0e790a2 -d ffa278c50818 Let's do it - $ hg rebase -Dr 9ac5d0e790a2 -d ffa278c50818 + $ hg rebase -r 9ac5d0e790a2 -d ffa278c50818 merging shopping The old version of bathroom is hidden again. diff -r 53d7e3413337 -r 5a0a01c4c7c2 hgext/__init__.py --- a/hgext/__init__.py Fri Aug 24 11:49:21 2012 +0200 +++ b/hgext/__init__.py Thu Sep 20 23:14:59 2012 +0200 @@ -1,1 +1,1 @@ -#f00 +# Copyright 2011 Logilab SA diff -r 53d7e3413337 -r 5a0a01c4c7c2 hgext/evolve.py --- a/hgext/evolve.py Fri Aug 24 11:49:21 2012 +0200 +++ b/hgext/evolve.py Thu Sep 20 23:14:59 2012 +0200 @@ -1,21 +1,22 @@ -# states.py - introduce the state concept for mercurial changeset -# # Copyright 2011 Peter Arrenbrecht # Logilab SA # Pierre-Yves David +# Patrick Mezard # # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. '''Extends Mercurial feature related to Changeset Evolution -This extension Provide several command tommutate history and deal with issue it may raise. +This extension provides several commands to mutate history and deal with +issues it may raise. It also: - - enable the "Changeset Obsolescence" feature of mercurial, - - alter core command and extension that rewrite history to use this feature, - - improve some aspect of the early implementation in 2.3 + - enables the "Changeset Obsolescence" feature of mercurial, + - alters core commands and extensions that rewrite history to use + this feature, + - improves some aspect of the early implementation in 2.3 ''' import random @@ -39,6 +40,7 @@ from mercurial import extensions from mercurial import hg from mercurial import localrepo +from mercurial import lock as lockmod from mercurial import merge from mercurial import node from mercurial import phases @@ -49,6 +51,8 @@ from mercurial.commands import walkopts, commitopts, commitopts2 from mercurial.node import nullid +import mercurial.hgweb.hgweb_mod + # This extension contains the following code @@ -294,15 +298,17 @@ ### Obsolescence Caching Logic ### ##################################################################### +# IN CORE fb72eec7efd8 + # Obsolescence related logic can be very slow if we don't have efficient cache. # # This section implements a cache mechanism that did not make it into core for -# time reason. It store meaningful set of revision related to obsolescence -# (obsolete, unstabletble ... +# time reason. It stores meaningful set of revisions related to obsolescence +# (obsolete, unstable, etc.) # # Here is: # -# - Computation of meaningful set, +# - Computation of meaningful sets # - Cache access logic, # - Cache invalidation logic, # - revset and ctx using this cache. @@ -317,58 +323,65 @@ #: function take a single "repo" argument. #: #: Use the `cachefor` decorator to register new cache function -cachefuncs = {} -def cachefor(name): - """Decorator to register a function as computing the cache for a set""" - def decorator(func): - assert name not in cachefuncs - cachefuncs[name] = func - return func - return decorator +try: + cachefuncs = obsolete.cachefuncs + cachefor = obsolete.cachefor + getobscache = obsolete.getobscache + clearobscaches = obsolete.clearobscaches +except AttributeError: + cachefuncs = {} -@cachefor('obsolete') -def _computeobsoleteset(repo): - """the set of obsolete revisions""" - obs = set() - nm = repo.changelog.nodemap - for prec in repo.obsstore.precursors: - rev = nm.get(prec) - if rev is not None: - obs.add(rev) - return set(repo.revs('%ld - public()', obs)) + def cachefor(name): + """Decorator to register a function as computing the cache for a set""" + def decorator(func): + assert name not in cachefuncs + cachefuncs[name] = func + return func + return decorator -@cachefor('unstable') -def _computeunstableset(repo): - """the set of non obsolete revisions with obsolete parents""" - return set(repo.revs('(obsolete()::) - obsolete()')) + @cachefor('obsolete') + def _computeobsoleteset(repo): + """the set of obsolete revisions""" + obs = set() + nm = repo.changelog.nodemap + for prec in repo.obsstore.precursors: + rev = nm.get(prec) + if rev is not None: + obs.add(rev) + return set(repo.revs('%ld - public()', obs)) -@cachefor('suspended') -def _computesuspendedset(repo): - """the set of obsolete parents with non obsolete descendants""" - return set(repo.revs('obsolete() and obsolete()::unstable()')) + @cachefor('unstable') + def _computeunstableset(repo): + """the set of non obsolete revisions with obsolete parents""" + return set(repo.revs('(obsolete()::) - obsolete()')) -@cachefor('extinct') -def _computeextinctset(repo): - """the set of obsolete parents without non obsolete descendants""" - return set(repo.revs('obsolete() - obsolete()::unstable()')) + @cachefor('suspended') + def _computesuspendedset(repo): + """the set of obsolete parents with non obsolete descendants""" + return set(repo.revs('obsolete() and obsolete()::unstable()')) -@eh.wrapfunction(obsolete.obsstore, '__init__') -def _initobsstorecache(orig, obsstore, *args, **kwargs): - """add a cache attribute to obsstore""" - obsstore.caches = {} - return orig(obsstore, *args, **kwargs) + @cachefor('extinct') + def _computeextinctset(repo): + """the set of obsolete parents without non obsolete descendants""" + return set(repo.revs('obsolete() - obsolete()::unstable()')) + + @eh.wrapfunction(obsolete.obsstore, '__init__') + def _initobsstorecache(orig, obsstore, *args, **kwargs): + """add a cache attribute to obsstore""" + obsstore.caches = {} + return orig(obsstore, *args, **kwargs) ### Cache access -def getobscache(repo, name): - """Return the set of revision that belong to the set + def getobscache(repo, name): + """Return the set of revision that belong to the set - Such access may compute the set and cache it for future use""" - if not repo.obsstore: - return () - if name not in repo.obsstore.caches: - repo.obsstore.caches[name] = cachefuncs[name](repo) - return repo.obsstore.caches[name] + Such access may compute the set and cache it for future use""" + if not repo.obsstore: + return () + if name not in repo.obsstore.caches: + repo.obsstore.caches[name] = cachefuncs[name](repo) + return repo.obsstore.caches[name] ### Cache clean up # @@ -380,85 +393,85 @@ # - strip is used a repo -def clearobscaches(repo): - """Remove all obsolescence related cache from a repo + def clearobscaches(repo): + """Remove all obsolescence related cache from a repo - This remove all cache in obsstore is the obsstore already exist on the - repo. + This remove all cache in obsstore is the obsstore already exist on the + repo. - (We could be smarter here)""" - if 'obsstore' in repo._filecache: - repo.obsstore.caches.clear() + (We could be smarter here)""" + if 'obsstore' in repo._filecache: + repo.obsstore.caches.clear() -@eh.wrapfunction(localrepo.localrepository, 'addchangegroup') # new changeset -@eh.wrapfunction(phases, 'retractboundary') # phase movement -@eh.wrapfunction(phases, 'advanceboundary') # phase movement -@eh.wrapfunction(localrepo.localrepository, 'destroyed') # strip -def wrapclearcache(orig, repo, *args, **kwargs): - try: - return orig(repo, *args, **kwargs) - finally: - # we are a bit wide here - # we could restrict to: - # advanceboundary + phase==public - # retractboundary + phase==draft - clearobscaches(repo) + @eh.wrapfunction(localrepo.localrepository, 'addchangegroup') # new changeset + @eh.wrapfunction(phases, 'retractboundary') # phase movement + @eh.wrapfunction(phases, 'advanceboundary') # phase movement + @eh.wrapfunction(localrepo.localrepository, 'destroyed') # strip + def wrapclearcache(orig, repo, *args, **kwargs): + try: + return orig(repo, *args, **kwargs) + finally: + # we are a bit wide here + # we could restrict to: + # advanceboundary + phase==public + # retractboundary + phase==draft + clearobscaches(repo) -@eh.wrapfunction(obsolete.obsstore, 'add') # new marker -def clearonadd(orig, obsstore, *args, **kwargs): - try: - return orig(obsstore, *args, **kwargs) - finally: - obsstore.caches.clear() + @eh.wrapfunction(obsolete.obsstore, 'add') # new marker + def clearonadd(orig, obsstore, *args, **kwargs): + try: + return orig(obsstore, *args, **kwargs) + finally: + obsstore.caches.clear() ### Use the case # Function in core that could benefic from the cache are overwritten by cache using version # changectx method -@eh.addattr(context.changectx, 'unstable') -def unstable(ctx): - """is the changeset unstable (have obsolete ancestor)""" - if ctx.node() is None: - return False - return ctx.rev() in getobscache(ctx._repo, 'unstable') + @eh.addattr(context.changectx, 'unstable') + def unstable(ctx): + """is the changeset unstable (have obsolete ancestor)""" + if ctx.node() is None: + return False + return ctx.rev() in getobscache(ctx._repo, 'unstable') -@eh.addattr(context.changectx, 'extinct') -def extinct(ctx): - """is the changeset extinct by other""" - if ctx.node() is None: - return False - return ctx.rev() in getobscache(ctx._repo, 'extinct') + @eh.addattr(context.changectx, 'extinct') + def extinct(ctx): + """is the changeset extinct by other""" + if ctx.node() is None: + return False + return ctx.rev() in getobscache(ctx._repo, 'extinct') # revset -@eh.revset('obsolete') -def revsetobsolete(repo, subset, x): - """``obsolete()`` - Changeset is obsolete. - """ - args = revset.getargs(x, 0, 0, 'obsolete takes no argument') - obsoletes = getobscache(repo, 'obsolete') - return [r for r in subset if r in obsoletes] + @eh.revset('obsolete') + def revsetobsolete(repo, subset, x): + """``obsolete()`` + Changeset is obsolete. + """ + args = revset.getargs(x, 0, 0, 'obsolete takes no argument') + obsoletes = getobscache(repo, 'obsolete') + return [r for r in subset if r in obsoletes] -@eh.revset('unstable') -def revsetunstable(repo, subset, x): - """``unstable()`` - Unstable changesets are non-obsolete with obsolete ancestors. - """ - args = revset.getargs(x, 0, 0, 'unstable takes no arguments') - unstables = getobscache(repo, 'unstable') - return [r for r in subset if r in unstables] + @eh.revset('unstable') + def revsetunstable(repo, subset, x): + """``unstable()`` + Unstable changesets are non-obsolete with obsolete ancestors. + """ + args = revset.getargs(x, 0, 0, 'unstable takes no arguments') + unstables = getobscache(repo, 'unstable') + return [r for r in subset if r in unstables] -@eh.revset('extinct') -def revsetextinct(repo, subset, x): - """``extinct()`` - Obsolete changesets with obsolete descendants only. - """ - args = revset.getargs(x, 0, 0, 'extinct takes no arguments') - extincts = getobscache(repo, 'extinct') - return [r for r in subset if r in extincts] + @eh.revset('extinct') + def revsetextinct(repo, subset, x): + """``extinct()`` + Obsolete changesets with obsolete descendants only. + """ + args = revset.getargs(x, 0, 0, 'extinct takes no arguments') + extincts = getobscache(repo, 'extinct') + return [r for r in subset if r in extincts] ##################################################################### ### Complete troubles computation logic ### @@ -564,7 +577,7 @@ return orig(repo, remote, outgoing, *args, **kwargs) ##################################################################### -### Filter extinct changeset from common operation ### +### Filter extinct changesets from common operations ### ##################################################################### @eh.wrapfunction(merge, 'update') @@ -579,6 +592,8 @@ @eh.wrapfunction(localrepo.localrepository, 'branchtip') def obsbranchtip(orig, repo, branch): """ensure "stable" reference does not end on a hidden changeset""" + if not getattr(repo, '_dofilterbranchtip', True): + return orig(repo, branch) result = () heads = repo.branchmap().get(branch, ()) if heads: @@ -588,6 +603,13 @@ return result[0].node() +@eh.wrapfunction(mercurial.hgweb.hgweb_mod.hgweb, '__init__') +@eh.wrapfunction(mercurial.hgweb.hgweb_mod.hgweb, 'refresh') +def nofilter(orig, hgweb, *args, **kwargs): + orig(hgweb, *args, **kwargs) + hgweb.repo._dofilterbranchtip = False + + ##################################################################### ### Additional Utilities ### ##################################################################### @@ -601,40 +623,43 @@ # - function to find useful changeset to stabilize ### Marker Create - -def createmarkers(repo, relations, metadata=None, flag=0): - """Add obsolete markers between changeset in a repo +# NOW IN CORE f85816af6294 +try: + createmarkers = obsolete.createmarkers +except AttributeError: + def createmarkers(repo, relations, metadata=None, flag=0): + """Add obsolete markers between changeset in a repo - must be an iterable of (, (, ...)) tuple. - `old` and `news` are changectx. + must be an iterable of (, (, ...)) tuple. + `old` and `news` are changectx. - Current user and date are used except if specified otherwise in the - metadata attribute. + Current user and date are used except if specified otherwise in the + metadata attribute. - /!\ assume the repo have been locked by the user /!\ - """ - # prepare metadata - if metadata is None: - metadata = {} - if 'date' not in metadata: - metadata['date'] = '%i %i' % util.makedate() - if 'user' not in metadata: - metadata['user'] = repo.ui.username() - # check future marker - tr = repo.transaction('add-obsolescence-marker') - try: - for prec, sucs in relations: - if not prec.mutable(): - raise util.Abort("Cannot obsolete immutable changeset: %s" % prec) - nprec = prec.node() - nsucs = tuple(s.node() for s in sucs) - if nprec in nsucs: - raise util.Abort("Changeset %s cannot obsolete himself" % prec) - repo.obsstore.create(tr, nprec, nsucs, flag, metadata) - clearobscaches(repo) - tr.close() - finally: - tr.release() + /!\ assume the repo have been locked by the user /!\ + """ + # prepare metadata + if metadata is None: + metadata = {} + if 'date' not in metadata: + metadata['date'] = '%i %i' % util.makedate() + if 'user' not in metadata: + metadata['user'] = repo.ui.username() + # check future marker + tr = repo.transaction('add-obsolescence-marker') + try: + for prec, sucs in relations: + if not prec.mutable(): + raise util.Abort("cannot obsolete immutable changeset: %s" % prec) + nprec = prec.node() + nsucs = tuple(s.node() for s in sucs) + if nprec in nsucs: + raise util.Abort("changeset %s cannot obsolete himself" % prec) + repo.obsstore.create(tr, nprec, nsucs, flag, metadata) + clearobscaches(repo) + tr.close() + finally: + tr.release() ### Useful alias @@ -675,8 +700,8 @@ Changesets with troubles. """ _ = revset.getargs(x, 0, 0, 'troubled takes no arguments') - return list(repo.revs('%ld and (unstable() + latecomer() + conflicting())', - subset)) + return repo.revs('%ld and (unstable() + latecomer() + conflicting())', + subset) ### Obsolescence graph @@ -787,15 +812,16 @@ # this section add several useful revset symbol not yet in core. # they are subject to changes -### hidden revset is not in core yet -@eh.revset('hidden') -def revsethidden(repo, subset, x): - """``hidden()`` - Changeset is hidden. - """ - args = revset.getargs(x, 0, 0, 'hidden takes no argument') - return [r for r in subset if r in repo.hiddenrevs] +if 'hidden' not in revset.symbols: + # in 2.3+ + @eh.revset('hidden') + def revsethidden(repo, subset, x): + """``hidden()`` + Changeset is hidden. + """ + args = revset.getargs(x, 0, 0, 'hidden takes no argument') + return [r for r in subset if r in repo.hiddenrevs] ### XXX I'm not sure this revset is useful @eh.revset('suspended') @@ -893,6 +919,8 @@ priorlatecomers = len(repo.revs('latecomer()')) priorconflictings = len(repo.revs('conflicting()')) ret = orig(ui, repo, *args, **kwargs) + # workaround phase stupidity + phases._filterunknown(ui, repo.changelog, repo._phasecache.phaseroots) newunstables = len(repo.revs('unstable()')) - priorunstables newlatecomers = len(repo.revs('latecomer()')) - priorlatecomers newconflictings = len(repo.revs('conflicting()')) - priorconflictings @@ -931,22 +959,20 @@ @eh.wrapcommand("summary") def obssummary(orig, ui, repo, *args, **kwargs): + def write(fmt, count): + s = fmt % count + if count: + ui.write(s) + else: + ui.note(s) + ret = orig(ui, repo, *args, **kwargs) nbunstable = len(getobscache(repo, 'unstable')) nblatecomer = len(getobscache(repo, 'latecomer')) nbconflicting = len(getobscache(repo, 'unstable')) - if nbunstable: - ui.write('unstable: %i changesets\n' % nbunstable) - else: - ui.note('unstable: 0 changesets\n') - if nblatecomer: - ui.write('latecomer: %i changesets\n' % nblatecomer) - else: - ui.note('latecomer: 0 changesets\n') - if nbconflicting: - ui.write('conflicting: %i changesets\n' % nbconflicting) - else: - ui.note('conflicting: 0 changesets\n') + write('unstable: %i changesets\n', nbunstable) + write('latecomer: %i changesets\n', nblatecomer) + write('conflicting: %i changesets\n', nbconflicting) return ret @@ -962,27 +988,30 @@ # # The precursor is still strip from the repository. -@eh.wrapfunction(cmdutil, 'amend') -def wrapcmdutilamend(orig, ui, repo, commitfunc, old, *args, **kwargs): - oldnode = old.node() - new = orig(ui, repo, commitfunc, old, *args, **kwargs) - if new != oldnode: - lock = repo.lock() - try: - tr = repo.transaction('post-amend-obst') +# IN CORE 63e45aee46d4 + +if getattr(cmdutil, 'obsolete', None) is None: + @eh.wrapfunction(cmdutil, 'amend') + def wrapcmdutilamend(orig, ui, repo, commitfunc, old, *args, **kwargs): + oldnode = old.node() + new = orig(ui, repo, commitfunc, old, *args, **kwargs) + if new != oldnode: + lock = repo.lock() try: - meta = { - 'date': '%i %i' % util.makedate(), - 'user': ui.username(), - } - repo.obsstore.create(tr, oldnode, [new], 0, meta) - tr.close() - clearobscaches(repo) + tr = repo.transaction('post-amend-obst') + try: + meta = { + 'date': '%i %i' % util.makedate(), + 'user': ui.username(), + } + repo.obsstore.create(tr, oldnode, [new], 0, meta) + tr.close() + clearobscaches(repo) + finally: + tr.release() finally: - tr.release() - finally: - lock.release() - return new + lock.release() + return new ### rebase # @@ -997,7 +1026,8 @@ repo.ui.warn(_('whole rebase set is extinct and ignored.\n')) return {} root = min(rebaseset) - if not repo._rebasekeep and not repo[root].mutable(): + if (not getattr(repo, '_rebasekeep', False) + and not repo[root].mutable()): raise util.Abort(_("can't rebase immutable changeset %s") % repo[root], hint=_('see hg help phases for details')) return orig(repo, dest, rebaseset, *ags, **kws) @@ -1085,11 +1115,14 @@ try: rebase = extensions.find('rebase') if rebase: - entry = extensions.wrapcommand(rebase.cmdtable, 'rebase', warnobserrors) - extensions.wrapfunction(rebase, 'buildstate', buildstate) - extensions.wrapfunction(rebase, 'defineparents', defineparents) - extensions.wrapfunction(rebase, 'concludenode', concludenode) - extensions.wrapcommand(rebase.cmdtable, "rebase", cmdrebase) + incore = getattr(rebase, 'obsolete', None) is not None + if not incore: + extensions.wrapcommand(rebase.cmdtable, "rebase", cmdrebase) + extensions.wrapcommand(rebase.cmdtable, 'rebase', warnobserrors) + if not incore: + extensions.wrapfunction(rebase, 'buildstate', buildstate) + extensions.wrapfunction(rebase, 'defineparents', defineparents) + extensions.wrapfunction(rebase, 'concludenode', concludenode) except KeyError: pass # rebase not found @@ -1219,15 +1252,18 @@ cmdutil.duplicatecopies(repo, orig.node(), dest.node()) nodesrc = orig.node() destphase = repo[nodesrc].phase() - if rebase.rebasenode.func_code.co_argcount == 5: - # rebasenode collapse argument was introduced by - # d1afbf03e69a (2.3) - rebase.rebasenode(repo, orig.node(), dest.node(), - {node.nullrev: node.nullrev}, False) - else: - rebase.rebasenode(repo, orig.node(), dest.node(), - {node.nullrev: node.nullrev}) try: + if rebase.rebasenode.func_code.co_argcount == 5: + # rebasenode collapse argument was introduced by + # d1afbf03e69a (2.3) + r = rebase.rebasenode(repo, orig.node(), dest.node(), + {node.nullrev: node.nullrev}, False) + else: + r = rebase.rebasenode(repo, orig.node(), dest.node(), + {node.nullrev: node.nullrev}) + if r[-1]: #some conflict + raise util.Abort( + 'unresolved merge conflicts (see hg help resolve)') nodenew = rebase.concludenode(repo, orig.node(), dest.node(), node.nullid) except util.Abort, exc: @@ -1256,25 +1292,6 @@ repo.dirstate.invalidate() raise -def _stabilizableunstable(repo, pctx): - """Return a changectx for an unstable changeset which can be - stabilized on top of pctx or one of its descendants. None if none - can be found. - """ - def selfanddescendants(repo, pctx): - yield pctx - for ctx in pctx.descendants(): - yield ctx - - # Look for an unstable which can be stabilized as a child of - # node. The unstable must be a child of one of node predecessors. - for ctx in selfanddescendants(repo, pctx): - unstables = list(repo.set('unstable() and children(allprecursors(%d))', - ctx.rev())) - if unstables: - return unstables[0] - return None - def _bookmarksupdater(repo, oldid): """Return a callable update(newid) updating the current bookmark and bookmarks bound to oldid to newid. @@ -1335,9 +1352,9 @@ graftcmd = commands.table['graft'][0] return graftcmd(ui, repo, old_obsolete=True, **{'continue': True}) - troubled = list(repo.revs('troubled()')) tr = _picknexttroubled(ui, repo, anyopt) if tr is None: + troubled = repo.revs('troubled()') if troubled: ui.write_err(_('nothing to evolve here\n')) ui.status(_('(%i troubled changesets, do you want --any ?)\n') @@ -1357,14 +1374,14 @@ else: assert False # WHAT? unknown troubles -def _picknexttroubled(ui, repo, any=False): +def _picknexttroubled(ui, repo, pickany=False): """Pick a the next trouble changeset to solve""" tr = _stabilizableunstable(repo, repo['.']) if tr is None: wdp = repo['.'] if 'conflicting' in wdp.troubles(): tr = wdp - if tr is None and any: + if tr is None and pickany: troubled = list(repo.set('unstable()')) if not troubled: troubled = list(repo.set('latecomer()')) @@ -1375,6 +1392,24 @@ return tr +def _stabilizableunstable(repo, pctx): + """Return a changectx for an unstable changeset which can be + stabilized on top of pctx or one of its descendants. None if none + can be found. + """ + def selfanddescendants(repo, pctx): + yield pctx + for ctx in pctx.descendants(): + yield ctx + + # Look for an unstable which can be stabilized as a child of + # node. The unstable must be a child of one of node predecessors. + for ctx in selfanddescendants(repo, pctx): + unstables = list(repo.set('unstable() and children(allprecursors(%d))', + ctx.rev())) + if unstables: + return unstables[0] + return None def _solveunstable(ui, repo, orig, dryrun=False): """Stabilize a unstable changeset""" @@ -1386,7 +1421,7 @@ # search of a parent which is not killed while newer == [()]: ui.debug("stabilize target %s is plain dead," - " trying to stabilize on it's parent") + " trying to stabilize on its parent") obs = obs.parents()[0] newer = newerversion(repo, obs.node()) if len(newer) > 1: @@ -1406,7 +1441,7 @@ repo.ui.status(_('atop:')) if not ui.quiet: displayer.show(target) - todo = 'hg rebase -Dr %s -d %s\n' % (orig, target) + todo = 'hg rebase -r %s -d %s\n' % (orig, target) if dryrun: repo.ui.write(todo) else: @@ -1442,7 +1477,7 @@ if not ui.quiet: displayer.show(prec) if dryrun: - todo = 'hg rebase --rev %s --detach %s;\n' % (latecomer, prec.p1()) + todo = 'hg rebase --rev %s --dest %s;\n' % (latecomer, prec.p1()) repo.ui.write(todo) repo.ui.write('hg update %s;\n' % prec) repo.ui.write('hg revert --all --rev %s;\n' % latecomer) @@ -1534,7 +1569,7 @@ if len(other.parents()) > 1: raise util.Abort("conflicting changeset can't be a merge (yet)") if other.p1() not in conflicting.parents(): - raise util.Abort("parent are not common (not handled yet)") + raise util.Abort("parents are not common (not handled yet)") displayer = cmdutil.show_changeset(ui, repo, {'template': shorttemplate}) ui.status(_('merge:')) @@ -1548,56 +1583,59 @@ displayer.show(base) if dryrun: ui.write('hg update -c %s &&\n' % conflicting) - ui.write('hg merge %s && \n' % other) - ui.write('hg commit -m "auto merge resolving conflict between %s and %s"&&\n' - % (conflicting, other)) + ui.write('hg merge %s &&\n' % other) + ui.write('hg commit -m "auto merge resolving conflict between ' + '%s and %s"&&\n' % (conflicting, other)) ui.write('hg up -C %s &&\n' % base) ui.write('hg revert --all --rev tip &&\n') - ui.write('hg commit -m "`hg log -r %s --template={desc}`";\n' % conflicting) + ui.write('hg commit -m "`hg log -r %s --template={desc}`";\n' + % conflicting) return - #oldphase = max(conflicting.phase(), other.phase()) - wlock = repo.wlock() + wlock = lock = None try: + wlock = repo.wlock() lock = repo.lock() + if conflicting not in repo[None].parents(): + repo.ui.status(_('updating to "local" conflict\n')) + hg.update(repo, conflicting.rev()) + repo.ui.note(_('merging conflicting changeset\n')) + stats = merge.update(repo, + other.node(), + branchmerge=True, + force=False, + partial=None, + ancestor=base.node(), + mergeancestor=True) + hg._showstats(repo, stats) + if stats[3]: + repo.ui.status(_("use 'hg resolve' to retry unresolved file merges " + "or 'hg update -C .' to abandon\n")) + if stats[3] > 0: + raise util.Abort('Merge conflict between several amendments, and this is not yet automated', + hint="""/!\ You can try: +/!\ * manual merge + resolve => new cset X +/!\ * hg up to the parent of the amended changeset (which are named W and Z) +/!\ * hg revert --all -r X +/!\ * hg ci -m "same message as the amended changeset" => new cset Y +/!\ * hg kill -n Y W Z +""") + tr = repo.transaction('stabilize-conflicting') try: - if conflicting not in repo[None].parents(): - repo.ui.status(_('updating to "local" conflict\n')) - hg.update(repo, conflicting.rev()) - repo.ui.note(_('merging conflicting changeset\n')) - stats = merge.update(repo, - other.node(), - branchmerge=True, - force=False, - partial=None, - ancestor=base.node(), - mergeancestor=True) - hg._showstats(repo, stats) - if stats[3]: - repo.ui.status(_("use 'hg resolve' to retry unresolved file merges " - "or 'hg update -C .' to abandon\n")) - #repo.dirstate.write() - if stats[3] > 0: - raise util.Abort('GASP! Merge Conflict! You are on you own chap!', - hint='/!\\ hg evolve --continue will NOT work /!\\') - tr = repo.transaction('stabilize-conflicting') - try: - repo.dirstate.setparents(conflicting.node(), node.nullid) - oldlen = len(repo) - amend(ui, repo) - if oldlen == len(repo): - new = conflicting - # no changes - else: - new = repo['.'] - createmarkers(repo, [(other, (new,))]) - phases.retractboundary(repo, other.phase(), [new.node()]) - tr.close() - finally: - tr.release() + repo.dirstate.setparents(conflicting.node(), node.nullid) + oldlen = len(repo) + amend(ui, repo) + if oldlen == len(repo): + new = conflicting + # no changes + else: + new = repo['.'] + createmarkers(repo, [(other, (new,))]) + phases.retractboundary(repo, other.phase(), [new.node()]) + tr.close() finally: - lock.release() + tr.release() finally: - wlock.release() + lockmod.release(lock, wlock) def conflictingdata(ctx): @@ -1687,6 +1725,8 @@ try: new = set(noderange(repo, opts['new'])) targetnodes = set(noderange(repo, revs)) + if not targetnodes: + raise util.Abort('nothing to prune') if new: sucs = tuple(repo[n] for n in new) else: @@ -1983,8 +2023,9 @@ _('[-r] revs')) def touch(ui, repo, *revs, **opts): """Create successors with exact same property but hash - - This is used to "resurect" changeset""" + + This is used to "resurrect" changesets + """ revs = list(revs) revs.extend(opts['rev']) if not revs: @@ -1995,80 +2036,75 @@ return 1 if repo.revs('public() and %ld', revs): raise util.Abort("can't touch public revision") - wlock = repo.wlock() + wlock = lock = None try: + wlock = repo.wlock() lock = repo.lock() + tr = repo.transaction('touch') try: - tr = repo.transaction('touch') - try: - for r in revs: - ctx = repo[r] - extra = ctx.extra().copy() - extra['__touch-noise__'] = random.randint(0, 0xffffffff) - new, _ = rewrite(repo, ctx, [], ctx, - [ctx.p1().node(), ctx.p2().node()], - commitopts={'extra': extra}) - createmarkers(repo, [(ctx, (repo[new],))]) - phases.retractboundary(repo, ctx.phase(), [new]) - if ctx in repo[None].parents(): - repo.dirstate.setparents(new, node.nullid) - tr.close() - finally: - tr.release() + for r in revs: + ctx = repo[r] + extra = ctx.extra().copy() + extra['__touch-noise__'] = random.randint(0, 0xffffffff) + new, _ = rewrite(repo, ctx, [], ctx, + [ctx.p1().node(), ctx.p2().node()], + commitopts={'extra': extra}) + createmarkers(repo, [(ctx, (repo[new],))]) + phases.retractboundary(repo, ctx.phase(), [new]) + if ctx in repo[None].parents(): + repo.dirstate.setparents(new, node.nullid) + tr.close() finally: - lock.release() + tr.release() finally: - wlock.release() + lockmod.release(lock, wlock) @command('^fold', - [('r', 'rev', [], 'revision to fold'),], + [('r', 'rev', [], 'revisions to fold'),], # allow to choose the seed ? _('[-r] revs')) def fold(ui, repo, *revs, **opts): - """Fold multiple revision into a single one""" + """Fold multiple revisions into a single one""" revs = list(revs) revs.extend(opts['rev']) - if not revs: - revs = ['.'] - revs = scmutil.revrange(repo, revs) + if revs: + revs = scmutil.revrange(repo, revs) if not revs: ui.write_err('no revision to fold\n') return 1 roots = repo.revs('roots(%ld)', revs) if len(roots) > 1: - raise util.Abort("set have multiple roots") + raise util.Abort("set has multiple roots") root = repo[roots[0]] if root.phase() <= phases.public: - raise util.Abort("can't touch public revision") + raise util.Abort("can't fold public revisions") heads = repo.revs('heads(%ld)', revs) if len(heads) > 1: - raise util.Abort("set have multiple heads") + raise util.Abort("set has multiple heads") head = repo[heads[0]] - wlock = repo.wlock() + wlock = lock = None try: + wlock = repo.wlock() lock = repo.lock() + tr = repo.transaction('touch') try: - tr = repo.transaction('touch') - try: - allctx = [repo[r] for r in revs] - targetphase = max(c.phase() for c in allctx) - msg = '\n\n***\n\n'.join(c.description() for c in allctx) - newid, _ = rewrite(repo, root, allctx, head, - [root.p1().node(), root.p2().node()], - commitopts={'message': msg}) - phases.retractboundary(repo, targetphase, [newid]) - createmarkers(repo, [(ctx, (repo[newid],)) - for ctx in allctx]) - tr.close() - finally: - tr.release() + allctx = [repo[r] for r in revs] + targetphase = max(c.phase() for c in allctx) + msg = '\n\n***\n\n'.join(c.description() for c in allctx) + newid, _ = rewrite(repo, root, allctx, head, + [root.p1().node(), root.p2().node()], + commitopts={'message': msg}) + phases.retractboundary(repo, targetphase, [newid]) + createmarkers(repo, [(ctx, (repo[newid],)) + for ctx in allctx]) + tr.close() finally: - lock.release() + tr.release() ui.status('%i changesets folded\n' % len(revs)) if repo.revs('. and %ld', revs): - repo.dirstate.setparents(newid, node.nullid) + hg.update(repo, newid) finally: - wlock.release() + lockmod.release(lock, wlock) @eh.wrapcommand('graft') @@ -2103,7 +2139,7 @@ except KeyError: raise error.Abort(_('evolution extension requires rebase extension.')) - for cmd in ['amend', 'kill', 'uncommit']: + for cmd in ['amend', 'kill', 'uncommit', 'touch', 'fold']: entry = extensions.wrapcommand(cmdtable, cmd, warnobserrors) diff -r 53d7e3413337 -r 5a0a01c4c7c2 hgext/obsolete.py --- a/hgext/obsolete.py Fri Aug 24 11:49:21 2012 +0200 +++ b/hgext/obsolete.py Thu Sep 20 23:14:59 2012 +0200 @@ -1,5 +1,3 @@ -# obsolete.py - introduce the obsolete concept in mercurial. -# # Copyright 2011 Pierre-Yves David # Logilab SA # diff -r 53d7e3413337 -r 5a0a01c4c7c2 hgext/qsync.py --- a/hgext/qsync.py Fri Aug 24 11:49:21 2012 +0200 +++ b/hgext/qsync.py Thu Sep 20 23:14:59 2012 +0200 @@ -1,3 +1,4 @@ +# Copyright 2011 Logilab SA """synchronize patches queues and evolving changesets""" import re diff -r 53d7e3413337 -r 5a0a01c4c7c2 qsync-enable.sh --- a/qsync-enable.sh Fri Aug 24 11:49:21 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ -#!/bin/sh - -here=`readlink -f "$0"` -repo_root=`dirname "$here"` - - - -cat << EOF >&2 -XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -XXX Add lines below to the [extensions] section of you hgrc XXX -XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX - - -EOF - -cat << EOF | sed -e "s#XXXREPOPATHXXX#${repo_root}#" -[extensions] -# experimental extensions for mq export -qsync=XXXREPOPATHXXX/hgext/qsync.py -EOF diff -r 53d7e3413337 -r 5a0a01c4c7c2 setup.py --- a/setup.py Fri Aug 24 11:49:21 2012 +0200 +++ b/setup.py Thu Sep 20 23:14:59 2012 +0200 @@ -3,15 +3,9 @@ from distutils.core import setup -requires = [] -try: - import mercurial -except ImportError: - requires.append('mercurial') - setup( name='hg-evolve', - version='0.1.0', + version='1.0.2', author='Pierre-Yves David', maintainer='Pierre-Yves David', maintainer_email='pierre-yves.david@logilab.fr', @@ -21,5 +15,4 @@ keywords='hg mercurial', license='GPLv2+', py_modules=['hgext.evolve'], - install_requires=requires, ) diff -r 53d7e3413337 -r 5a0a01c4c7c2 tests/run-tests.py --- a/tests/run-tests.py Fri Aug 24 11:49:21 2012 +0200 +++ b/tests/run-tests.py Thu Sep 20 23:14:59 2012 +0200 @@ -74,7 +74,7 @@ if 'java' in sys.platform: IMPL_PATH = 'JYTHONPATH' -requiredtools = ["python", "diff", "grep", "unzip", "gunzip", "bunzip2", "sed"] +requiredtools = ["python", "diff", "grep", "sed"] defaults = { 'jobs': ('HGTEST_JOBS', 1), diff -r 53d7e3413337 -r 5a0a01c4c7c2 tests/test-evolve.t --- a/tests/test-evolve.t Fri Aug 24 11:49:21 2012 +0200 +++ b/tests/test-evolve.t Thu Sep 20 23:14:59 2012 +0200 @@ -58,7 +58,7 @@ $ hg log -r 1 --template '{rev} {phase} {obsolete}\n' 1 public stable $ hg kill 1 - abort: Cannot obsolete immutable changeset: 7c3bad9141dc + abort: cannot obsolete immutable changeset: 7c3bad9141dc [255] $ hg log -r 1 --template '{rev} {phase} {obsolete}\n' 1 public stable @@ -554,8 +554,13 @@ Test fold + $ rm *.orig + $ hg fold + no revision to fold + [1] $ hg fold 6::10 2 changesets folded + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved $ glog @ 11:*@default(draft) add 1 (glob) | @@ -573,9 +578,43 @@ *** conflict + $ hg debugrebuildstate + $ hg st + +Test fold with wc parent is not the head of the folded revision + + $ hg up 4 + 0 files updated, 0 files merged, 2 files removed, 0 files unresolved + $ hg fold 4::11 + 3 changesets folded + 2 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ glog + @ 12:*@default(draft) add 4 (glob) + | + | o 1:73d38bb17fd7@default(draft) add 1 + |/ + o 0:8685c6d34325@default(draft) add 0 + + $ hg log -r 12 --template '{desc}\n' + add 4 + + *** + + add 3 + + *** + + add 1 + + *** + + conflict + $ hg debugrebuildstate + $ hg st Test olog $ hg olog - 6 : add 1 - test - 10 : conflict - test + 4 : add 4 - test + 5 : add 3 - test + 11 : add 1 - test diff -r 53d7e3413337 -r 5a0a01c4c7c2 tests/test-obsolete-rebase.t --- a/tests/test-obsolete-rebase.t Fri Aug 24 11:49:21 2012 +0200 +++ b/tests/test-obsolete-rebase.t Thu Sep 20 23:14:59 2012 +0200 @@ -39,7 +39,7 @@ (see hg help phases for details) [255] $ hg phase --draft --force 0 - $ hg rebase -d 1 -r 3 --detach --keep + $ hg rebase -d 1 -r 3 --keep $ glog @ 4:9c5494949763@default(draft) adde | @@ -66,7 +66,7 @@ $ hg --config extensions.hgext.mq= strip tip 0 files updated, 0 files merged, 1 files removed, 0 files unresolved saved backup bundle to $TESTTMP/repo/.hg/strip-backup/9c5494949763-backup.hg - $ hg rebase -d 1 -r 3 --detach + $ hg rebase -d 1 -r 3 $ glog @ 4:9c5494949763@default(draft) adde | @@ -224,3 +224,89 @@ +a31943eabc4327df16f9eca71bf7779c32f815f7 03f165c84ea8889fc35a64a392caa7a0084dd212 0 {'date': '* *', 'user': 'test'} (glob) +4b9d80f48523e296f4402cc8e37236b768dfb981 1951ead9710803dbf117e95901954d5ed717f80b 0 {'date': '* *', 'user': 'test'} (glob) [1] + +Test hg pull --rebase + + $ hg glog + @ changeset: 12:1951ead97108 + | tag: tip + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: appendab + | + o changeset: 11:03f165c84ea8 + | parent: 1:540395c44225 + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: addd + | + | o changeset: 8:a7773ffa7edc + |/ parent: 1:540395c44225 + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: Collapsed revision + | + | o changeset: 4:9c5494949763 + |/ parent: 1:540395c44225 + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: adde + | + | o changeset: 2:102a90ea7b4a + | | parent: 0:07f494440405 + | | user: test + | | date: Thu Jan 01 00:00:00 1970 +0000 + | | summary: addb + | | + o | changeset: 1:540395c44225 + |/ user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: changea + | + o changeset: 0:07f494440405 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: adda + + $ echo '[phases]' >> .hg/hgrc + $ echo 'publish=False' >> .hg/hgrc + $ hg clone . -r 540395c44225 ../other + adding changesets + adding manifests + adding file changes + added 2 changesets with 2 changes to 1 files + updating to branch default + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ hg ph -vfd 'all()' + no phases changed + [1] + $ cd ../other + $ echo 'babar' > toto + $ hg add toto + $ hg ci -m 'babar is not dead' + $ echo '[ui]' >> .hg/hgrc + $ echo 'logtemplate={rev} {node|short} {desc|firstline}\n' >> .hg/hgrc + $ hg pull --rebase --traceback | grep -v 'saved' + pulling from $TESTTMP/repo + searching for changes + adding changesets + adding manifests + adding file changes + added 5 changesets with 5 changes to 5 files (+4 heads) + $ hg glog + @ [78] d5567dbec794 babar is not dead (re) + | + o [67] 1951ead97108 appendab (re) + | + o [56] 03f165c84ea8 addd (re) + | + | o [45] a7773ffa7edc Collapsed revision (re) + |/ + | o [34] 9c5494949763 adde (re) + |/ + | o [23] 102a90ea7b4a addb (re) + | | + o | 1 540395c44225 changea + |/ + o 0 07f494440405 adda + diff -r 53d7e3413337 -r 5a0a01c4c7c2 tests/test-obsolete.t --- a/tests/test-obsolete.t Fri Aug 24 11:49:21 2012 +0200 +++ b/tests/test-obsolete.t Thu Sep 20 23:14:59 2012 +0200 @@ -7,7 +7,6 @@ > [alias] > odiff=diff --rev 'limit(precursors(.),1)' --rev . > [extensions] - > hgext.graphlog= > hgext.rebase= > EOF $ echo "evolve=$(echo $(dirname $TESTDIR))/hgext/evolve.py" >> $HGRCPATH @@ -141,7 +140,7 @@ Test obsolete keyword - $ hg glog --template '{rev}:{node|short}@{branch}({obsolete}/{phase}) {desc|firstline}\n' \ + $ hg log -G --template '{rev}:{node|short}@{branch}({obsolete}/{phase}) {desc|firstline}\n' \ > --hidden @ 5:a7a6f2b5d8a5@default(unstable/draft) add d | @@ -458,19 +457,19 @@ check rebase compat - $ hg glog -r 'not extinct()' --template='{rev} - {node|short}\n' - o 8 - 159dfc9fa5d3 + $ hg log -G --template='{rev} - {node|short} {desc}\n' + o 8 - 159dfc9fa5d3 add obsol_d'' | - | o 4 - 725c380fe99b + | o 4 - 725c380fe99b add obsol_c' | | - x | 3 - 0d3f46688ccc + x | 3 - 0d3f46688ccc add obsol_c |/ - o 1 - 7c3bad9141dc + o 1 - 7c3bad9141dc add b | - o 0 - 1f0dee641bb7 + o 0 - 1f0dee641bb7 add a - $ hg glog --template='{rev} - {node|short}\n' --hidden + $ hg log -G --template='{rev} - {node|short}\n' --hidden x 9 - 83b5778897ad o 8 - 159dfc9fa5d3 @@ -494,21 +493,21 @@ should not rebase extinct changeset - $ hg --config extensions.hgext.rebase= rebase -s 7 -d 4 - whole rebase set is extinct and ignored. +#excluded 'whole rebase set is extinct and ignored.' message not in core + $ hg rebase -s 7 -d 4 2>&1 | grep -v 'whole rebase' nothing to rebase - [1] - $ hg --config extensions.hgext.rebase= rebase -b 3 -d 4 --traceback - $ hg --config extensions.graphlog= glog -r 'not extinct()' --template='{rev} - {node|short}\n' - @ 11 - 9468a5f5d8b2 + $ hg rebase -b '3' -d 4 --traceback + 2 new conflicting changesets + $ hg log -G --template='{rev} - {node|short} {desc}\n' + @ 11 - 9468a5f5d8b2 add obsol_d'' | - o 10 - 2033b4e49474 + o 10 - 2033b4e49474 add obsol_c | - o 4 - 725c380fe99b + o 4 - 725c380fe99b add obsol_c' | - o 1 - 7c3bad9141dc + o 1 - 7c3bad9141dc add b | - o 0 - 1f0dee641bb7 + o 0 - 1f0dee641bb7 add a Does not complain about new head if you obsolete the old one @@ -539,7 +538,7 @@ $ cd local $ hg phase --public 11 1 new latecomer changesets - $ hg --config extensions.graphlog=glog glog --template='{rev} - ({phase}) {node|short} {desc}\n' + $ hg log -G --template='{rev} - ({phase}) {node|short} {desc}\n' @ 12 - (draft) 6db5e282cb91 add obsol_d''' | | o 11 - (public) 9468a5f5d8b2 add obsol_d'' @@ -574,10 +573,9 @@ $ mkcommit f created new head $ echo 42 >> f - $ hg commit --amend --traceback - saved backup bundle to $TESTTMP/local/.hg/strip-backup/0b1b6dd009c0-amend-backup.hg - $ hg glog - @ changeset: 13:3734a65252e6 + $ hg commit --amend --traceback --quiet + $ hg log -G + @ changeset: 1[35]:3734a65252e6 (re) | tag: tip | parent: 10:2033b4e49474 | user: test @@ -617,7 +615,7 @@ date: Thu Jan 01 00:00:00 1970 +0000 summary: add a - $ hg debugobsolete + $ hg debugobsolete | grep -v 33d458d86621f3186c40bfccd77652f4a122743e 4538525df7e2b9f09423636c61ef63a4cb872a2d 0d3f46688ccc6e756c7e96cf64c391c411309597 0 {'date': '', 'user': 'test'} (glob) 0d3f46688ccc6e756c7e96cf64c391c411309597 725c380fe99b5e76613493f0903e8d11ddc70d54 0 {'date': '', 'user': 'test'} (glob) a7a6f2b5d8a54b81bc7aa2fba2934ad6d700a79e 95de7fc6918dea4c9c8d5382f50649794b474c4a 0 {'date': '', 'user': 'test'} (glob) @@ -629,6 +627,8 @@ 159dfc9fa5d334d7e03a0aecfc7f7ab4c3431fea 9468a5f5d8b2c5d91e17474e95ae4791e9718fdf 0 {'date': '* *', 'user': 'test'} (glob) 9468a5f5d8b2c5d91e17474e95ae4791e9718fdf 6db5e282cb91df5c43ff1f1287c119ff83230d42 0 {'date': '', 'user': 'test'} (glob) 0b1b6dd009c037985363e2290a0b579819f659db 3734a65252e69ddcced85901647a4f335d40de1e 0 {'date': '* *', 'user': 'test'} (glob) +#no produced by 2.3 +33d458d86621f3186c40bfccd77652f4a122743e 3734a65252e69ddcced85901647a4f335d40de1e 0 {'date': '* *', 'user': 'test'} (glob) Check conflict detection @@ -636,15 +636,15 @@ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved $ mkcommit "obsolet_conflicting_d" $ hg summary - parent: 14:50f11e5e3a63 tip + parent: 1[46]:50f11e5e3a63 tip (re) add obsolet_conflicting_d branch: default commit: (clean) - update: 9 new changesets, 9 branch heads (merge) + update: (9|11) new changesets, (9|10) branch heads \(merge\) (re) latecomer: 1 changesets $ hg debugobsolete `getid a7a6f2b5d8a5` `getid 50f11e5e3a63` $ hg log -r 'conflicting()' - changeset: 14:50f11e5e3a63 + changeset: 1[46]:50f11e5e3a63 (re) tag: tip parent: 11:9468a5f5d8b2 user: test diff -r 53d7e3413337 -r 5a0a01c4c7c2 tests/test-stabilize-conflict.t --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-stabilize-conflict.t Thu Sep 20 23:14:59 2012 +0200 @@ -0,0 +1,250 @@ +================================================================= +This files test the proper behavior of evo during merge conflict. +================================================================= + +Initial setup + + $ cat >> $HGRCPATH < [ui] + > interactive=false + > merge=internal:merge + > [defaults] + > amend=-d "0 0" + > [merge-tools] + > touch.checkchanged=true + > touch.gui=true + > touch.args=babar + > [extensions] + > hgext.rebase= + > EOF + $ echo "evolve=$(echo $(dirname $TESTDIR))/hgext/evolve.py" >> $HGRCPATH + + +create a simple repo + + $ hg init repo + $ cd repo + $ cat << EOF > babar + > un + > deux + > trois + > quatre + > cinq + > EOF + $ hg add babar + $ hg commit -m "babar count up to five" + $ cat << EOF >> babar + > six + > sept + > huit + > neuf + > dix + > EOF + $ hg commit -m "babar count up to ten" + $ cat << EOF >> babar + > onze + > douze + > treize + > quatorze + > quinze + > EOF + $ hg commit -m "babar count up to fifteen" + + +proper behavior without conflict +---------------------------------- + + $ hg gdown + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + [1] babar count up to ten + $ sed -i'' 's/huit/height/' babar + $ hg diff + diff -r 9d5daf8bd956 babar + --- a/babar Thu Jan 01 00:00:00 1970 +0000 + +++ b/babar * (glob) + @@ -5,6 +5,6 @@ + cinq + six + sept + -huit + +height + neuf + dix + $ hg amend + 1 new unstable changesets + $ hg evolve + move:[2] babar count up to fifteen + atop:[4] babar count up to ten + merging babar + $ hg resolve -l + $ hg log -G + @ changeset: 5:fd62611d0178 + | tag: tip + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: babar count up to fifteen + | + o changeset: 4:83066dedff55 + | parent: 0:29ec1554cfaf + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: babar count up to ten + | + o changeset: 0:29ec1554cfaf + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: babar count up to five + + + +proper behavior with conflict using internal:merge +-------------------------------------------------- + + $ hg gdown + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + [4] babar count up to ten + $ sed -i'' 's/dix/ten/' babar + $ hg diff + diff -r 83066dedff55 babar + --- a/babar Thu Jan 01 00:00:00 1970 +0000 + +++ b/babar * (glob) + @@ -7,4 +7,4 @@ + sept + height + neuf + -dix + +ten + $ hg amend + 1 new unstable changesets + $ hg evolve + move:[5] babar count up to fifteen + atop:[7] babar count up to ten + merging babar + warning: conflicts during merge. + merging babar incomplete! (edit conflicts, then use 'hg resolve --mark') + evolve failed! + fix conflict and run "hg evolve --continue" + abort: unresolved merge conflicts (see hg help resolve) + [255] + $ hg resolve -l + U babar + $ hg log -G + @ changeset: 7:cc96f75eae0b + | tag: tip + | parent: 0:29ec1554cfaf + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: babar count up to ten + | + | @ changeset: 5:fd62611d0178 + | | user: test + | | date: Thu Jan 01 00:00:00 1970 +0000 + | | summary: babar count up to fifteen + | | + | x changeset: 4:83066dedff55 + |/ parent: 0:29ec1554cfaf + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: babar count up to ten + | + o changeset: 0:29ec1554cfaf + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: babar count up to five + +(fix the conflict and continue) + + $ hg revert -r 5 --all + reverting babar + $ sed -i'' 's/dix/ten/' babar + $ hg resolve --all -m + $ hg evolve --continue + grafting revision 5 + $ hg resolve -l + $ hg log -G + @ changeset: 8:ce7ee8fecf30 + | tag: tip + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: babar count up to fifteen + | + o changeset: 7:cc96f75eae0b + | parent: 0:29ec1554cfaf + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: babar count up to ten + | + o changeset: 0:29ec1554cfaf + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: babar count up to five + +proper behavior with conflict using an external merge tools +----------------------------------------------------------- + + $ sed -i'' 's/merge=.*/merge=touch/' $HGRCPATH + $ sed -i'' 's/touch.gui=.*/touch.gui=false/' $HGRCPATH + $ hg gdown + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + [7] babar count up to ten + $ sed -i'' 's/ten/zehn/' babar + $ hg diff + diff -r cc96f75eae0b babar + --- a/babar Thu Jan 01 00:00:00 1970 +0000 + +++ b/babar * (glob) + @@ -7,4 +7,4 @@ + sept + height + neuf + -ten + +zehn + $ hg amend + 1 new unstable changesets + $ sed -i'' 's/interactive=.*/interactive=true/' $HGRCPATH + $ yes n 2> ../shutup | HGMERGE=touch hg evolve + move:[8] babar count up to fifteen + atop:[10] babar count up to ten + merging babar + output file babar appears unchanged + was merge successful (yn)? merging babar failed! + evolve failed! + fix conflict and run "hg evolve --continue" + abort: unresolved merge conflicts (see hg help resolve) + [255] + $ hg resolve -l + U babar + $ hg log -G + @ changeset: 10:02c637e61375 + | tag: tip + | parent: 0:29ec1554cfaf + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: babar count up to ten + | + | @ changeset: 8:ce7ee8fecf30 + | | user: test + | | date: Thu Jan 01 00:00:00 1970 +0000 + | | summary: babar count up to fifteen + | | + | x changeset: 7:cc96f75eae0b + |/ parent: 0:29ec1554cfaf + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: babar count up to ten + | + o changeset: 0:29ec1554cfaf + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: babar count up to five + + $ cat babar + un + deux + trois + quatre + cinq + six + sept + height + neuf + zehn diff -r 53d7e3413337 -r 5a0a01c4c7c2 tests/test-stabilize-order.t --- a/tests/test-stabilize-order.t Fri Aug 24 11:49:21 2012 +0200 +++ b/tests/test-stabilize-order.t Thu Sep 20 23:14:59 2012 +0200 @@ -65,7 +65,7 @@ $ hg evolve -v move:[5] addb atop:[7] adda - hg rebase -Dr ab8cbb6d87ff -d f5ff10856e5a + hg rebase -r ab8cbb6d87ff -d f5ff10856e5a resolving manifests getting b b @@ -91,7 +91,7 @@ $ hg evolve -v move:[3] addc atop:[8] addb - hg rebase -Dr 7a7552255fb5 -d 6bf44048e43f + hg rebase -r 7a7552255fb5 -d 6bf44048e43f resolving manifests getting b resolving manifests @@ -147,7 +147,7 @@ $ hg evolve --any -v move:[9] addc atop:[11] addb - hg rebase -Dr 5e819fbb0d27 -d 4e7cec6b4afe + hg rebase -r 5e819fbb0d27 -d 4e7cec6b4afe resolving manifests removing c getting b diff -r 53d7e3413337 -r 5a0a01c4c7c2 tests/test-stabilize-result.t --- a/tests/test-stabilize-result.t Fri Aug 24 11:49:21 2012 +0200 +++ b/tests/test-stabilize-result.t Thu Sep 20 23:14:59 2012 +0200 @@ -31,7 +31,7 @@ $ hg evolve -v move:[2] changea atop:[4] changea - hg rebase -Dr cce2c55b8965 -d 1447e1c4828d + hg rebase -r cce2c55b8965 -d 1447e1c4828d resolving manifests $ glog --hidden @ 4:1447e1c4828d@default(draft) bk:[changea] changea @@ -99,7 +99,7 @@ Stabilize of late comer with different parent ================================================== -(the with same parent is handled in test-evolve.t) +(the same parent case is handled in test-evolve.t) $ glog @ 8:e3183e9c0961@default(draft) bk:[] newer a @@ -149,7 +149,7 @@ $ hg evolve --any --dry-run recreate:[12] newer a atop:[8] newer a - hg rebase --rev 15c83af6f3a3 --detach e8cc1b534401; + hg rebase --rev 15c83af6f3a3 --dest e8cc1b534401; hg update e3183e9c0961; hg revert --all --rev 15c83af6f3a3; hg commit --msg "latecomer update to %s" (no-eol) @@ -171,8 +171,8 @@ o 0:07f494440405@default(public) bk:[] adda -Stabilize of conflicting changeset with same parent -==================================================== +Stabilize conflicting changesets with same parent +================================================= $ rm a.orig $ hg up 9 @@ -231,7 +231,7 @@ $ hg evolve -qn hg update -c 3883461cc228 && - hg merge 4754d61bc2db && + hg merge 4754d61bc2db && hg commit -m "auto merge resolving conflict between 3883461cc228 and 4754d61bc2db"&& hg up -C 7391601a4bfa && hg revert --all --rev tip && @@ -288,3 +288,38 @@ +less +conflict +babar + +Check conflicting during conflicting resolution +------------------------------------------------- + + $ hg up 15 + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + Working directory parent is obsolete + $ echo 'gotta break' >> a + $ hg amend + 1 new conflicting changesets + $ hg evolve -qn + hg update -c c956a4b140b6 && + hg merge ac6d600735a4 && + hg commit -m "auto merge resolving conflict between c956a4b140b6 and ac6d600735a4"&& + hg up -C 7391601a4bfa && + hg revert --all --rev tip && + hg commit -m "`hg log -r c956a4b140b6 --template={desc}`"; + $ hg evolve + merge:[24] More addition + with: [22] More addition + base: [15] More addition + merging a + warning: conflicts during merge. + merging a incomplete! (edit conflicts, then use 'hg resolve --mark') + 0 files updated, 0 files merged, 0 files removed, 1 files unresolved + use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon + abort: Merge conflict between several amendments, and this is not yet automated + (/!\ You can try: + /!\ * manual merge + resolve => new cset X + /!\ * hg up to the parent of the amended changeset (which are named W and Z) + /!\ * hg revert --all -r X + /!\ * hg ci -m "same message as the amended changeset" => new cset Y + /!\ * hg kill -n Y W Z + ) + [255] diff -r 53d7e3413337 -r 5a0a01c4c7c2 tests/test-tutorial.t --- a/tests/test-tutorial.t Fri Aug 24 11:49:21 2012 +0200 +++ b/tests/test-tutorial.t Thu Sep 20 23:14:59 2012 +0200 @@ -59,10 +59,13 @@ $ hg showconfig extensions extensions.hgext.graphlog= -And of course, we anabled the experimental extensions for mutable history: +And of course, we enable the experimental extensions for mutable history: - $ $(dirname $TESTDIR)/enable.sh >> $HGRCPATH 2> /dev/null - + $ cat >> $HGRCPATH < [extensions] + > rebase = + > evolve = $TESTDIR/../hgext/evolve.py + > EOF ----------------------- Single Developer Usage @@ -400,7 +403,7 @@ for simplicity shake we get the bathroom change in line again - $ hg rebase -Dr 8d39a843582d -d a2fccc2e7b08 + $ hg rebase -r 8d39a843582d -d a2fccc2e7b08 merging shopping $ hg phase --draft . $ hg log -G @@ -624,11 +627,11 @@ $ hg evolve --dry-run move:[15] animals atop:[14] bathroom stuff - hg rebase -Dr 9ac5d0e790a2 -d ffa278c50818 + hg rebase -r 9ac5d0e790a2 -d ffa278c50818 Let's do it - $ hg rebase -Dr 9ac5d0e790a2 -d ffa278c50818 + $ hg rebase -r 9ac5d0e790a2 -d ffa278c50818 merging shopping The old version of bathroom is hidden again.