merge with stable
authorAugie Fackler <augie@google.com>
Thu, 30 Nov 2017 15:48:42 -0500
changeset 35163 ee64e677c3cf
parent 35162 bdd2e18b54c5 (current diff)
parent 35111 62539b425347 (diff)
child 35164 6864c405f023
merge with stable
mercurial/cmdutil.py
mercurial/commands.py
mercurial/configitems.py
mercurial/dispatch.py
mercurial/localrepo.py
mercurial/subrepo.py
tests/test-amend.t
tests/test-bookmarks-pushpull.t
tests/test-setdiscovery.t
--- a/hgext/convert/__init__.py	Wed Nov 22 22:18:06 2017 +0800
+++ b/hgext/convert/__init__.py	Thu Nov 30 15:48:42 2017 -0500
@@ -28,103 +28,6 @@
 # leave the attribute unspecified.
 testedwith = 'ships-with-hg-core'
 
-configtable = {}
-configitem = registrar.configitem(configtable)
-
-configitem('convert', 'cvsps.cache',
-    default=True,
-)
-configitem('convert', 'cvsps.fuzz',
-    default=60,
-)
-configitem('convert', 'cvsps.logencoding',
-    default=None,
-)
-configitem('convert', 'cvsps.mergefrom',
-    default=None,
-)
-configitem('convert', 'cvsps.mergeto',
-    default=None,
-)
-configitem('convert', 'git.committeractions',
-    default=lambda: ['messagedifferent'],
-)
-configitem('convert', 'git.extrakeys',
-    default=list,
-)
-configitem('convert', 'git.findcopiesharder',
-    default=False,
-)
-configitem('convert', 'git.remoteprefix',
-    default='remote',
-)
-configitem('convert', 'git.renamelimit',
-    default=400,
-)
-configitem('convert', 'git.saverev',
-    default=True,
-)
-configitem('convert', 'git.similarity',
-    default=50,
-)
-configitem('convert', 'git.skipsubmodules',
-    default=False,
-)
-configitem('convert', 'hg.clonebranches',
-    default=False,
-)
-configitem('convert', 'hg.ignoreerrors',
-    default=False,
-)
-configitem('convert', 'hg.revs',
-    default=None,
-)
-configitem('convert', 'hg.saverev',
-    default=False,
-)
-configitem('convert', 'hg.sourcename',
-    default=None,
-)
-configitem('convert', 'hg.startrev',
-    default=None,
-)
-configitem('convert', 'hg.tagsbranch',
-    default='default',
-)
-configitem('convert', 'hg.usebranchnames',
-    default=True,
-)
-configitem('convert', 'ignoreancestorcheck',
-    default=False,
-)
-configitem('convert', 'localtimezone',
-    default=False,
-)
-configitem('convert', 'p4.encoding',
-    default=lambda: convcmd.orig_encoding,
-)
-configitem('convert', 'p4.startrev',
-    default=0,
-)
-configitem('convert', 'skiptags',
-    default=False,
-)
-configitem('convert', 'svn.debugsvnlog',
-    default=True,
-)
-configitem('convert', 'svn.trunk',
-    default=None,
-)
-configitem('convert', 'svn.tags',
-    default=None,
-)
-configitem('convert', 'svn.branches',
-    default=None,
-)
-configitem('convert', 'svn.startrev',
-    default=0,
-)
-
 # Commands definition was moved elsewhere to ease demandload job.
 
 @command('convert',
--- a/hgext/convert/p4.py	Wed Nov 22 22:18:06 2017 +0800
+++ b/hgext/convert/p4.py	Thu Nov 30 15:48:42 2017 -0500
@@ -44,6 +44,9 @@
 
 class p4_source(common.converter_source):
     def __init__(self, ui, path, revs=None):
+        # avoid import cycle
+        from . import convcmd
+
         super(p4_source, self).__init__(ui, path, revs=revs)
 
         if "/" in path and not path.startswith('//'):
@@ -53,7 +56,8 @@
         common.checktool('p4', abort=False)
 
         self.revmap = {}
-        self.encoding = self.ui.config('convert', 'p4.encoding')
+        self.encoding = self.ui.config('convert', 'p4.encoding',
+                                       convcmd.orig_encoding)
         self.re_type = re.compile(
             "([a-z]+)?(text|binary|symlink|apple|resource|unicode|utf\d+)"
             "(\+\w+)?$")
--- a/i18n/pt_BR.po	Wed Nov 22 22:18:06 2017 +0800
+++ b/i18n/pt_BR.po	Thu Nov 30 15:48:42 2017 -0500
@@ -1512,10 +1512,10 @@
 msgstr "    Por favor use :hg:`log`::"
 
 msgid ""
-"        hg children => hg log -r \"children()\"\n"
+"        hg children => hg log -r \"children(.)\"\n"
 "        hg children -r REV => hg log -r \"children(REV)\""
 msgstr ""
-"        hg children => hg log -r \"children()\"\n"
+"        hg children => hg log -r \"children(.)\"\n"
 "        hg children -r REV => hg log -r \"children(REV)\""
 
 msgid "    See :hg:`help log` and :hg:`help revsets.children`."
@@ -5510,7 +5510,7 @@
 #. i18n: column positioning for "hg summary"
 #, python-format
 msgid "hist:   %s (histedit --continue)\n"
-msgstr "hist:         %s (histedit --continue)\n"
+msgstr "histedit:      %s (histedit --continue)\n"
 
 #, python-format
 msgid "%d remaining"
@@ -6527,16 +6527,16 @@
 
 #. i18n: column positioning for "hg summary"
 msgid "largefiles: (no remote repo)\n"
-msgstr "largefiles:   (nenhum repositório remoto)\n"
+msgstr "largefiles:    (nenhum repositório remoto)\n"
 
 #. i18n: column positioning for "hg summary"
 msgid "largefiles: (no files to upload)\n"
-msgstr "largefiles:   (nenhum arquivo a ser enviado)\n"
+msgstr "largefiles:    (nenhum arquivo a ser enviado)\n"
 
 #. i18n: column positioning for "hg summary"
 #, python-format
 msgid "largefiles: %d entities for %d files to upload\n"
-msgstr "largefiles: %d entidades para %d arquivos a serem enviados\n"
+msgstr "largefiles:    %d entidades para %d arquivos a serem enviados\n"
 
 #, python-format
 msgid "largefile %s is not in cache and could not be downloaded"
@@ -8265,11 +8265,11 @@
 #. i18n: column positioning for "hg summary"
 #, python-format
 msgid "mq:     %s\n"
-msgstr "mq:           %s\n"
+msgstr "mq:            %s\n"
 
 #. i18n: column positioning for "hg summary"
 msgid "mq:     (empty queue)\n"
-msgstr "mq:           (fila vazia)\n"
+msgstr "mq:            (fila vazia)\n"
 
 msgid ""
 "``mq()``\n"
@@ -9799,12 +9799,12 @@
 
 #. i18n: column positioning for "hg summary"
 msgid "rebase: (use \"hg rebase --abort\" to clear broken state)\n"
-msgstr "rebase: (use \"hg rebase --abort\" para limpar o estado quebrado)\n"
+msgstr "rebase:        (use \"hg rebase --abort\" para limpar o estado quebrado)\n"
 
 #. i18n: column positioning for "hg summary"
 #, python-format
 msgid "rebase: %s, %s (rebase --continue)\n"
-msgstr "rebase:       %s, %s (rebase --continue)\n"
+msgstr "rebase:        %s, %s (rebase --continue)\n"
 
 #, python-format
 msgid "%d rebased"
@@ -10492,7 +10492,7 @@
 "    caminho ou URL pedida em :hg:`clone` for idêntico a um repositório\n"
 "    que tenha sido clonado anteriormente."
 
-msgid "    The default naming mode is \"identity.\"\n"
+msgid "    The default naming mode is \"identity\".\n"
 msgstr "    O modo de nomeação padrão é \"identity\".\n"
 
 msgid "do not create a working directory"
@@ -12157,7 +12157,7 @@
 #. i18n: column positioning for "hg summary"
 #, python-format
 msgid "remote: %s\n"
-msgstr "remoto:       %s\n"
+msgstr "remoto:        %s\n"
 
 msgid "push failed:"
 msgstr "o push falhou:"
@@ -15012,7 +15012,7 @@
 
 msgid ""
 "    If --force is specified, revisions will be grafted even if they\n"
-"    are already ancestors of or have been grafted to the destination.\n"
+"    are already ancestors of, or have been grafted to, the destination.\n"
 "    This is useful when the revisions have since been backed out."
 msgstr ""
 "    Se --force for especificado, as revisões serão enxertadas mesmo\n"
@@ -15705,11 +15705,12 @@
 msgid ""
 "    Show new changesets found in the specified path/URL or the default\n"
 "    pull location. These are the changesets that would have been pulled\n"
-"    if a pull at the time you issued this command."
+"    by :hg:`pull` at the time you issued this command."
 msgstr ""
 "    Mostra novas revisões encontradas no caminho/URL especificado\n"
 "    ou na localização de pull padrão. Estas são as revisões que\n"
-"    seriam trazidas se um pull fosse executado."
+"    seriam trazidas por :hg:`pull` no momento da execução deste\n"
+"    comando."
 
 msgid "    See pull for valid source format details."
 msgstr "    Veja pull para detalhes sobre formatos válidos da origem."
@@ -16442,8 +16443,8 @@
 "    secreta, respectivamente."
 
 msgid ""
-"    Unless -f/--force is specified, :hg:`phase` won't move changeset from a\n"
-"    lower phase to an higher phase. Phases are ordered as follows::"
+"    Unless -f/--force is specified, :hg:`phase` won't move changesets from a\n"
+"    lower phase to a higher phase. Phases are ordered as follows::"
 msgstr ""
 "    A não ser que -f/--force seja especificado, :hg:`phase` não\n"
 "    moverá revisões de uma fase mais baixa para uma mais alta. As\n"
@@ -17449,13 +17450,14 @@
 "      'i' 'ignorado' e 'c' 'limpo'."
 
 msgid ""
-"      It abbreviates only those statuses which are passed. Note that ignored\n"
-"      files are not displayed with '--terse i' unless the -i/--ignored option is\n"
-"      also used."
+"      It abbreviates only those statuses which are passed. Note that clean and\n"
+"      ignored files are not displayed with '--terse ic' unless the -c/--clean\n"
+"      and -i/--ignored options are also used."
 msgstr ""
 "      A saída será abreviada apenas para os status que forem passados.\n"
-"      Note que arquivos ignorados não serão mostrados com '--terse i'\n"
-"      a não ser que a opção -i/--ignored também seja usada."
+"      Note que arquivos limpos ou ignorados não serão mostrados com\n"
+"      '--terse ic' a não ser que as opções -c/--clean e -i/--ignored\n"
+"      também sejam usadas."
 
 msgid ""
 "      The -v/--verbose option shows information when the repository is in an\n"
@@ -17554,7 +17556,7 @@
 #. i18n: column positioning for "hg summary"
 #, python-format
 msgid "parent: %d:%s "
-msgstr "pai:          %d:%s "
+msgstr "pai:           %d:%s "
 
 msgid " (empty repository)"
 msgstr " (repositório vazio)"
@@ -17568,11 +17570,11 @@
 #. i18n: column positioning for "hg summary"
 #, python-format
 msgid "branch: %s\n"
-msgstr "ramo:         %s\n"
+msgstr "ramo:          %s\n"
 
 #. i18n: column positioning for "hg summary"
 msgid "bookmarks:"
-msgstr "marcadores:  "
+msgstr "marcadores:   "
 
 #, python-format
 msgid "%d modified"
@@ -17634,21 +17636,21 @@
 #. i18n: column positioning for "hg summary"
 #, python-format
 msgid "commit: %s\n"
-msgstr "consolidação: %s\n"
+msgstr "consolidação:  %s\n"
 
 #. i18n: column positioning for "hg summary"
 msgid "update: (current)\n"
-msgstr "atualizações: (atual)\n"
+msgstr "atualizações:  (atual)\n"
 
 #. i18n: column positioning for "hg summary"
 #, python-format
 msgid "update: %d new changesets (update)\n"
-msgstr "atualizações: %d novas revisões (update)\n"
+msgstr "atualizações:  %d novas revisões (update)\n"
 
 #. i18n: column positioning for "hg summary"
 #, python-format
 msgid "update: %d new changesets, %d branch heads (merge)\n"
-msgstr "atualizações: %d novas revisões, %d cabeças de ramo (merge)\n"
+msgstr "atualizações:  %d novas revisões, %d cabeças de ramo (merge)\n"
 
 #, python-format
 msgid "%d draft"
@@ -17660,7 +17662,7 @@
 
 #, python-format
 msgid "phases: %s\n"
-msgstr "fases: %s\n"
+msgstr "fases:         %s\n"
 
 #, python-format
 msgid "orphan: %d changesets"
@@ -17691,7 +17693,7 @@
 
 #. i18n: column positioning for "hg summary"
 msgid "remote: (synced)\n"
-msgstr "remoto:       (sincronizado)\n"
+msgstr "remoto:        (sincronizado)\n"
 
 msgid "force tag"
 msgstr "força a mudança da etiqueta"
@@ -20935,6 +20937,9 @@
 msgid "Changegroups"
 msgstr "Changegroups"
 
+msgid "Config Registrar"
+msgstr "Registrador de Configurações"
+
 msgid "Repository Requirements"
 msgstr "Requisitos do Repositório"
 
@@ -23843,25 +23848,31 @@
 "  Run right before a phase change is actually finalized. Any repository change\n"
 "  will be visible to the hook program. This lets you validate the transaction\n"
 "  content or change it. Exit status 0 allows the commit to proceed.  A non-zero\n"
-"  status will cause the transaction to be rolled back.\n"
+"  status will cause the transaction to be rolled back. The hook is called\n"
+"  multiple times, once for each revision affected by a phase change.\n"
 "  The affected node is available in ``$HG_NODE``, the phase in ``$HG_PHASE``\n"
 "  while the previous ``$HG_OLDPHASE``. In case of new node, ``$HG_OLDPHASE``\n"
 "  will be empty.  In addition, the reason for the transaction opening will be in\n"
 "  ``$HG_TXNNAME``, and a unique identifier for the transaction will be in\n"
-"  ``HG_TXNID``."
-msgstr ""
-"``pretxnclose``\n"
+"  ``HG_TXNID``. The hook is also run for newly added revisions. In this case\n"
+"  the ``$HG_OLDPHASE`` entry will be empty."
+msgstr ""
+"``pretxnclose-phase``\n"
 "  Executado imediatamente antes de uma mudança de fase ser finalizada.\n"
 "  Qualquer mudança do repositório será visível para o gancho.\n"
 "  Isto permite que o conteúdo da transação seja validado ou alterado.\n"
 "  O status de saída 0 permite que a consolidação prossiga. Um status\n"
 "  de saída diferente de zero fará com que a transação seja desfeita.\n"
+"  O gancho é chamado diversas vezes, uma para cada revisão afetada\n"
+"  pela mudança de fase.\n"
 "  O nó afetado será passado em ``$HG_NODE``, a nova fase em ``$HG_PHASE``\n"
 "  e a anterior em ``$HG_OLDPHASE``.\n"
 "  No caso de um novo nó, ``$HG_OLDPHASE`` estará vazia.\n"
 "  Adicionalmente, a razão da abertura da transação será passada em\n"
 "  ``$HG_TXNNAME``, e um identificador único para a transação será\n"
-"  passado em ``HG_TXNID``."
+"  passado em ``HG_TXNID``.\n"
+"  O gancho também será executado para revisões novas; nesse caso,\n"
+"  ``$HG_OLDPHASE`` estará vazia."
 
 msgid ""
 "``txnclose``\n"
@@ -25832,6 +25843,105 @@
 "As regras são aplicadas na ordem de definição."
 
 msgid ""
+"``subrepos``\n"
+"------------"
+msgstr ""
+"``subrepos``\n"
+"------------"
+
+msgid ""
+"This section contains options that control the behavior of the\n"
+"subrepositories feature. See also :hg:`help subrepos`."
+msgstr ""
+"Esta seção contém opções que controlam o comportamento\n"
+"da funcionalidade de sub-repositórios.\n"
+"Veja também :hg:`help subrepos`."
+
+msgid ""
+"Security note: auditing in Mercurial is known to be insufficient to\n"
+"prevent clone-time code execution with carefully constructed Git\n"
+"subrepos. It is unknown if a similar detect is present in Subversion\n"
+"subrepos. Both Git and Subversion subrepos are disabled by default\n"
+"out of security concerns. These subrepo types can be enabled using\n"
+"the respective options below."
+msgstr ""
+"Aviso de segurança: sabe-se que a auditoria no Mercurial é\n"
+"insuficiente para impedir execução de código no momento da\n"
+"clonagem com repositórios Git construídos maliciosamente.\n"
+"Não se sabe se esse problema afeta repositórios do Subversion.\n"
+"Tanto sub-repositórios do Git como do Subversion são por padrão\n"
+"desabilitados por razões de segurança.\n"
+"Esses tipos de sub-repositórios podem ser habilitados usando as\n"
+"respectivas opções abaixo."
+
+msgid ""
+"``allowed``\n"
+"    Whether subrepositories are allowed in the working directory."
+msgstr ""
+"``allowed``\n"
+"    Define se sub-repositórios são permitidos no diretório\n"
+"    de trabalho."
+
+msgid ""
+"    When false, commands involving subrepositories (like :hg:`update`)\n"
+"    will fail for all subrepository types.\n"
+"    (default: true)"
+msgstr ""
+"    Se False, comandos envolvendo sub-repositórios (como :hg:`update`)\n"
+"    falharão para todos os tipos de sub-repositório.\n"
+"    (padrão: True)"
+
+msgid ""
+"``hg:allowed``\n"
+"    Whether Mercurial subrepositories are allowed in the working\n"
+"    directory. This option only has an effect if ``subrepos.allowed``\n"
+"    is true.\n"
+"    (default: true)"
+msgstr ""
+"``hg:allowed``\n"
+"    Se sub-repositórios do Mercurial são permitidos no diretório\n"
+"    de trabalho.\n"
+"    Esta opção tem efeito apenas se ``subrepos.allowed`` for True.\n"
+"    (padrão: True)"
+
+msgid ""
+"``git:allowed``\n"
+"    Whether Git subrepositories are allowed in the working directory.\n"
+"    This option only has an effect if ``subrepos.allowed`` is true."
+msgstr ""
+"``git:allowed``\n"
+"    Se sub-repositórios do Git são permitidos no diretório\n"
+"    de trabalho.\n"
+"    Esta opção tem efeito apenas se ``subrepos.allowed`` for True."
+
+msgid ""
+"    See the security note above before enabling Git subrepos.\n"
+"    (default: false)"
+msgstr ""
+"    Veja o aviso de segurança acima antes de habilitar\n"
+"    sub-repositórios do Git.\n"
+"    (padrão: False)"
+
+msgid ""
+"``svn:allowed``\n"
+"    Whether Subversion subrepositories are allowed in the working\n"
+"    directory. This option only has an effect if ``subrepos.allowed``\n"
+"    is true."
+msgstr ""
+"``svn:allowed``\n"
+"    Se sub-repositórios do Subversion são permitidos no diretório\n"
+"    de trabalho.\n"
+"    Esta opção tem efeito apenas se ``subrepos.allowed`` for True."
+
+msgid ""
+"    See the security note above before enabling Subversion subrepos.\n"
+"    (default: false)"
+msgstr ""
+"    Veja o aviso de segurança acima antes de habilitar\n"
+"    sub-repositórios do Subversion.\n"
+"    (padrão: False)"
+
+msgid ""
 "``templatealias``\n"
 "-----------------"
 msgstr ""
@@ -29958,7 +30068,7 @@
 msgid ""
 "   After selecting a merge program, Mercurial will by default attempt\n"
 "   to merge the files using a simple merge algorithm first. Only if it doesn't\n"
-"   succeed because of conflicting changes Mercurial will actually execute the\n"
+"   succeed because of conflicting changes will Mercurial actually execute the\n"
 "   merge program. Whether to use the simple merge algorithm first can be\n"
 "   controlled by the premerge setting of the merge tool. Premerge is enabled by\n"
 "   default unless the file is binary or a symlink."
@@ -30334,7 +30444,7 @@
 "Veja :hg:`help -v phase` para alguns exemplos."
 
 msgid ""
-"To make yours commits secret by default, put this in your\n"
+"To make your commits secret by default, put this in your\n"
 "configuration file::"
 msgstr ""
 "Para colocar suas consolidações na fase secret por padrão,\n"
@@ -30453,7 +30563,7 @@
 msgid "     hg phase --force --draft ."
 msgstr "     hg phase --force --draft ."
 
-msgid " - show a list of changeset revision and phase::"
+msgid " - show a list of changeset revisions and each corresponding phase::"
 msgstr " - mostra uma lista de números de revisão e suas respectivas fases::"
 
 msgid "     hg log --template \"{rev} {phase}\\n\""
@@ -30755,7 +30865,7 @@
 
 msgid ""
 "For example, ``tag(r're:(?i)release')`` matches \"release\" or \"RELEASE\"\n"
-"or \"Release\", etc"
+"or \"Release\", etc."
 msgstr ""
 "Por exemplo, ``tag(r're:(?i)release')`` corresponde a \"release\"\n"
 "ou \"RELEASE\" ou \"Release\", etc."
@@ -30886,7 +30996,7 @@
 "    hg log -r \"(keyword(bug) or keyword(issue)) and not ancestors(tag())\""
 
 msgid ""
-"- Update to commit that bookmark @ is pointing too, without activating the\n"
+"- Update to the commit that bookmark @ is pointing to, without activating the\n"
 "  bookmark (this works because the last revision of the revset is used)::"
 msgstr ""
 "- Atualiza para a revisão que o marcador @ está apontando, sem ativar\n"
@@ -33530,12 +33640,12 @@
 #. i18n: column positioning for "hg log"
 #, python-format
 msgid "bookmark:    %s\n"
-msgstr "marcador:     %s\n"
+msgstr "marcador:      %s\n"
 
 #. i18n: column positioning for "hg log"
 #, python-format
 msgid "tag:         %s\n"
-msgstr "etiqueta:     %s\n"
+msgstr "etiqueta:      %s\n"
 
 #, python-format
 msgid "no such name: %s"
@@ -36031,6 +36141,20 @@
 msgstr "aviso: removendo 'hgrc' potencialmente hostil em '%s'\n"
 
 #, python-format
+msgid "subrepo '%s' traverses symbolic link"
+msgstr "o sub-repositório '%s' atravessa um link simbólico"
+
+msgid "subrepos not enabled"
+msgstr "sub-repositórios não estão habilitados"
+
+msgid "see 'hg help config.subrepos' for details"
+msgstr "veja 'hg help config.subrepos' para detalhes"
+
+#, python-format
+msgid "%s subrepos not allowed"
+msgstr "sub-repositórios %s não são permitidos"
+
+#, python-format
 msgid "unknown subrepo type %s"
 msgstr "tipo de sub-repositório %s desconhecido"
 
--- a/mercurial/chgserver.py	Wed Nov 22 22:18:06 2017 +0800
+++ b/mercurial/chgserver.py	Thu Nov 30 15:48:42 2017 -0500
@@ -235,6 +235,7 @@
     cwds = dispatch._earlygetopt(['--cwd'], args)
     cwd = cwds and os.path.realpath(cwds[-1]) or None
     rpath = dispatch._earlygetopt(["-R", "--repository", "--repo"], args)
+    rpath = rpath and rpath[-1] or ''
     path, newlui = dispatch._getlocal(newui, rpath, wd=cwd)
 
     return (newui, newlui)
--- a/mercurial/cmdutil.py	Wed Nov 22 22:18:06 2017 +0800
+++ b/mercurial/cmdutil.py	Thu Nov 30 15:48:42 2017 -0500
@@ -3166,6 +3166,18 @@
             raise error.Abort(
                 _("failed to mark all new/missing files as added/removed"))
 
+        # Check subrepos. This depends on in-place wctx._status update in
+        # subrepo.precommit(). To minimize the risk of this hack, we do
+        # nothing if .hgsub does not exist.
+        if '.hgsub' in wctx or '.hgsub' in old:
+            from . import subrepo  # avoid cycle: cmdutil -> subrepo -> cmdutil
+            subs, commitsubs, newsubstate = subrepo.precommit(
+                ui, wctx, wctx._status, matcher)
+            # amend should abort if commitsubrepos is enabled
+            assert not commitsubs
+            if subs:
+                subrepo.writestate(repo, newsubstate)
+
         filestoamend = set(f for f in wctx.files() if matcher(f))
 
         changes = (len(filestoamend) > 0)
@@ -3179,9 +3191,11 @@
             # introduced file X and the file was renamed in the working
             # copy, then those two files are the same and
             # we can discard X from our list of files. Likewise if X
-            # was deleted, it's no longer relevant
+            # was removed, it's no longer relevant. If X is missing (aka
+            # deleted), old X must be preserved.
             files.update(filestoamend)
-            files = [f for f in files if not samefile(f, wctx, base)]
+            files = [f for f in files if (not samefile(f, wctx, base)
+                                          or f in wctx.deleted())]
 
             def filectxfn(repo, ctx_, path):
                 try:
@@ -3193,12 +3207,11 @@
                     if path not in filestoamend:
                         return old.filectx(path)
 
+                    # Return None for removed files.
+                    if path in wctx.removed():
+                        return None
+
                     fctx = wctx[path]
-
-                    # Return None for removed files.
-                    if not fctx.exists():
-                        return None
-
                     flags = fctx.flags()
                     mctx = context.memfilectx(repo,
                                               fctx.path(), fctx.data(),
--- a/mercurial/commands.py	Wed Nov 22 22:18:06 2017 +0800
+++ b/mercurial/commands.py	Thu Nov 30 15:48:42 2017 -0500
@@ -103,6 +103,10 @@
      _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
 ]
 
+# options which must be pre-parsed before loading configs and extensions
+# TODO: perhaps --debugger should be included
+earlyoptflags = ("--cwd", "-R", "--repository", "--repo", "--config")
+
 dryrunopts = cmdutil.dryrunopts
 remoteopts = cmdutil.remoteopts
 walkopts = cmdutil.walkopts
--- a/mercurial/configitems.py	Wed Nov 22 22:18:06 2017 +0800
+++ b/mercurial/configitems.py	Thu Nov 30 15:48:42 2017 -0500
@@ -208,6 +208,99 @@
     default=None,
     generic=True,
 )
+coreconfigitem('convert', 'cvsps.cache',
+    default=True,
+)
+coreconfigitem('convert', 'cvsps.fuzz',
+    default=60,
+)
+coreconfigitem('convert', 'cvsps.logencoding',
+    default=None,
+)
+coreconfigitem('convert', 'cvsps.mergefrom',
+    default=None,
+)
+coreconfigitem('convert', 'cvsps.mergeto',
+    default=None,
+)
+coreconfigitem('convert', 'git.committeractions',
+    default=lambda: ['messagedifferent'],
+)
+coreconfigitem('convert', 'git.extrakeys',
+    default=list,
+)
+coreconfigitem('convert', 'git.findcopiesharder',
+    default=False,
+)
+coreconfigitem('convert', 'git.remoteprefix',
+    default='remote',
+)
+coreconfigitem('convert', 'git.renamelimit',
+    default=400,
+)
+coreconfigitem('convert', 'git.saverev',
+    default=True,
+)
+coreconfigitem('convert', 'git.similarity',
+    default=50,
+)
+coreconfigitem('convert', 'git.skipsubmodules',
+    default=False,
+)
+coreconfigitem('convert', 'hg.clonebranches',
+    default=False,
+)
+coreconfigitem('convert', 'hg.ignoreerrors',
+    default=False,
+)
+coreconfigitem('convert', 'hg.revs',
+    default=None,
+)
+coreconfigitem('convert', 'hg.saverev',
+    default=False,
+)
+coreconfigitem('convert', 'hg.sourcename',
+    default=None,
+)
+coreconfigitem('convert', 'hg.startrev',
+    default=None,
+)
+coreconfigitem('convert', 'hg.tagsbranch',
+    default='default',
+)
+coreconfigitem('convert', 'hg.usebranchnames',
+    default=True,
+)
+coreconfigitem('convert', 'ignoreancestorcheck',
+    default=False,
+)
+coreconfigitem('convert', 'localtimezone',
+    default=False,
+)
+coreconfigitem('convert', 'p4.encoding',
+    default=dynamicdefault,
+)
+coreconfigitem('convert', 'p4.startrev',
+    default=0,
+)
+coreconfigitem('convert', 'skiptags',
+    default=False,
+)
+coreconfigitem('convert', 'svn.debugsvnlog',
+    default=True,
+)
+coreconfigitem('convert', 'svn.trunk',
+    default=None,
+)
+coreconfigitem('convert', 'svn.tags',
+    default=None,
+)
+coreconfigitem('convert', 'svn.branches',
+    default=None,
+)
+coreconfigitem('convert', 'svn.startrev',
+    default=0,
+)
 coreconfigitem('debug', 'dirstate.delaywrite',
     default=0,
 )
--- a/mercurial/dispatch.py	Wed Nov 22 22:18:06 2017 +0800
+++ b/mercurial/dispatch.py	Thu Nov 30 15:48:42 2017 -0500
@@ -55,6 +55,9 @@
         self.fout = fout
         self.ferr = ferr
 
+        # remember options pre-parsed by _earlyreqopt*()
+        self.earlyoptions = {}
+
         # reposetups which run before extensions, useful for chg to pre-fill
         # low-level repo state (for example, changelog) before extensions.
         self.prereposetups = prereposetups or []
@@ -147,7 +150,7 @@
     try:
         if not req.ui:
             req.ui = uimod.ui.load()
-        if '--traceback' in req.args:
+        if _earlyreqoptbool(req, 'traceback', ['--traceback']):
             req.ui.setconfig('ui', 'traceback', 'on', '--traceback')
 
         # set ui streams from the request
@@ -261,7 +264,8 @@
 
             # read --config before doing anything else
             # (e.g. to change trust settings for reading .hg/hgrc)
-            cfgs = _parseconfig(req.ui, _earlygetopt(['--config'], req.args))
+            cfgs = _parseconfig(req.ui,
+                                _earlyreqopt(req, 'config', ['--config']))
 
             if req.repo:
                 # copy configs that were passed on the cmdline (--config) to
@@ -275,7 +279,7 @@
             if not debugger or ui.plain():
                 # if we are in HGPLAIN mode, then disable custom debugging
                 debugger = 'pdb'
-            elif '--debugger' in req.args:
+            elif _earlyreqoptbool(req, 'debugger', ['--debugger']):
                 # This import can be slow for fancy debuggers, so only
                 # do it when absolutely necessary, i.e. when actual
                 # debugging has been requested
@@ -289,7 +293,7 @@
             debugmortem[debugger] = debugmod.post_mortem
 
             # enter the debugger before command execution
-            if '--debugger' in req.args:
+            if _earlyreqoptbool(req, 'debugger', ['--debugger']):
                 ui.warn(_("entering debugger - "
                         "type c to continue starting hg or h for help\n"))
 
@@ -305,7 +309,7 @@
                 ui.flush()
         except: # re-raises
             # enter the debugger when we hit an exception
-            if '--debugger' in req.args:
+            if _earlyreqoptbool(req, 'debugger', ['--debugger']):
                 traceback.print_exc()
                 debugmortem[debugger](sys.exc_info()[2])
             raise
@@ -465,7 +469,7 @@
         self.cmdname = cmd = args.pop(0)
         self.givenargs = args
 
-        for invalidarg in ("--cwd", "-R", "--repository", "--repo", "--config"):
+        for invalidarg in commands.earlyoptflags:
             if _earlygetopt([invalidarg], args):
                 self.badalias = (_("error in definition for alias '%s': %s may "
                                    "only be given on the command line")
@@ -640,11 +644,11 @@
 
     return configs
 
-def _earlygetopt(aliases, args):
+def _earlygetopt(aliases, args, strip=True):
     """Return list of values for an option (or aliases).
 
     The values are listed in the order they appear in args.
-    The options and values are removed from args.
+    The options and values are removed from args if strip=True.
 
     >>> args = [b'x', b'--cwd', b'foo', b'y']
     >>> _earlygetopt([b'--cwd'], args), args
@@ -654,13 +658,33 @@
     >>> _earlygetopt([b'--cwd'], args), args
     (['bar'], ['x', 'y'])
 
+    >>> args = [b'x', b'--cwd=bar', b'y']
+    >>> _earlygetopt([b'--cwd'], args, strip=False), args
+    (['bar'], ['x', '--cwd=bar', 'y'])
+
     >>> args = [b'x', b'-R', b'foo', b'y']
     >>> _earlygetopt([b'-R'], args), args
     (['foo'], ['x', 'y'])
 
+    >>> args = [b'x', b'-R', b'foo', b'y']
+    >>> _earlygetopt([b'-R'], args, strip=False), args
+    (['foo'], ['x', '-R', 'foo', 'y'])
+
     >>> args = [b'x', b'-Rbar', b'y']
     >>> _earlygetopt([b'-R'], args), args
     (['bar'], ['x', 'y'])
+
+    >>> args = [b'x', b'-Rbar', b'y']
+    >>> _earlygetopt([b'-R'], args, strip=False), args
+    (['bar'], ['x', '-Rbar', 'y'])
+
+    >>> args = [b'x', b'-R=bar', b'y']
+    >>> _earlygetopt([b'-R'], args), args
+    (['=bar'], ['x', 'y'])
+
+    >>> args = [b'x', b'-R', b'--', b'y']
+    >>> _earlygetopt([b'-R'], args), args
+    ([], ['x', '-R', '--', 'y'])
     """
     try:
         argcount = args.index("--")
@@ -671,28 +695,77 @@
     pos = 0
     while pos < argcount:
         fullarg = arg = args[pos]
-        equals = arg.find('=')
+        equals = -1
+        if arg.startswith('--'):
+            equals = arg.find('=')
         if equals > -1:
             arg = arg[:equals]
         if arg in aliases:
-            del args[pos]
             if equals > -1:
                 values.append(fullarg[equals + 1:])
-                argcount -= 1
+                if strip:
+                    del args[pos]
+                    argcount -= 1
+                else:
+                    pos += 1
             else:
                 if pos + 1 >= argcount:
                     # ignore and let getopt report an error if there is no value
                     break
-                values.append(args.pop(pos))
-                argcount -= 2
+                values.append(args[pos + 1])
+                if strip:
+                    del args[pos:pos + 2]
+                    argcount -= 2
+                else:
+                    pos += 2
         elif arg[:2] in shortopts:
             # short option can have no following space, e.g. hg log -Rfoo
-            values.append(args.pop(pos)[2:])
-            argcount -= 1
+            values.append(args[pos][2:])
+            if strip:
+                del args[pos]
+                argcount -= 1
+            else:
+                pos += 1
         else:
             pos += 1
     return values
 
+def _earlyreqopt(req, name, aliases):
+    """Peek a list option without using a full options table"""
+    values = _earlygetopt(aliases, req.args, strip=False)
+    req.earlyoptions[name] = values
+    return values
+
+def _earlyreqoptstr(req, name, aliases):
+    """Peek a string option without using a full options table"""
+    value = (_earlygetopt(aliases, req.args, strip=False) or [''])[-1]
+    req.earlyoptions[name] = value
+    return value
+
+def _earlyreqoptbool(req, name, aliases):
+    """Peek a boolean option without using a full options table
+
+    >>> req = request([b'x', b'--debugger'])
+    >>> _earlyreqoptbool(req, b'debugger', [b'--debugger'])
+    True
+
+    >>> req = request([b'x', b'--', b'--debugger'])
+    >>> _earlyreqoptbool(req, b'debugger', [b'--debugger'])
+    """
+    try:
+        argcount = req.args.index("--")
+    except ValueError:
+        argcount = len(req.args)
+    value = None
+    pos = 0
+    while pos < argcount:
+        arg = req.args[pos]
+        if arg in aliases:
+            value = True
+        pos += 1
+    req.earlyoptions[name] = value
+    return value
+
 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
     # run pre-hook, and abort if it fails
     hook.hook(lui, repo, "pre-%s" % cmd, True, args=" ".join(fullargs),
@@ -727,8 +800,8 @@
         lui = ui.copy()
         lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
 
-    if rpath and rpath[-1]:
-        path = lui.expandpath(rpath[-1])
+    if rpath:
+        path = lui.expandpath(rpath)
         lui = ui.copy()
         lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
 
@@ -759,6 +832,9 @@
     fn = entry[0]
 
     if cmd and util.safehasattr(fn, 'shell'):
+        # shell alias shouldn't receive early options which are consumed by hg
+        args = args[:]
+        _earlygetopt(commands.earlyoptflags, args, strip=True)
         d = lambda: fn(ui, *args[1:])
         return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d,
                                   [], {})
@@ -768,11 +844,11 @@
     ui = req.ui
 
     # check for cwd
-    cwd = _earlygetopt(['--cwd'], args)
+    cwd = _earlyreqoptstr(req, 'cwd', ['--cwd'])
     if cwd:
-        os.chdir(cwd[-1])
+        os.chdir(cwd)
 
-    rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
+    rpath = _earlyreqoptstr(req, 'repository', ["-R", "--repository", "--repo"])
     path, lui = _getlocal(ui, rpath)
 
     uis = {ui, lui}
@@ -780,7 +856,7 @@
     if req.repo:
         uis.add(req.repo.ui)
 
-    if '--profile' in args:
+    if _earlyreqoptbool(req, 'profile', ['--profile']):
         for ui_ in uis:
             ui_.setconfig('profiling', 'enabled', 'true', '--profile')
 
@@ -812,14 +888,17 @@
         fullargs = args
         cmd, func, args, options, cmdoptions = _parse(lui, args)
 
-        if options["config"]:
+        if options["config"] != req.earlyoptions["config"]:
             raise error.Abort(_("option --config may not be abbreviated!"))
-        if options["cwd"]:
+        if options["cwd"] != req.earlyoptions["cwd"]:
             raise error.Abort(_("option --cwd may not be abbreviated!"))
-        if options["repository"]:
+        if options["repository"] != req.earlyoptions["repository"]:
             raise error.Abort(_(
                 "option -R has to be separated from other options (e.g. not "
                 "-qR) and --repository may only be abbreviated as --repo!"))
+        if options["debugger"] != req.earlyoptions["debugger"]:
+            raise error.Abort(_("option --debugger may not be abbreviated!"))
+        # don't validate --profile/--traceback, which can be enabled from now
 
         if options["encoding"]:
             encoding.encoding = options["encoding"]
@@ -908,7 +987,7 @@
                 except error.RequirementError:
                     raise
                 except error.RepoError:
-                    if rpath and rpath[-1]: # invalid -R path
+                    if rpath: # invalid -R path
                         raise
                     if not func.optionalrepo:
                         if func.inferrepo and args and not path:
--- a/mercurial/localrepo.py	Wed Nov 22 22:18:06 2017 +0800
+++ b/mercurial/localrepo.py	Thu Nov 30 15:48:42 2017 -0500
@@ -1848,58 +1848,8 @@
                 status.modified.extend(status.clean) # mq may commit clean files
 
             # check subrepos
-            subs = []
-            commitsubs = set()
-            newstate = wctx.substate.copy()
-            # only manage subrepos and .hgsubstate if .hgsub is present
-            if '.hgsub' in wctx:
-                # we'll decide whether to track this ourselves, thanks
-                for c in status.modified, status.added, status.removed:
-                    if '.hgsubstate' in c:
-                        c.remove('.hgsubstate')
-
-                # compare current state to last committed state
-                # build new substate based on last committed state
-                oldstate = wctx.p1().substate
-                for s in sorted(newstate.keys()):
-                    if not match(s):
-                        # ignore working copy, use old state if present
-                        if s in oldstate:
-                            newstate[s] = oldstate[s]
-                            continue
-                        if not force:
-                            raise error.Abort(
-                                _("commit with new subrepo %s excluded") % s)
-                    dirtyreason = wctx.sub(s).dirtyreason(True)
-                    if dirtyreason:
-                        if not self.ui.configbool('ui', 'commitsubrepos'):
-                            raise error.Abort(dirtyreason,
-                                hint=_("use --subrepos for recursive commit"))
-                        subs.append(s)
-                        commitsubs.add(s)
-                    else:
-                        bs = wctx.sub(s).basestate()
-                        newstate[s] = (newstate[s][0], bs, newstate[s][2])
-                        if oldstate.get(s, (None, None, None))[1] != bs:
-                            subs.append(s)
-
-                # check for removed subrepos
-                for p in wctx.parents():
-                    r = [s for s in p.substate if s not in newstate]
-                    subs += [s for s in r if match(s)]
-                if subs:
-                    if (not match('.hgsub') and
-                        '.hgsub' in (wctx.modified() + wctx.added())):
-                        raise error.Abort(
-                            _("can't commit subrepos without .hgsub"))
-                    status.modified.insert(0, '.hgsubstate')
-
-            elif '.hgsub' in status.removed:
-                # clean up .hgsubstate when .hgsub is removed
-                if ('.hgsubstate' in wctx and
-                    '.hgsubstate' not in (status.modified + status.added +
-                                          status.removed)):
-                    status.removed.insert(0, '.hgsubstate')
+            subs, commitsubs, newstate = subrepo.precommit(
+                self.ui, wctx, status, match, force=force)
 
             # make sure all explicit patterns are matched
             if not force:
--- a/mercurial/scmutil.py	Wed Nov 22 22:18:06 2017 +0800
+++ b/mercurial/scmutil.py	Thu Nov 30 15:48:42 2017 -0500
@@ -1233,9 +1233,17 @@
 
     def reportsummary(func):
         """decorator for report callbacks."""
-        reporef = weakref.ref(repo)
+        # The repoview life cycle is shorter than the one of the actual
+        # underlying repository. So the filtered object can die before the
+        # weakref is used leading to troubles. We keep a reference to the
+        # unfiltered object and restore the filtering when retrieving the
+        # repository through the weakref.
+        filtername = repo.filtername
+        reporef = weakref.ref(repo.unfiltered())
         def wrapped(tr):
             repo = reporef()
+            if filtername:
+                repo = repo.filtered(filtername)
             func(repo, tr)
         newcat = '%2i-txnreport' % len(categories)
         otr.addpostclose(newcat, wrapped)
--- a/mercurial/subrepo.py	Wed Nov 22 22:18:06 2017 +0800
+++ b/mercurial/subrepo.py	Thu Nov 30 15:48:42 2017 -0500
@@ -293,6 +293,71 @@
     writestate(repo, sm)
     return sm
 
+def precommit(ui, wctx, status, match, force=False):
+    """Calculate .hgsubstate changes that should be applied before committing
+
+    Returns (subs, commitsubs, newstate) where
+    - subs: changed subrepos (including dirty ones)
+    - commitsubs: dirty subrepos which the caller needs to commit recursively
+    - newstate: new state dict which the caller must write to .hgsubstate
+
+    This also updates the given status argument.
+    """
+    subs = []
+    commitsubs = set()
+    newstate = wctx.substate.copy()
+
+    # only manage subrepos and .hgsubstate if .hgsub is present
+    if '.hgsub' in wctx:
+        # we'll decide whether to track this ourselves, thanks
+        for c in status.modified, status.added, status.removed:
+            if '.hgsubstate' in c:
+                c.remove('.hgsubstate')
+
+        # compare current state to last committed state
+        # build new substate based on last committed state
+        oldstate = wctx.p1().substate
+        for s in sorted(newstate.keys()):
+            if not match(s):
+                # ignore working copy, use old state if present
+                if s in oldstate:
+                    newstate[s] = oldstate[s]
+                    continue
+                if not force:
+                    raise error.Abort(
+                        _("commit with new subrepo %s excluded") % s)
+            dirtyreason = wctx.sub(s).dirtyreason(True)
+            if dirtyreason:
+                if not ui.configbool('ui', 'commitsubrepos'):
+                    raise error.Abort(dirtyreason,
+                        hint=_("use --subrepos for recursive commit"))
+                subs.append(s)
+                commitsubs.add(s)
+            else:
+                bs = wctx.sub(s).basestate()
+                newstate[s] = (newstate[s][0], bs, newstate[s][2])
+                if oldstate.get(s, (None, None, None))[1] != bs:
+                    subs.append(s)
+
+        # check for removed subrepos
+        for p in wctx.parents():
+            r = [s for s in p.substate if s not in newstate]
+            subs += [s for s in r if match(s)]
+        if subs:
+            if (not match('.hgsub') and
+                '.hgsub' in (wctx.modified() + wctx.added())):
+                raise error.Abort(_("can't commit subrepos without .hgsub"))
+            status.modified.insert(0, '.hgsubstate')
+
+    elif '.hgsub' in status.removed:
+        # clean up .hgsubstate when .hgsub is removed
+        if ('.hgsubstate' in wctx and
+            '.hgsubstate' not in (status.modified + status.added +
+                                  status.removed)):
+            status.removed.insert(0, '.hgsubstate')
+
+    return subs, commitsubs, newstate
+
 def _updateprompt(ui, sub, dirty, local, remote):
     if dirty:
         msg = (_(' subrepository sources for %s differ\n'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-amend-subrepo.t	Thu Nov 30 15:48:42 2017 -0500
@@ -0,0 +1,154 @@
+#testcases obsstore-off obsstore-on
+
+  $ cat << EOF >> $HGRCPATH
+  > [extensions]
+  > amend =
+  > EOF
+
+#if obsstore-on
+  $ cat << EOF >> $HGRCPATH
+  > [experimental]
+  > evolution.createmarkers = True
+  > EOF
+#endif
+
+Prepare parent repo
+-------------------
+
+  $ hg init r
+  $ cd r
+
+  $ echo a > a
+  $ hg ci -Am0
+  adding a
+
+Link first subrepo
+------------------
+
+  $ echo 's = s' >> .hgsub
+  $ hg add .hgsub
+  $ hg init s
+
+amend without .hgsub
+
+  $ hg amend s
+  abort: can't commit subrepos without .hgsub
+  [255]
+
+amend with subrepo
+
+  $ hg amend
+  saved backup bundle to * (glob) (obsstore-off !)
+  $ hg status --change .
+  A .hgsub
+  A .hgsubstate
+  A a
+  $ cat .hgsubstate
+  0000000000000000000000000000000000000000 s
+
+Update subrepo
+--------------
+
+add new commit to be amended
+
+  $ echo a >> a
+  $ hg ci -m1
+
+amend with dirty subrepo
+
+  $ echo a >> s/a
+  $ hg add -R s
+  adding s/a
+  $ hg amend
+  abort: uncommitted changes in subrepository "s"
+  (use --subrepos for recursive commit)
+  [255]
+
+amend with modified subrepo
+
+  $ hg ci -R s -m0
+  $ hg amend
+  saved backup bundle to * (glob) (obsstore-off !)
+  $ hg status --change .
+  M .hgsubstate
+  M a
+  $ cat .hgsubstate
+  f7b1eb17ad24730a1651fccd46c43826d1bbc2ac s
+
+revert subrepo change
+
+  $ hg up -R s -q null
+  $ hg amend
+  saved backup bundle to * (glob) (obsstore-off !)
+  $ hg status --change .
+  M a
+
+Link another subrepo
+--------------------
+
+add new commit to be amended
+
+  $ echo b >> b
+  $ hg ci -qAm2
+
+also checks if non-subrepo change is included
+
+  $ echo a >> a
+
+amend with another subrepo
+
+  $ hg init t
+  $ echo b >> t/b
+  $ hg ci -R t -Am0
+  adding b
+  $ echo 't = t' >> .hgsub
+  $ hg amend
+  saved backup bundle to * (glob) (obsstore-off !)
+  $ hg status --change .
+  M .hgsub
+  M .hgsubstate
+  M a
+  A b
+  $ cat .hgsubstate
+  0000000000000000000000000000000000000000 s
+  bfb1a4fb358498a9533dabf4f2043d94162f1fcd t
+
+Unlink one subrepo
+------------------
+
+add new commit to be amended
+
+  $ echo a >> a
+  $ hg ci -m3
+
+amend with one subrepo dropped
+
+  $ echo 't = t' > .hgsub
+  $ hg amend
+  saved backup bundle to * (glob) (obsstore-off !)
+  $ hg status --change .
+  M .hgsub
+  M .hgsubstate
+  M a
+  $ cat .hgsubstate
+  bfb1a4fb358498a9533dabf4f2043d94162f1fcd t
+
+Unlink subrepos completely
+--------------------------
+
+add new commit to be amended
+
+  $ echo a >> a
+  $ hg ci -m3
+
+amend with .hgsub removed
+
+  $ hg rm .hgsub
+  $ hg amend
+  saved backup bundle to * (glob) (obsstore-off !)
+  $ hg status --change .
+  M a
+  R .hgsub
+  R .hgsubstate
+
+  $ cd ..
--- a/tests/test-amend.t	Wed Nov 22 22:18:06 2017 +0800
+++ b/tests/test-amend.t	Thu Nov 30 15:48:42 2017 -0500
@@ -235,3 +235,97 @@
   |
   o  A
   
+
+More complete test for status changes (issue5732)
+-------------------------------------------------
+
+Generates history of files having 3 states, r0_r1_wc:
+
+ r0: ground (content/missing)
+ r1: old state to be amended (content/missing, where missing means removed)
+ wc: changes to be included in r1 (content/missing-tracked/untracked)
+
+  $ hg init $TESTTMP/wcstates
+  $ cd $TESTTMP/wcstates
+
+  $ $PYTHON $TESTDIR/generate-working-copy-states.py state 2 1
+  $ hg addremove -q --similarity 0
+  $ hg commit -m0
+
+  $ $PYTHON $TESTDIR/generate-working-copy-states.py state 2 2
+  $ hg addremove -q --similarity 0
+  $ hg commit -m1
+
+  $ $PYTHON $TESTDIR/generate-working-copy-states.py state 2 wc
+  $ hg addremove -q --similarity 0
+  $ hg forget *_*_*-untracked
+  $ rm *_*_missing-*
+
+amend r1 to include wc changes
+
+  $ hg amend
+  saved backup bundle to * (glob) (obsstore-off !)
+
+clean/modified/removed/added states of the amended revision
+
+  $ hg status --all --change . 'glob:content1_*_content1-tracked'
+  C content1_content1_content1-tracked
+  C content1_content2_content1-tracked
+  C content1_missing_content1-tracked
+  $ hg status --all --change . 'glob:content1_*_content[23]-tracked'
+  M content1_content1_content3-tracked
+  M content1_content2_content2-tracked
+  M content1_content2_content3-tracked
+  M content1_missing_content3-tracked
+  $ hg status --all --change . 'glob:content1_*_missing-tracked'
+  M content1_content2_missing-tracked
+  R content1_missing_missing-tracked
+  C content1_content1_missing-tracked
+  $ hg status --all --change . 'glob:content1_*_*-untracked'
+  R content1_content1_content1-untracked
+  R content1_content1_content3-untracked
+  R content1_content1_missing-untracked
+  R content1_content2_content1-untracked
+  R content1_content2_content2-untracked
+  R content1_content2_content3-untracked
+  R content1_content2_missing-untracked
+  R content1_missing_content1-untracked
+  R content1_missing_content3-untracked
+  R content1_missing_missing-untracked
+  $ hg status --all --change . 'glob:missing_content2_*'
+  A missing_content2_content2-tracked
+  A missing_content2_content3-tracked
+  A missing_content2_missing-tracked
+  $ hg status --all --change . 'glob:missing_missing_*'
+  A missing_missing_content3-tracked
+
+working directory should be all clean (with some missing/untracked files)
+
+  $ hg status --all 'glob:*_content?-tracked'
+  C content1_content1_content1-tracked
+  C content1_content1_content3-tracked
+  C content1_content2_content1-tracked
+  C content1_content2_content2-tracked
+  C content1_content2_content3-tracked
+  C content1_missing_content1-tracked
+  C content1_missing_content3-tracked
+  C missing_content2_content2-tracked
+  C missing_content2_content3-tracked
+  C missing_missing_content3-tracked
+  $ hg status --all 'glob:*_missing-tracked'
+  ! content1_content1_missing-tracked
+  ! content1_content2_missing-tracked
+  ! content1_missing_missing-tracked
+  ! missing_content2_missing-tracked
+  ! missing_missing_missing-tracked
+  $ hg status --all 'glob:*-untracked'
+  ? content1_content1_content1-untracked
+  ? content1_content1_content3-untracked
+  ? content1_content2_content1-untracked
+  ? content1_content2_content2-untracked
+  ? content1_content2_content3-untracked
+  ? content1_missing_content1-untracked
+  ? content1_missing_content3-untracked
+  ? missing_content2_content2-untracked
+  ? missing_content2_content3-untracked
+  ? missing_missing_content3-untracked
--- a/tests/test-blackbox.t	Wed Nov 22 22:18:06 2017 +0800
+++ b/tests/test-blackbox.t	Thu Nov 30 15:48:42 2017 -0500
@@ -19,7 +19,7 @@
   1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> init blackboxtest exited 0 after * seconds (glob)
   1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> add a
   1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> add a exited 0 after * seconds (glob)
-  1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000+ (5000)> blackbox
+  1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000+ (5000)> blackbox --config *blackbox.dirty=True* (glob)
 
 alias expansion is logged
   $ rm ./.hg/blackbox.log
--- a/tests/test-bookmarks-pushpull.t	Wed Nov 22 22:18:06 2017 +0800
+++ b/tests/test-bookmarks-pushpull.t	Thu Nov 30 15:48:42 2017 -0500
@@ -261,7 +261,7 @@
      Z                         1:0d2164f0ce0d
 
   $ cd ../b
-  $ hg up --config
+  $ hg up
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   updating bookmark foobar
   $ echo c2 > f2
--- a/tests/test-dispatch.t	Wed Nov 22 22:18:06 2017 +0800
+++ b/tests/test-dispatch.t	Thu Nov 30 15:48:42 2017 -0500
@@ -30,6 +30,89 @@
   (use 'hg cat -h' to show more help)
   [255]
 
+Missing parameter for early option:
+
+  $ hg log -R 2>&1 | grep 'hg log'
+  hg log: option -R requires argument
+  hg log [OPTION]... [FILE]
+  (use 'hg log -h' to show more help)
+
+  $ hg log -R -- 2>&1 | grep 'hg log'
+  hg log: option -R requires argument
+  hg log [OPTION]... [FILE]
+  (use 'hg log -h' to show more help)
+
+Parsing of early options should stop at "--":
+
+  $ hg cat -- --config=hooks.pre-cat=false
+  --config=hooks.pre-cat=false: no such file in rev cb9a9f314b8b
+  [1]
+  $ hg cat -- --debugger
+  --debugger: no such file in rev cb9a9f314b8b
+  [1]
+
+Unparsable form of early options:
+
+  $ hg cat --debugg
+  abort: option --debugger may not be abbreviated!
+  [255]
+
+Parsing failure of early options should be detected before executing the
+command:
+
+  $ hg log -b '--config=hooks.pre-log=false' default
+  abort: option --config may not be abbreviated!
+  [255]
+  $ hg log -b -R. default
+  abort: option -R has to be separated from other options (e.g. not -qR) and --repository may only be abbreviated as --repo!
+  [255]
+  $ hg log --cwd .. -b --cwd=. default
+  abort: option --cwd may not be abbreviated!
+  [255]
+
+However, we can't prevent it from loading extensions and configs:
+
+  $ cat <<EOF > bad.py
+  > raise Exception('bad')
+  > EOF
+  $ hg log -b '--config=extensions.bad=bad.py' default
+  *** failed to import extension bad from bad.py: bad
+  abort: option --config may not be abbreviated!
+  [255]
+
+  $ mkdir -p badrepo/.hg
+  $ echo 'invalid-syntax' > badrepo/.hg/hgrc
+  $ hg log -b -Rbadrepo default
+  hg: parse error at badrepo/.hg/hgrc:1: invalid-syntax
+  [255]
+
+  $ hg log -b --cwd=inexistent default
+  abort: No such file or directory: 'inexistent'
+  [255]
+
+  $ hg log -b '--config=ui.traceback=yes' 2>&1 | grep '^Traceback'
+  Traceback (most recent call last):
+  $ hg log -b '--config=profiling.enabled=yes' 2>&1 | grep -i sample
+  Sample count: .*|No samples recorded\. (re)
+
+Early options can't be specified in [aliases] and [defaults] because they are
+applied before the command name is resolved:
+
+  $ hg log -b '--config=alias.log=log --config=hooks.pre-log=false'
+  hg log: option -b not recognized
+  error in definition for alias 'log': --config may only be given on the command
+  line
+  [255]
+
+  $ hg log -b '--config=defaults.log=--config=hooks.pre-log=false'
+  abort: option --config may not be abbreviated!
+  [255]
+
+Shell aliases bypass any command parsing rules but for the early one:
+
+  $ hg log -b '--config=alias.log=!echo howdy'
+  howdy
+
 [defaults]
 
   $ hg cat a
--- a/tests/test-lfconvert.t	Wed Nov 22 22:18:06 2017 +0800
+++ b/tests/test-lfconvert.t	Thu Nov 30 15:48:42 2017 -0500
@@ -233,9 +233,10 @@
   $ cd ..
 
 round-trip: converting back to a normal (non-largefiles) repo with
-"lfconvert --to-normal" should give the same as ../bigfile-repo
+"lfconvert --to-normal" should give the same as ../bigfile-repo.  The
+convert extension is disabled to show config items can be loaded without it.
   $ cd largefiles-repo
-  $ hg lfconvert --to-normal . ../normal-repo
+  $ hg --config extensions.convert=! lfconvert --to-normal . ../normal-repo
   initializing destination ../normal-repo
   0 additional largefiles cached
   scanning source...
--- a/tests/test-merge-subrepos.t	Wed Nov 22 22:18:06 2017 +0800
+++ b/tests/test-merge-subrepos.t	Thu Nov 30 15:48:42 2017 -0500
@@ -61,7 +61,7 @@
   9bfe45a197d7+ tip
   $ cat .hg/blackbox.log
   * @9bfe45a197d7b0ab09bf287729dd57e9619c9da5+ (*)> serve --cmdserver chgunix * (glob) (chg !)
-  * @9bfe45a197d7b0ab09bf287729dd57e9619c9da5+ (*)> id (glob)
+  * @9bfe45a197d7b0ab09bf287729dd57e9619c9da5+ (*)> id --config *extensions.blackbox=* --config *blackbox.dirty=True* (glob)
   * @9bfe45a197d7b0ab09bf287729dd57e9619c9da5+ (*)> id --config *extensions.blackbox=* --config *blackbox.dirty=True* exited 0 * (glob)
 
 TODO: a deleted file should be listed as such, like the top level repo
--- a/tests/test-setdiscovery.t	Wed Nov 22 22:18:06 2017 +0800
+++ b/tests/test-setdiscovery.t	Thu Nov 30 15:48:42 2017 -0500
@@ -17,7 +17,7 @@
   >     hg -R a debugdiscovery b --verbose --debug --config progress.debug=true
   >     echo
   >     echo "% -- b -> a tree"
-  >     hg -R b debugdiscovery a --verbose --old --config
+  >     hg -R b debugdiscovery a --verbose --old
   >     echo
   >     echo "% -- b -> a set"
   >     hg -R b debugdiscovery a --verbose --debug --config progress.debug=true
@@ -406,8 +406,8 @@
   101 102 103 104 105 106 107 108 109 110  (no-eol)
   $ hg -R r1 --config extensions.blackbox= blackbox
   * @5d0b986a083e0d91f116de4691e2aaa54d5bbec0 (*)> serve --cmdserver chgunix * (glob) (chg !)
-  * @5d0b986a083e0d91f116de4691e2aaa54d5bbec0 (*)> outgoing r2 *-T{rev} * (glob)
+  * @5d0b986a083e0d91f116de4691e2aaa54d5bbec0 (*)> -R r1 outgoing r2 *-T{rev} * --config *extensions.blackbox=* (glob)
   * @5d0b986a083e0d91f116de4691e2aaa54d5bbec0 (*)> found 101 common and 1 unknown server heads, 2 roundtrips in *.????s (glob)
   * @5d0b986a083e0d91f116de4691e2aaa54d5bbec0 (*)> -R r1 outgoing r2 *-T{rev} * --config *extensions.blackbox=* exited 0 after *.?? seconds (glob)
-  * @5d0b986a083e0d91f116de4691e2aaa54d5bbec0 (*)> blackbox (glob)
+  * @5d0b986a083e0d91f116de4691e2aaa54d5bbec0 (*)> -R r1 --config *extensions.blackbox=* blackbox (glob)
   $ cd ..