Re: [PATCH] commands: add short option `-H` for `--hidden`

2020-07-17 Thread Manuel Jacob

I’m sorry for the non-optimal form and timing.

This was meant as an RFC patch. That’s why it contains no tests. It 
should have been flagged as such.


Now is probably not a good time for RFC patches. I was aware that RFC 
patches should not be sent after the freeze. That’s why I kinda rushed 
it before the freeze. As a discussion about a global option could easily 
extend until after the freeze, this is a violation of the spirit of that 
rule (getting everyone focused).


I’ll bring this up again after the release.


On 2020-07-17 20:50, Manuel Jacob wrote:

# HG changeset patch
# User Manuel Jacob 
# Date 1595011777 -7200
#  Fri Jul 17 20:49:37 2020 +0200
# Node ID 91ac61b56b6ed95d9f62ba3615e8b160e6be8d9b
# Parent  a37f290a71240b851f5df900833f848efbab576a
# EXP-Topic hidden-shortcut
commands: add short option `-H` for `--hidden`

When digging in history, I have to use `--hidden` a lot. Therefore it 
would be a

major timesaver for me to have a short option for that.

I couldn’t think of another single letter that makes sense. Since `-h` 
is

already taken for `--help`, I decided for `-H`.

diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -137,7 +137,7 @@
 (b'', b'profile', None, _(b'print command execution profile')),
 (b'', b'version', None, _(b'output version information and 
exit')),

 (b'h', b'help', None, _(b'display help and exit')),
-(b'', b'hidden', False, _(b'consider hidden changesets')),
+(b'H', b'hidden', False, _(b'consider hidden changesets')),
 (
 b'',
 b'pager',
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel

___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH] commands: add short option `-H` for `--hidden`

2020-07-17 Thread Manuel Jacob
# HG changeset patch
# User Manuel Jacob 
# Date 1595011777 -7200
#  Fri Jul 17 20:49:37 2020 +0200
# Node ID 91ac61b56b6ed95d9f62ba3615e8b160e6be8d9b
# Parent  a37f290a71240b851f5df900833f848efbab576a
# EXP-Topic hidden-shortcut
commands: add short option `-H` for `--hidden`

When digging in history, I have to use `--hidden` a lot. Therefore it would be a
major timesaver for me to have a short option for that.

I couldn’t think of another single letter that makes sense. Since `-h` is
already taken for `--help`, I decided for `-H`.

diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -137,7 +137,7 @@
 (b'', b'profile', None, _(b'print command execution profile')),
 (b'', b'version', None, _(b'output version information and exit')),
 (b'h', b'help', None, _(b'display help and exit')),
-(b'', b'hidden', False, _(b'consider hidden changesets')),
+(b'H', b'hidden', False, _(b'consider hidden changesets')),
 (
 b'',
 b'pager',
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D8765: absorb: improve message for the case when changeset became empty

2020-07-17 Thread mjacob (Manuel Jacob)
mjacob created this revision.
Herald added a reviewer: hg-reviewers.
Herald added a subscriber: mercurial-patches.

REVISION SUMMARY
  In changeset f55099982bc5 
, I 
introduced the message "became empty and became
  ...", which I was never very happy with. Raphaël Gomès suggested "became empty
  as ...". That sounds much nicer.

REPOSITORY
  rHG Mercurial

BRANCH
  default

REVISION DETAIL
  https://phab.mercurial-scm.org/D8765

AFFECTED FILES
  hgext/absorb.py
  tests/test-absorb.t

CHANGE DETAILS

diff --git a/tests/test-absorb.t b/tests/test-absorb.t
--- a/tests/test-absorb.t
+++ b/tests/test-absorb.t
@@ -530,8 +530,8 @@
   $ hg absorb -av --config rewrite.empty-successor=keep | grep became
   0:bfafb49242db: 1 file(s) changed, became 5:1a2de97fc652
   1:115485984805: 2 file(s) changed, became 6:0c930dfab74c
-  2:30970dbf7b40: 2 file(s) changed, became empty and became 7:df6574ae635c
-  3:a393a58b9a85: 2 file(s) changed, became empty and became 8:ad4bd3462c9e
+  2:30970dbf7b40: 2 file(s) changed, became empty as 7:df6574ae635c
+  3:a393a58b9a85: 2 file(s) changed, became empty as 8:ad4bd3462c9e
   4:1bb0e8cff87a: 2 file(s) changed, became 9:2dbed75af996
   $ hg log -T '{rev} {desc}\n' -Gp
   @  9 empty
diff --git a/hgext/absorb.py b/hgext/absorb.py
--- a/hgext/absorb.py
+++ b/hgext/absorb.py
@@ -798,10 +798,7 @@
 self.replacemap[ctx.node()] = lastcommitted.node()
 if memworkingcopy:
 if willbecomenoop:
-msg = _(
-b'%d file(s) changed, became empty '
-b'and became %s'
-)
+msg = _(b'%d file(s) changed, became empty as %s')
 else:
 msg = _(b'%d file(s) changed, became %s')
 msg = msg % (



To: mjacob, #hg-reviewers
Cc: mercurial-patches, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D8353: debugcommands: create new debugantivirusrunning command

2020-07-17 Thread durin42 (Augie Fackler)
Closed by commit rHG87047efbc6a6: debugcommands: create new 
debugantivirusrunning command (authored by durin42).
This revision was automatically updated to reflect the committed changes.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D8353?vs=21426=21955

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8353/new/

REVISION DETAIL
  https://phab.mercurial-scm.org/D8353

AFFECTED FILES
  mercurial/debugcommands.py
  tests/test-completion.t
  tests/test-help.t

CHANGE DETAILS

diff --git a/tests/test-help.t b/tests/test-help.t
--- a/tests/test-help.t
+++ b/tests/test-help.t
@@ -971,6 +971,8 @@
   
debugancestor
  find the ancestor revision of two revisions in a given index
+   debugantivirusrunning
+ attempt to trigger an antivirus scanner to see if one is 
active
debugapplystreamclonebundle
  apply a stream clone bundle file
debugbackupbundle
diff --git a/tests/test-completion.t b/tests/test-completion.t
--- a/tests/test-completion.t
+++ b/tests/test-completion.t
@@ -74,6 +74,7 @@
 Show debug commands if there are no other candidates
   $ hg debugcomplete debug
   debugancestor
+  debugantivirusrunning
   debugapplystreamclonebundle
   debugbackupbundle
   debugbuilddag
@@ -261,6 +262,7 @@
   continue: dry-run
   copy: forget, after, at-rev, force, include, exclude, dry-run
   debugancestor: 
+  debugantivirusrunning: 
   debugapplystreamclonebundle: 
   debugbackupbundle: recover, patch, git, limit, no-merges, stat, graph, 
style, template
   debugbuilddag: mergeable-file, overwritten-file, new-file
diff --git a/mercurial/debugcommands.py b/mercurial/debugcommands.py
--- a/mercurial/debugcommands.py
+++ b/mercurial/debugcommands.py
@@ -127,6 +127,23 @@
 ui.write(b'%d:%s\n' % (r.rev(a), hex(a)))
 
 
+@command(b'debugantivirusrunning', [])
+def debugantivirusrunning(ui, repo):
+"""attempt to trigger an antivirus scanner to see if one is active"""
+with repo.cachevfs.open('eicar-test-file.com', b'wb') as f:
+f.write(
+util.b85decode(
+# This is a base85-armored version of the EICAR test file. See
+# https://en.wikipedia.org/wiki/EICAR_test_file for details.
+b'ST#=}P$fV?P+K%yP+C|uG$>GBDK|qyDK~v2MM*https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 2 of 2 rebased] exchange: check actually missing revs for obsolete / unstable revs (issue6372)

2020-07-17 Thread Pulkit Goyal
On Fri, Jul 17, 2020 at 6:15 PM Manuel Jacob  wrote:
>
> # HG changeset patch
> # User Manuel Jacob 
> # Date 1594966891 -7200
> #  Fri Jul 17 08:21:31 2020 +0200
> # Node ID b5983bd8811e77fc82e7c7fbe3f602ab3e90852a
> # Parent  6284dfa728899a6385361d59ba95d9c3d137a5e6
> # EXP-Topic issue6372
> exchange: check actually missing revs for obsolete / unstable revs (issue6372)
>
> The previous code was using `outgoing.ancestorsof`, which was originally 
> called
> `outgoing.missingheads` although not containing the missing heads. This
> confusion was probably the reason why the buggy code was written.
>
> The actually outgoing changesets are stored in `outgoing.missing`. By checking
> all outgoing changesets, we avoid the problem and can show the list of all
> obsolete or unstable changesets, which is more helpful for the user.

Queuing these. Thanks a lot!
>
> diff --git a/mercurial/exchange.py b/mercurial/exchange.py
> --- a/mercurial/exchange.py
> +++ b/mercurial/exchange.py
> @@ -905,27 +905,32 @@
>  # if repo.obsstore == False --> no obsolete
>  # then, save the iteration
>  if unfi.obsstore:
> -# this message are here for 80 char limit reason
> -mso = _(b"push includes obsolete changeset: %s!")
> -mspd = _(b"push includes phase-divergent changeset: %s!")
> -mscd = _(b"push includes content-divergent changeset: %s!")
> -mst = {
> -b"orphan": _(b"push includes orphan changeset: %s!"),
> -b"phase-divergent": mspd,
> -b"content-divergent": mscd,
> -}
> -# If we are to push if there is at least one
> -# obsolete or unstable changeset in missing, at
> -# least one of the missinghead will be obsolete or
> -# unstable. So checking heads only is ok
> -for node in outgoing.ancestorsof:
> +obsoletes = []
> +unstables = []
> +for node in outgoing.missing:
>  ctx = unfi[node]
>  if ctx.obsolete():
> -raise error.Abort(mso % ctx)
> +obsoletes.append(ctx)
>  elif ctx.isunstable():
> -# TODO print more than one instability in the abort
> -# message
> -raise error.Abort(mst[ctx.instabilities()[0]] % ctx)
> +unstables.append(ctx)
> +if obsoletes or unstables:
> +msg = b""
> +if obsoletes:
> +msg += _(b"push includes obsolete changesets:\n")
> +msg += b"\n".join(b'  %s' % ctx for ctx in obsoletes)
> +if unstables:
> +if msg:
> +msg += b"\n"
> +msg += _(b"push includes unstable changesets:\n")
> +msg += b"\n".join(
> +b'  %s (%s)'
> +% (
> +ctx,
> +b", ".join(_(ins) for ins in 
> ctx.instabilities()),
> +)
> +for ctx in unstables
> +)
> +raise error.Abort(msg)
>
>  discovery.checkheads(pushop)
>  return True
> diff --git a/tests/test-obsolete-divergent.t b/tests/test-obsolete-divergent.t
> --- a/tests/test-obsolete-divergent.t
> +++ b/tests/test-obsolete-divergent.t
> @@ -118,7 +118,9 @@
>$ hg push ../other
>pushing to ../other
>searching for changes
> -  abort: push includes content-divergent changeset: 392fd25390da!
> +  abort: push includes unstable changesets:
> +82623d38b9ba (content-divergent)
> +392fd25390da (content-divergent)
>[255]
>
>$ cd ..
> diff --git a/tests/test-obsolete.t b/tests/test-obsolete.t
> --- a/tests/test-obsolete.t
> +++ b/tests/test-obsolete.t
> @@ -251,7 +251,8 @@
>$ hg push ../tmpa
>pushing to ../tmpa
>searching for changes
> -  abort: push includes phase-divergent changeset: 5601fb93a350!
> +  abort: push includes unstable changesets:
> +5601fb93a350 (phase-divergent)
>[255]
>
>  Fixing "bumped" situation
> @@ -616,7 +617,8 @@
>$ hg push ../tmpc/ -r 'desc("original_d")'
>pushing to ../tmpc/
>searching for changes
> -  abort: push includes obsolete changeset: 94b33453f93b!
> +  abort: push includes obsolete changesets:
> +94b33453f93b
>[255]
>
>  refuse to push unstable changeset
> @@ -624,7 +626,10 @@
>$ hg push ../tmpc/
>pushing to ../tmpc/
>searching for changes
> -  abort: push includes orphan changeset: cda648ca50f5!
> +  abort: push includes obsolete changesets:
> +94b33453f93b
> +  push includes unstable changesets:
> +cda648ca50f5 (orphan)
>[255]
>
>  with --force it will work anyway
> @@ -647,6 +652,26 @@
>no changes found
>[1]
>
> +pushing should work even if the outgoing changes contain an unrelated 
> 

Heptapod news: doc sprint, versions 0.14 and 0.15

2020-07-17 Thread Georges Racinet
Hello everybody,

Here are some news about Heptapod, the friendly fork of GitLab Community
Edition supporting Mercurial.

== Documentation virtual sprint ==

    We're organizing an informal single day sprint about documentation
and user messages. It will happen on the last week of July and doesn't
require a full developer setup.

    There is a poll to choose the exact date at
https://framadate.org/heptapod-vsprint-2020-07

    Everybody is welcome to join us on https://mattermost.heptapod.net.
The event will be on an European time zone, but don't hesitate to attend
even if you can only be there for a couple of hours.

    We intend to make more such virtual sprints in the future and we're
open to set them in other time zones if there are enough interested
attendees.

== Current Heptapod 0.14 is based on a supported GitLab version ==

    Since version 0.14.0 (released on June, 30th), Heptapod has been
running on top of the currently supported GitLab 12.10. With Python 3.8,
Mercurial 5.4 and hg-evolve 10.0, I'm glad to say there is currently
only supported software in Heptapod by default.

    More details at
https://heptapod.net/heptapod-0.14.0.html#heptapod-0.14.0

    Today saw the release of Heptapod 0.14.2, featuring in particular
Mercurial 5.4.2 and GitLab 12.10.14.

    The community instance for Free and Open Source Software
(foss.heptapod.net) and the commercial service (heptapod.host) are both
running 0.14.2,

== Heptapod 0.15 around the corner ==

    GitLab 12.10 will reach its end of life on 2020-07-22 (next
Wednesday), so we have to hurry up for next version: Heptapod 0.15 will
be based on GitLab 13.1, whose end of life is 2020-09-22.

    In fact, 0.15.0rc1 was scheduled for today, but I've decided to play
safe and postpone it to the beginning of next week.

    We'll probably stay a few days on GitLab 12.10 after it becomes
obsolete. Once Heptapod 0.15 is out, we'll have almost two months of
stability, during which we'll turn ourselves a bit more towards
Mercurial features and user experience improvements.

Best,

-- 
Georges Racinet
https://octobus.net, https://about.heptapod.host, https://heptapod.net
GPG: BF5456F4DC625443849B6E58EE20CA44EF691D39, sur serveurs publics




signature.asc
Description: OpenPGP digital signature
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D8764: localrepo: deduplicate code around reading requires file

2020-07-17 Thread pulkit (Pulkit Goyal)
pulkit created this revision.
Herald added a reviewer: hg-reviewers.
Herald added a subscriber: mercurial-patches.

REPOSITORY
  rHG Mercurial

BRANCH
  default

REVISION DETAIL
  https://phab.mercurial-scm.org/D8764

AFFECTED FILES
  mercurial/localrepo.py

CHANGE DETAILS

diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -522,17 +522,21 @@
 
 raise error.RepoError(_(b'repository %s not found') % path)
 
+def _readrequires(vfs):
+try:
+requirements = set(vfs.read(b'requires').splitlines())
+except IOError as e:
+if e.errno != errno.ENOENT:
+raise
+requirements = set()
+return requirements
+
 # .hg/requires file contains a newline-delimited list of
 # features/capabilities the opener (us) must have in order to use
 # the repository. This file was introduced in Mercurial 0.9.2,
 # which means very old repositories may not have one. We assume
 # a missing file translates to no requirements.
-try:
-requirements = set(hgvfs.read(b'requires').splitlines())
-except IOError as e:
-if e.errno != errno.ENOENT:
-raise
-requirements = set()
+requirements = _readrequires(hgvfs)
 
 # if .hg/requires contains the sharesafe requirement, it means
 # there exists a `.hg/store/requires` too and we should read it
@@ -545,12 +549,7 @@
 storevfs = vfsmod.vfs(vfsmod.vfs(sharedpath).join(b'store'))
 else:
 storevfs = vfsmod.vfs(hgvfs.join(b'store'), cacheaudited=True)
-try:
-store_requirements = set(storevfs.read(b'requires').splitlines())
-requirements |= store_requirements
-except IOError as e:
-if e.errno != errno.ENOENT:
-raise
+requirements |= _readrequires(storevfs)
 
 # The .hg/hgrc file may load extensions or contain config options
 # that influence repository construction. Attempt to load it and



To: pulkit, #hg-reviewers
Cc: mercurial-patches, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH] windows: handle file-like objects without isatty() method

2020-07-17 Thread Manuel Jacob
# HG changeset patch
# User Manuel Jacob 
# Date 1594990702 -7200
#  Fri Jul 17 14:58:22 2020 +0200
# Node ID aa6621ba3a4871256c15bb7b87e8e5dfe940ad0f
# Parent  a37f290a71240b851f5df900833f848efbab576a
# EXP-Topic winstdout
windows: handle file-like objects without isatty() method

Copying the function is not nice, but moving around stuff to avoid the
circular import didn’t seem to be worth the effort.

diff --git a/mercurial/windows.py b/mercurial/windows.py
--- a/mercurial/windows.py
+++ b/mercurial/windows.py
@@ -186,6 +186,14 @@
 listdir = osutil.listdir
 
 
+# copied from .utils.procutil, remove after Python 2 support was dropped
+def _isatty(fp):
+try:
+return fp.isatty()
+except AttributeError:
+return False
+
+
 class winstdout(object):
 '''Some files on Windows misbehave.
 
@@ -197,7 +205,7 @@
 
 def __init__(self, fp):
 self.fp = fp
-self.throttle = not pycompat.ispy3 and fp.isatty()
+self.throttle = not pycompat.ispy3 and _isatty(fp)
 
 def __getattr__(self, key):
 return getattr(self.fp, key)
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 4 of 4] windows: always work around EINVAL in case of broken pipe for stdout / stderr

2020-07-17 Thread Manuel Jacob

On 2020-07-17 13:24, Yuya Nishihara wrote:

On Fri, 17 Jul 2020 04:38:50 +0200, Manuel Jacob wrote:

# HG changeset patch
# User Manuel Jacob 
# Date 1594949332 -7200
#  Fri Jul 17 03:28:52 2020 +0200
# Node ID 741837f160677ec24154b3d5aa209133a3872d53
# Parent  91f6d0508acac2c8eb0fbf8864528f8f584e697c
# EXP-Topic stdio-broken_pipe
windows: always work around EINVAL in case of broken pipe for stdout / 
stderr


Queued, thanks.


diff --git a/mercurial/windows.py b/mercurial/windows.py
--- a/mercurial/windows.py
+++ b/mercurial/windows.py
@@ -197,6 +197,7 @@

 def __init__(self, fp):
 self.fp = fp
+self.throttle = not pycompat.ispy3 and fp.isatty()


If we need to handle the case where sys.stdout is a pseudo file object 
on

Python 2, isatty() may be missing.


Right, I’ll send another patch. Feel free to fold them together.


 def write(self, s):
+if not pycompat.ispy3:
+self.softspace = 0


No idea what this softspace is for, but I assume it's py2-only 
attribute.


It’s an obscure implementation artifact of the Python 2 print function: 
https://docs.python.org/2/library/stdtypes.html#file.softspace


I tried to not change the behavior of the existing code on Python 2. 
However, reading from the documentation, it is likely that removing that 
code makes it more correct that leaving it. Also, I think we don’t use 
the Python 2 print function ourselves. Should we remove the two lines?

___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH]: [Bug 6373] py3 support for popen on windows vs cmdbuilder

2020-07-17 Thread Александр Литягин

The encoding of user arguments is unknown, but maybe using a.decode("mbcs")

is better since the other hgclient APIs would expect an MBCS-encoded bytes
on Windows.

https://www.mercurial-scm.org/repo/hg/file/5.4/mercurial/pycompat.py#l174

And we might also want to leverage the encoding parameter if specified:

def init(dest=None, ssh=None, remotecmd=None, insecure=False,
 encoding=None, configs=None):
args = util.cmdbuilder('init', ...)
args = util.tonativeargs(args, encoding=encoding)
...
proc = util.popen(args)



There some legacy code alredy have. so, `util.tonativeargs(args, 
encoding=encoding) ` - fine, but somebody can use


`cmdbuilder` and `popen` aside. Their code should keep workable, therefore 
better fixup args for subprocess in `popen`.


17.07.2020 14:56, Yuya Nishihara пишет:

On Thu, 16 Jul 2020 23:05:19 +0300, Александр Литягин wrote:

# HG changeset patch
# User alexrayne 
# Date 1557358579 -10800
#  Thu May 09 02:36:19 2019 +0300
# Node ID 856cea175acabd5b8f87319001067a7785c15279
# Parent  33b512aa8dba0cbe523188fbb62d30ae2125a236
!popen:py3 - #6065 subprocess.Popen uses strings args. so, py2 normaly
+def encodes(s, name_or_codec, *args, **kwargs):
+    if s is None:
+    return [];
+    if (isinstance(name_or_codec, string_types)):
+    codec = codecs.lookup(name_or_codec)
+    else:
+    codec = name_or_codec
+    r = []
+    for arg in s:
+    if (isinstance(arg, string_types)):
+    rv, length = codec.encode(arg, *args, **kwargs)
+    r.append(rv)
+    else:
+    r.append(arg)
+    return r

Unused.


+def decodes(s, name_or_codec, *args, **kwargs):
+    if (isinstance(name_or_codec, string_types)):
+    codec = codecs.lookup(name_or_codec)
+    else:
+    codec = name_or_codec
+    if s is None:
+    return [];
+    r = []
+    for arg in s:
+    if (isinstance(arg, bytes)):
+    rv, length = codec.decode(arg, *args, **kwargs)
+    if not isinstance(rv, (str, bytes, bytearray)):
+    raise TypeError('Not a string or byte codec')
+    r.append(rv)
+    else:
+    r.append(arg)
+    return r
+
+if (sys.version_info[0] >= 3) and (os.name == 'nt') :
+    def _fix_encoding_args(a):
+    #py3 Popen accepts str args
+    encoding = get_encoding() or 'UTF-8'
+    argcodec = codecs.lookup(encoding)

I think there's no need to look up codec object.


+    return decodes( a, argcodec ) #get_encoding()
+else:
+    def _fix_encoding_args(a):
+    #py2 Popen accepts binary_str args
+    return a #encodes(a, argcodec) #a;
+
   def popen(args, env=None):
   environ = None
   if env:
   environ = dict(os.environ)
   environ.update(env)

-    return subprocess.Popen(args, stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
+    return subprocess.Popen(_fix_encoding_args(args),

The encoding of user arguments is unknown, but maybe using a.decode("mbcs")
is better since the other hgclient APIs would expect an MBCS-encoded bytes
on Windows.

https://www.mercurial-scm.org/repo/hg/file/5.4/mercurial/pycompat.py#l174

And we might also want to leverage the encoding parameter if specified:

def init(dest=None, ssh=None, remotecmd=None, insecure=False,
  encoding=None, configs=None):
 args = util.cmdbuilder('init', ...)
 args = util.tonativeargs(args, encoding=encoding)
 ...
 proc = util.popen(args)



___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 2 of 2 rebased] exchange: check actually missing revs for obsolete / unstable revs (issue6372)

2020-07-17 Thread Manuel Jacob
# HG changeset patch
# User Manuel Jacob 
# Date 1594966891 -7200
#  Fri Jul 17 08:21:31 2020 +0200
# Node ID b5983bd8811e77fc82e7c7fbe3f602ab3e90852a
# Parent  6284dfa728899a6385361d59ba95d9c3d137a5e6
# EXP-Topic issue6372
exchange: check actually missing revs for obsolete / unstable revs (issue6372)

The previous code was using `outgoing.ancestorsof`, which was originally called
`outgoing.missingheads` although not containing the missing heads. This
confusion was probably the reason why the buggy code was written.

The actually outgoing changesets are stored in `outgoing.missing`. By checking
all outgoing changesets, we avoid the problem and can show the list of all
obsolete or unstable changesets, which is more helpful for the user.

diff --git a/mercurial/exchange.py b/mercurial/exchange.py
--- a/mercurial/exchange.py
+++ b/mercurial/exchange.py
@@ -905,27 +905,32 @@
 # if repo.obsstore == False --> no obsolete
 # then, save the iteration
 if unfi.obsstore:
-# this message are here for 80 char limit reason
-mso = _(b"push includes obsolete changeset: %s!")
-mspd = _(b"push includes phase-divergent changeset: %s!")
-mscd = _(b"push includes content-divergent changeset: %s!")
-mst = {
-b"orphan": _(b"push includes orphan changeset: %s!"),
-b"phase-divergent": mspd,
-b"content-divergent": mscd,
-}
-# If we are to push if there is at least one
-# obsolete or unstable changeset in missing, at
-# least one of the missinghead will be obsolete or
-# unstable. So checking heads only is ok
-for node in outgoing.ancestorsof:
+obsoletes = []
+unstables = []
+for node in outgoing.missing:
 ctx = unfi[node]
 if ctx.obsolete():
-raise error.Abort(mso % ctx)
+obsoletes.append(ctx)
 elif ctx.isunstable():
-# TODO print more than one instability in the abort
-# message
-raise error.Abort(mst[ctx.instabilities()[0]] % ctx)
+unstables.append(ctx)
+if obsoletes or unstables:
+msg = b""
+if obsoletes:
+msg += _(b"push includes obsolete changesets:\n")
+msg += b"\n".join(b'  %s' % ctx for ctx in obsoletes)
+if unstables:
+if msg:
+msg += b"\n"
+msg += _(b"push includes unstable changesets:\n")
+msg += b"\n".join(
+b'  %s (%s)'
+% (
+ctx,
+b", ".join(_(ins) for ins in ctx.instabilities()),
+)
+for ctx in unstables
+)
+raise error.Abort(msg)
 
 discovery.checkheads(pushop)
 return True
diff --git a/tests/test-obsolete-divergent.t b/tests/test-obsolete-divergent.t
--- a/tests/test-obsolete-divergent.t
+++ b/tests/test-obsolete-divergent.t
@@ -118,7 +118,9 @@
   $ hg push ../other
   pushing to ../other
   searching for changes
-  abort: push includes content-divergent changeset: 392fd25390da!
+  abort: push includes unstable changesets:
+82623d38b9ba (content-divergent)
+392fd25390da (content-divergent)
   [255]
 
   $ cd ..
diff --git a/tests/test-obsolete.t b/tests/test-obsolete.t
--- a/tests/test-obsolete.t
+++ b/tests/test-obsolete.t
@@ -251,7 +251,8 @@
   $ hg push ../tmpa
   pushing to ../tmpa
   searching for changes
-  abort: push includes phase-divergent changeset: 5601fb93a350!
+  abort: push includes unstable changesets:
+5601fb93a350 (phase-divergent)
   [255]
 
 Fixing "bumped" situation
@@ -616,7 +617,8 @@
   $ hg push ../tmpc/ -r 'desc("original_d")'
   pushing to ../tmpc/
   searching for changes
-  abort: push includes obsolete changeset: 94b33453f93b!
+  abort: push includes obsolete changesets:
+94b33453f93b
   [255]
 
 refuse to push unstable changeset
@@ -624,7 +626,10 @@
   $ hg push ../tmpc/
   pushing to ../tmpc/
   searching for changes
-  abort: push includes orphan changeset: cda648ca50f5!
+  abort: push includes obsolete changesets:
+94b33453f93b
+  push includes unstable changesets:
+cda648ca50f5 (orphan)
   [255]
 
 with --force it will work anyway
@@ -647,6 +652,26 @@
   no changes found
   [1]
 
+pushing should work even if the outgoing changes contain an unrelated changeset
+(neither obsolete nor unstable) (issue6372)
+
+  $ hg up 1 -q
+  $ hg branch new -q
+  $ mkcommit c
+
+  $ hg push ../tmpc/ --new-branch
+  pushing to ../tmpc/
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files (+1 heads)
+
+make later 

[PATCH 1 of 2 rebased] tests: test that push doesn’t complain about unstable changesets if no changes

2020-07-17 Thread Manuel Jacob
# HG changeset patch
# User Manuel Jacob 
# Date 1594965560 -7200
#  Fri Jul 17 07:59:20 2020 +0200
# Node ID 6284dfa728899a6385361d59ba95d9c3d137a5e6
# Parent  a37f290a71240b851f5df900833f848efbab576a
# EXP-Topic issue6372
tests: test that push doesn’t complain about unstable changesets if no changes

When there’re no outgoing changes, push doesn’t complain about unstable
changesets.

There is currently a bug (see issue6372) that causes that there is an abort on
push when the outgoing changes contain another changeset even if that is not
obsolete or unstable. A test case and fix for that is sent in the next patch.

diff --git a/tests/test-obsolete.t b/tests/test-obsolete.t
--- a/tests/test-obsolete.t
+++ b/tests/test-obsolete.t
@@ -627,6 +627,26 @@
   abort: push includes orphan changeset: cda648ca50f5!
   [255]
 
+with --force it will work anyway
+
+  $ hg push ../tmpc/ --force
+  pushing to ../tmpc/
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 2 changesets with 2 changes to 2 files
+  1 new obsolescence markers
+  1 new orphan changesets
+
+if the orphan changeset is already on the server, pushing should work
+
+  $ hg push ../tmpc/
+  pushing to ../tmpc/
+  searching for changes
+  no changes found
+  [1]
+
 Test that extinct changeset are properly detected
 
   $ hg log -r 'extinct()'
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH]: [Bug 6373] py3 support for popen on windows vs cmdbuilder

2020-07-17 Thread Yuya Nishihara
On Thu, 16 Jul 2020 23:05:19 +0300, Александр Литягин wrote:
> # HG changeset patch
> # User alexrayne 
> # Date 1557358579 -10800
> #  Thu May 09 02:36:19 2019 +0300
> # Node ID 856cea175acabd5b8f87319001067a7785c15279
> # Parent  33b512aa8dba0cbe523188fbb62d30ae2125a236
> !popen:py3 - #6065 subprocess.Popen uses strings args. so, py2 normaly 

> +def encodes(s, name_or_codec, *args, **kwargs):
> +    if s is None:
> +    return [];
> +    if (isinstance(name_or_codec, string_types)):
> +    codec = codecs.lookup(name_or_codec)
> +    else:
> +    codec = name_or_codec
> +    r = []
> +    for arg in s:
> +    if (isinstance(arg, string_types)):
> +    rv, length = codec.encode(arg, *args, **kwargs)
> +    r.append(rv)
> +    else:
> +    r.append(arg)
> +    return r

Unused.

> +def decodes(s, name_or_codec, *args, **kwargs):
> +    if (isinstance(name_or_codec, string_types)):
> +    codec = codecs.lookup(name_or_codec)
> +    else:
> +    codec = name_or_codec
> +    if s is None:
> +    return [];
> +    r = []
> +    for arg in s:
> +    if (isinstance(arg, bytes)):
> +    rv, length = codec.decode(arg, *args, **kwargs)
> +    if not isinstance(rv, (str, bytes, bytearray)):
> +    raise TypeError('Not a string or byte codec')
> +    r.append(rv)
> +    else:
> +    r.append(arg)
> +    return r
> +
> +if (sys.version_info[0] >= 3) and (os.name == 'nt') :
> +    def _fix_encoding_args(a):
> +    #py3 Popen accepts str args
> +    encoding = get_encoding() or 'UTF-8'
> +    argcodec = codecs.lookup(encoding)

I think there's no need to look up codec object.

> +    return decodes( a, argcodec ) #get_encoding()
> +else:
> +    def _fix_encoding_args(a):
> +    #py2 Popen accepts binary_str args
> +    return a #encodes(a, argcodec) #a;
> +
>   def popen(args, env=None):
>   environ = None
>   if env:
>   environ = dict(os.environ)
>   environ.update(env)
> 
> -    return subprocess.Popen(args, stdin=subprocess.PIPE, 
> stdout=subprocess.PIPE,
> +    return subprocess.Popen(_fix_encoding_args(args),

The encoding of user arguments is unknown, but maybe using a.decode("mbcs")
is better since the other hgclient APIs would expect an MBCS-encoded bytes
on Windows.

https://www.mercurial-scm.org/repo/hg/file/5.4/mercurial/pycompat.py#l174

And we might also want to leverage the encoding parameter if specified:

def init(dest=None, ssh=None, remotecmd=None, insecure=False,
 encoding=None, configs=None):
args = util.cmdbuilder('init', ...)
args = util.tonativeargs(args, encoding=encoding)
...
proc = util.popen(args)
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 4 of 4] windows: always work around EINVAL in case of broken pipe for stdout / stderr

2020-07-17 Thread Yuya Nishihara
On Fri, 17 Jul 2020 04:38:50 +0200, Manuel Jacob wrote:
> # HG changeset patch
> # User Manuel Jacob 
> # Date 1594949332 -7200
> #  Fri Jul 17 03:28:52 2020 +0200
> # Node ID 741837f160677ec24154b3d5aa209133a3872d53
> # Parent  91f6d0508acac2c8eb0fbf8864528f8f584e697c
> # EXP-Topic stdio-broken_pipe
> windows: always work around EINVAL in case of broken pipe for stdout / stderr

Queued, thanks.

> diff --git a/mercurial/windows.py b/mercurial/windows.py
> --- a/mercurial/windows.py
> +++ b/mercurial/windows.py
> @@ -197,6 +197,7 @@
>  
>  def __init__(self, fp):
>  self.fp = fp
> +self.throttle = not pycompat.ispy3 and fp.isatty()

If we need to handle the case where sys.stdout is a pseudo file object on
Python 2, isatty() may be missing.

>  def write(self, s):
> +if not pycompat.ispy3:
> +self.softspace = 0

No idea what this softspace is for, but I assume it's py2-only attribute.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 1 of 2] discovery: weaken claim about returned common heads if ancestorsof are given

2020-07-17 Thread Yuya Nishihara
On Fri, 17 Jul 2020 09:54:41 +0200, Manuel Jacob wrote:
> On 2020-07-17 08:49, Pierre-Yves David wrote:
> > On 7/17/20 6:16 AM, Manuel Jacob wrote:
> >> On 2020-07-17 05:15, Pierre-Yves David wrote:
> >>> This looks correct to me. Thanks of lot to Manuel for making this
> >>> clarification work.
> >>> 
> >>> You should consider using mercurial.util.nouideprecwarn to catch (and
> >>> have extension catch) user of the old attribute.
> >> 
> >> In the current patch, I forward the new name to the old name without 
> >> changing the users. However, I think that changing the name at all the 
> >> users is a good idea because then it will become more obvious in the 
> >> code if there is a bug. We’ll need to review all places using the 
> >> attribute (and possibly fix some). Using "ancestorsof" at all the 
> >> users will make the fix more obvious in the patch.
> >> 
> >> I could either:
> >> 
> >> 1) send a follow-up patch doing the mass-rename and adding the warning 
> >> (this means the already sent patch stays less noisy), or
> >> 2) send a new patch combining the docstring change and the 
> >> mass-rename.
> > 
> > Sending follow ups seems better.
> 
> I send such a patch in reply to the patch fixing the docstring.

Queued these, thanks.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D8763: diff: move no-eol text constant to a common location

2020-07-17 Thread rdamazio (Rodrigo Damazio Bovendorp)
rdamazio created this revision.
Herald added a reviewer: hg-reviewers.
Herald added a subscriber: mercurial-patches.

REPOSITORY
  rHG Mercurial

BRANCH
  default

REVISION DETAIL
  https://phab.mercurial-scm.org/D8763

AFFECTED FILES
  mercurial/crecord.py
  mercurial/diffhelper.py
  mercurial/mdiff.py
  mercurial/patch.py

CHANGE DETAILS

diff --git a/mercurial/patch.py b/mercurial/patch.py
--- a/mercurial/patch.py
+++ b/mercurial/patch.py
@@ -785,7 +785,7 @@
 for l in x.hunk:
 lines.append(l)
 if l[-1:] != b'\n':
-lines.append(b"\n\\ No newline at end of file\n")
+lines.append(b'\n' + diffhelper.MISSING_NEWLINE_MARKER)
 self.backend.writerej(self.fname, len(self.rej), self.hunks, lines)
 
 def apply(self, h):
@@ -1069,7 +1069,7 @@
 
 def write(self, fp):
 delta = len(self.before) + len(self.after)
-if self.after and self.after[-1] == b'\\ No newline at end of file\n':
+if self.after and self.after[-1] == diffhelper.MISSING_NEWLINE_MARKER:
 delta -= 1
 fromlen = delta + self.removed
 tolen = delta + self.added
diff --git a/mercurial/mdiff.py b/mercurial/mdiff.py
--- a/mercurial/mdiff.py
+++ b/mercurial/mdiff.py
@@ -17,6 +17,7 @@
 setattr,
 )
 from . import (
+diffhelper,
 encoding,
 error,
 policy,
@@ -25,8 +26,6 @@
 )
 from .utils import dateutil
 
-_missing_newline_marker = b"\\ No newline at end of file\n"
-
 bdiff = policy.importmod('bdiff')
 mpatch = policy.importmod('mpatch')
 
@@ -309,7 +308,7 @@
 hunklines = [b"@@ -0,0 +1,%d @@\n" % size] + [b"+" + e for e in b]
 if without_newline:
 hunklines[-1] += b'\n'
-hunklines.append(_missing_newline_marker)
+hunklines.append(diffhelper.MISSING_NEWLINE_MARKER)
 hunks = ((hunkrange, hunklines),)
 elif not b:
 without_newline = not a.endswith(b'\n')
@@ -325,7 +324,7 @@
 hunklines = [b"@@ -1,%d +0,0 @@\n" % size] + [b"-" + e for e in a]
 if without_newline:
 hunklines[-1] += b'\n'
-hunklines.append(_missing_newline_marker)
+hunklines.append(diffhelper.MISSING_NEWLINE_MARKER)
 hunks = ((hunkrange, hunklines),)
 else:
 hunks = _unidiff(a, b, opts=opts)
@@ -418,13 +417,13 @@
 if hunklines[i].startswith(b' '):
 skip = True
 hunklines[i] += b'\n'
-hunklines.insert(i + 1, _missing_newline_marker)
+hunklines.insert(i + 1, diffhelper.MISSING_NEWLINE_MARKER)
 break
 if not skip and not t2.endswith(b'\n') and bstart + blen == len(l2) + 
1:
 for i in pycompat.xrange(len(hunklines) - 1, -1, -1):
 if hunklines[i].startswith(b'+'):
 hunklines[i] += b'\n'
-hunklines.insert(i + 1, _missing_newline_marker)
+hunklines.insert(i + 1, diffhelper.MISSING_NEWLINE_MARKER)
 break
 yield hunkrange, hunklines
 
diff --git a/mercurial/diffhelper.py b/mercurial/diffhelper.py
--- a/mercurial/diffhelper.py
+++ b/mercurial/diffhelper.py
@@ -14,6 +14,8 @@
 pycompat,
 )
 
+MISSING_NEWLINE_MARKER = b'\\ No newline at end of file\n'
+
 
 def addlines(fp, hunk, lena, lenb, a, b):
 """Read lines from fp into the hunk
@@ -32,7 +34,7 @@
 s = fp.readline()
 if not s:
 raise error.ParseError(_(b'incomplete hunk'))
-if s == b"\\ No newline at end of file\n":
+if s == MISSING_NEWLINE_MARKER:
 fixnewline(hunk, a, b)
 continue
 if s == b'\n' or s == b'\r\n':
diff --git a/mercurial/crecord.py b/mercurial/crecord.py
--- a/mercurial/crecord.py
+++ b/mercurial/crecord.py
@@ -20,6 +20,7 @@
 open,
 )
 from . import (
+diffhelper,
 encoding,
 error,
 patch as patchmod,
@@ -416,7 +417,7 @@
 contextlen = (
 len(self.before) + len(self.after) + removedconvertedtocontext
 )
-if self.after and self.after[-1] == b'\\ No newline at end of file\n':
+if self.after and self.after[-1] == diffhelper.MISSING_NEWLINE_MARKER:
 contextlen -= 1
 fromlen = contextlen + self.removed
 tolen = contextlen + self.added
@@ -503,7 +504,7 @@
 noeol = False
 for line in self.changedlines:
 text = line.linetext
-if line.linetext == b'\\ No newline at end of file\n':
+if line.linetext == diffhelper.MISSING_NEWLINE_MARKER:
 noeol = True
 break
 if line.applied:



To: rdamazio, #hg-reviewers
Cc: mercurial-patches, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org

D8762: revert: fix interactive reverting of end-of-file newline changes

2020-07-17 Thread rdamazio (Rodrigo Damazio Bovendorp)
rdamazio created this revision.
Herald added a reviewer: hg-reviewers.
Herald added a subscriber: mercurial-patches.

REVISION SUMMARY
  The chunk reversal used by `revert -i` in Curses mode was not taking this case
  into account.

REPOSITORY
  rHG Mercurial

BRANCH
  default

REVISION DETAIL
  https://phab.mercurial-scm.org/D8762

AFFECTED FILES
  mercurial/crecord.py
  tests/test-revert-interactive-curses.t

CHANGE DETAILS

diff --git a/tests/test-revert-interactive-curses.t 
b/tests/test-revert-interactive-curses.t
new file mode 100644
--- /dev/null
+++ b/tests/test-revert-interactive-curses.t
@@ -0,0 +1,55 @@
+#require tic
+
+Revert interactive tests with the Curses interface
+
+  $ cat <> $HGRCPATH
+  > [ui]
+  > interactive = true
+  > interface = curses
+  > [experimental]
+  > crecordtest = testModeCommands
+  > EOF
+
+TODO: Make a curses version of the other tests from test-revert-interactive.t.
+
+When a line without EOL is selected during "revert -i"
+
+  $ hg init $TESTTMP/revert-i-curses-eol
+  $ cd $TESTTMP/revert-i-curses-eol
+  $ echo 0 > a
+  $ hg ci -qAm 0
+  $ printf 1 >> a
+  $ hg ci -qAm 1
+  $ cat a
+  0
+  1 (no-eol)
+
+  $ cat  c
+  > EOF
+
+  $ hg revert -ir'.^'
+  reverting a
+  $ cat a
+  0
+
+When a selected line is reverted to have no EOL
+
+  $ hg init $TESTTMP/revert-i-curses-eol2
+  $ cd $TESTTMP/revert-i-curses-eol2
+  $ printf 0 > a
+  $ hg ci -qAm 0
+  $ echo 0 > a
+  $ hg ci -qAm 1
+  $ cat a
+  0
+
+  $ cat  c
+  > EOF
+
+  $ hg revert -ir'.^'
+  reverting a
+  $ cat a
+  0 (no-eol)
+
diff --git a/mercurial/crecord.py b/mercurial/crecord.py
--- a/mercurial/crecord.py
+++ b/mercurial/crecord.py
@@ -500,8 +500,12 @@
 """
 dels = []
 adds = []
+noeol = False
 for line in self.changedlines:
 text = line.linetext
+if line.linetext == b'\\ No newline at end of file\n':
+noeol = True
+break
 if line.applied:
 if text.startswith(b'+'):
 dels.append(text[1:])
@@ -511,6 +515,9 @@
 dels.append(text[1:])
 adds.append(text[1:])
 hunk = [b'-%s' % l for l in dels] + [b'+%s' % l for l in adds]
+if noeol and hunk:
+# Remove the newline from the end of the hunk.
+hunk[-1] = hunk[-1][:-1]
 h = self._hunk
 return patchmod.recordhunk(
 h.header, h.toline, h.fromline, h.proc, h.before, hunk, h.after



To: rdamazio, #hg-reviewers
Cc: mercurial-patches, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 13 of 13] merge: remove no longer required ACTION_GET_OTHER_AND_STORE

2020-07-17 Thread Pulkit Goyal
# HG changeset patch
# User Pulkit Goyal <7895pul...@gmail.com>
# Date 1594725028 -19800
#  Tue Jul 14 16:40:28 2020 +0530
# Node ID a5812036d3a33b466854204be2128d8aa1a11b0f
# Parent  4021b2b860103442ac0d36b0cc5176ec74c92a6a
# EXP-Topic mergestate-refactor
merge: remove no longer required ACTION_GET_OTHER_AND_STORE

In 1b8fd4af33189c84feadb47c74d659ec31cde3b9 I (ab)used merge actions to pass
info from manifestmerge() to applyupdates() and store info in mergestate.

In previous patches, we introduced a separate return value from manifestmerge()
and calculateupdates() and an argument to applyupdates() which achieved the same
thing.

Let's remove this no longer required messy code.

Differential Revision: https://phab.mercurial-scm.org/D8744

diff --git a/mercurial/merge.py b/mercurial/merge.py
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
@@ -671,9 +671,7 @@ def manifestmerge(
 )
 else:
 actions[f] = (
-mergestatemod.ACTION_GET_OTHER_AND_STORE
-if branchmerge
-else mergestatemod.ACTION_GET,
+mergestatemod.ACTION_GET,
 (fl2, False),
 b'remote is newer',
 )
@@ -687,9 +685,7 @@ def manifestmerge(
 )
 elif nol and n1 == a:  # local only changed 'x'
 actions[f] = (
-mergestatemod.ACTION_GET_OTHER_AND_STORE
-if branchmerge
-else mergestatemod.ACTION_GET,
+mergestatemod.ACTION_GET,
 (fl1, False),
 b'remote is newer',
 )
@@ -960,8 +956,6 @@ def calculateupdates(
 
 for f, a in sorted(pycompat.iteritems(actions)):
 m, args, msg = a
-if m == mergestatemod.ACTION_GET_OTHER_AND_STORE:
-m = mergestatemod.ACTION_GET
 repo.ui.debug(b' %s: %s -> %s\n' % (f, msg, m))
 if f in fbids:
 d = fbids[f]
@@ -1193,7 +1187,6 @@ def emptyactions():
 mergestatemod.ACTION_KEEP,
 mergestatemod.ACTION_PATH_CONFLICT,
 mergestatemod.ACTION_PATH_CONFLICT_RESOLVE,
-mergestatemod.ACTION_GET_OTHER_AND_STORE,
 )
 }
 
@@ -1237,10 +1230,6 @@ def applyupdates(
 if op == b'other':
 ms.addmergedother(f)
 
-# add ACTION_GET_OTHER_AND_STORE to mergestate
-for e in actions[mergestatemod.ACTION_GET_OTHER_AND_STORE]:
-ms.addmergedother(e[0])
-
 moves = []
 for m, l in actions.items():
 l.sort()
@@ -1783,7 +1772,6 @@ def update(
 mergestatemod.ACTION_EXEC,
 mergestatemod.ACTION_REMOVE,
 mergestatemod.ACTION_PATH_CONFLICT_RESOLVE,
-mergestatemod.ACTION_GET_OTHER_AND_STORE,
 ):
 msg = _(b"conflicting changes")
 hint = _(b"commit or update --clean to discard changes")
@@ -1854,10 +1842,6 @@ def update(
 actions[m] = []
 actions[m].append((f, args, msg))
 
-# ACTION_GET_OTHER_AND_STORE is a mergestatemod.ACTION_GET + store in 
mergestate
-for e in actions[mergestatemod.ACTION_GET_OTHER_AND_STORE]:
-actions[mergestatemod.ACTION_GET].append(e)
-
 if not util.fscasesensitive(repo.path):
 # check collision between files only in p2 for clean update
 if not branchmerge and (
diff --git a/mercurial/mergestate.py b/mercurial/mergestate.py
--- a/mercurial/mergestate.py
+++ b/mercurial/mergestate.py
@@ -113,8 +113,6 @@ ACTION_DIR_RENAME_MOVE_LOCAL = b'dm'
 ACTION_KEEP = b'k'
 ACTION_EXEC = b'e'
 ACTION_CREATED_MERGE = b'cm'
-# GET the other/remote side and store this info in mergestate
-ACTION_GET_OTHER_AND_STORE = b'gs'
 
 
 class mergestate(object):

___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 12 of 13] merge: pass commitinfo to applyupdates() and get it stored in mergestate

2020-07-17 Thread Pulkit Goyal
# HG changeset patch
# User Pulkit Goyal <7895pul...@gmail.com>
# Date 1594724512 -19800
#  Tue Jul 14 16:31:52 2020 +0530
# Node ID 4021b2b860103442ac0d36b0cc5176ec74c92a6a
# Parent  9fd8b89eee7e32ce4f3703d423cc320dec64da86
# EXP-Topic mergestate-refactor
merge: pass commitinfo to applyupdates() and get it stored in mergestate

This patch passes the commitinfo calulcated in manifestmerge() to applyupdates()
so that it can be read there and stored in mergestate. On commit, we can read
mergestate for such information and act accordingly.

This patch also makes ACTION_GET_OTHER_AND_STORE not required anymore. Next
patch will remove the messy code surrounding it.

Differential Revision: https://phab.mercurial-scm.org/D8743

diff --git a/hgext/remotefilelog/__init__.py b/hgext/remotefilelog/__init__.py
--- a/hgext/remotefilelog/__init__.py
+++ b/hgext/remotefilelog/__init__.py
@@ -479,7 +479,7 @@ def storewrapper(orig, requirements, pat
 
 # prefetch files before update
 def applyupdates(
-orig, repo, actions, wctx, mctx, overwrite, wantfiledata, labels=None
+orig, repo, actions, wctx, mctx, overwrite, wantfiledata, **opts
 ):
 if isenabled(repo):
 manifest = mctx.manifest()
@@ -488,9 +488,7 @@ def applyupdates(
 files.append((f, hex(manifest[f])))
 # batch fetch the needed files from the server
 repo.fileservice.prefetch(files)
-return orig(
-repo, actions, wctx, mctx, overwrite, wantfiledata, labels=labels
-)
+return orig(repo, actions, wctx, mctx, overwrite, wantfiledata, **opts)
 
 
 # Prefetch merge checkunknownfiles
diff --git a/mercurial/merge.py b/mercurial/merge.py
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
@@ -1199,12 +1199,21 @@ def emptyactions():
 
 
 def applyupdates(
-repo, actions, wctx, mctx, overwrite, wantfiledata, labels=None
+repo,
+actions,
+wctx,
+mctx,
+overwrite,
+wantfiledata,
+labels=None,
+commitinfo=None,
 ):
 """apply the merge action list to the working directory
 
 wctx is the working copy context
 mctx is the context to be merged into the working copy
+commitinfo is a mapping of information which needs to be stored somewhere
+   (probably mergestate) so that it can be used at commit time.
 
 Return a tuple of (counts, filedata), where counts is a tuple
 (updated, merged, removed, unresolved) that describes how many
@@ -1219,6 +1228,15 @@ def applyupdates(
 repo, wctx.p1().node(), mctx.node(), labels
 )
 
+if commitinfo is None:
+commitinfo = {}
+
+for f, op in pycompat.iteritems(commitinfo):
+# the other side of filenode was choosen while merging, store this in
+# mergestate so that it can be reused on commit
+if op == b'other':
+ms.addmergedother(f)
+
 # add ACTION_GET_OTHER_AND_STORE to mergestate
 for e in actions[mergestatemod.ACTION_GET_OTHER_AND_STORE]:
 ms.addmergedother(e[0])
@@ -1891,7 +1909,14 @@ def update(
 
 wantfiledata = updatedirstate and not branchmerge
 stats, getfiledata = applyupdates(
-repo, actions, wc, p2, overwrite, wantfiledata, labels=labels
+repo,
+actions,
+wc,
+p2,
+overwrite,
+wantfiledata,
+labels=labels,
+commitinfo=commitinfo,
 )
 
 if updatedirstate:

___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 11 of 13] merge: return 'commitinfo' from manifestmerge() and calculateupdates() (API)

2020-07-17 Thread Pulkit Goyal
# HG changeset patch
# User Pulkit Goyal <7895pul...@gmail.com>
# Date 1594723868 -19800
#  Tue Jul 14 16:21:08 2020 +0530
# Node ID 9fd8b89eee7e32ce4f3703d423cc320dec64da86
# Parent  6a87141b0721d719fcc3b8bb94743eda1a120c17
# EXP-Topic mergestate-refactor
merge: return 'commitinfo' from manifestmerge() and calculateupdates() (API)

commitinfo will be used to pass information which is required on commit phase
from the merge phase.

One common example is, merge chooses filenode from second parent and we need to
tell commit to choose that. Right now this one and related cases are not very
neatly implement and there is no clear line on how to pass on such information.

Upcoming patches will try to work on in this area and make things easier.

Differential Revision: https://phab.mercurial-scm.org/D8742

diff --git a/hgext/convert/hg.py b/hgext/convert/hg.py
--- a/hgext/convert/hg.py
+++ b/hgext/convert/hg.py
@@ -217,7 +217,8 @@ class mercurial_sink(common.converter_si
 """
 anc = [p1ctx.ancestor(p2ctx)]
 # Calculate what files are coming from p2
-actions, diverge, rename = mergemod.calculateupdates(
+# TODO: this might be achieved using commitinfo
+actions, diverge, rename, commitinfo = mergemod.calculateupdates(
 self.repo,
 p1ctx,
 p2ctx,
diff --git a/hgext/largefiles/overrides.py b/hgext/largefiles/overrides.py
--- a/hgext/largefiles/overrides.py
+++ b/hgext/largefiles/overrides.py
@@ -543,12 +543,12 @@ def overridecalculateupdates(
 origfn, repo, p1, p2, pas, branchmerge, force, acceptremote, *args, 
**kwargs
 ):
 overwrite = force and not branchmerge
-actions, diverge, renamedelete = origfn(
+actions, diverge, renamedelete, commitinfo = origfn(
 repo, p1, p2, pas, branchmerge, force, acceptremote, *args, **kwargs
 )
 
 if overwrite:
-return actions, diverge, renamedelete
+return actions, diverge, renamedelete, commitinfo
 
 # Convert to dictionary with filename as key and action as value.
 lfiles = set()
@@ -620,7 +620,7 @@ def overridecalculateupdates(
 actions[lfile] = (b'g', largs, b'replaces standin')
 actions[standin] = (b'r', None, b'replaced by non-standin')
 
-return actions, diverge, renamedelete
+return actions, diverge, renamedelete, commitinfo
 
 
 @eh.wrapfunction(mergestatemod, b'recordupdates')
diff --git a/mercurial/merge.py b/mercurial/merge.py
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
@@ -565,6 +565,8 @@ def manifestmerge(
 diverge: mapping of source name -> list of dest name for divergent renames
 renamedelete: mapping of source name -> list of destinations for files
   deleted on one side and renamed on other.
+commitinfo: dict containing data which should be used on commit
+contains a filename -> info mapping
 """
 if matcher is not None and matcher.always():
 matcher = None
@@ -578,6 +580,10 @@ def manifestmerge(
 branch_copies1 = copies.branch_copies()
 branch_copies2 = copies.branch_copies()
 diverge = {}
+# information from merge which is needed at commit time
+# for example choosing filelog of which parent to commit
+# TODO: use specific constants in future for this mapping
+commitinfo = {}
 if followcopies:
 branch_copies1, branch_copies2, diverge = copies.mergecopies(
 repo, wctx, p2, pa
@@ -671,6 +677,8 @@ def manifestmerge(
 (fl2, False),
 b'remote is newer',
 )
+if branchmerge:
+commitinfo[f] = b'other'
 elif nol and n2 == a:  # remote only changed 'x'
 actions[f] = (
 mergestatemod.ACTION_EXEC,
@@ -685,6 +693,8 @@ def manifestmerge(
 (fl1, False),
 b'remote is newer',
 )
+if branchmerge:
+commitinfo[f] = b'other'
 else:  # both changed something
 actions[f] = (
 mergestatemod.ACTION_MERGE,
@@ -845,7 +855,7 @@ def manifestmerge(
 renamedelete = branch_copies1.renamedelete
 renamedelete.update(branch_copies2.renamedelete)
 
-return actions, diverge, renamedelete
+return actions, diverge, renamedelete, commitinfo
 
 
 def _resolvetrivial(repo, wctx, mctx, ancestor, actions):
@@ -891,13 +901,13 @@ def calculateupdates(
 
 Also filters out actions which are unrequired if repository is sparse.
 
-Returns same 3 element tuple as manifestmerge().
+Returns same 4 element tuple as manifestmerge().
 """
 # Avoid cycle.
 from . import sparse
 
 if len(ancestors) == 1:  # default
-actions, diverge, renamedelete = manifestmerge(
+actions, diverge, renamedelete, commitinfo 

[PATCH 09 of 13] merge: refactor code to advise fsmonitor in separate function

2020-07-17 Thread Pulkit Goyal
# HG changeset patch
# User Pulkit Goyal <7895pul...@gmail.com>
# Date 1594301530 -19800
#  Thu Jul 09 19:02:10 2020 +0530
# Node ID 15d0b77c5833af7c1b04e29dd4628a66d9518cde
# Parent  3e356397d1b4f0b07465fab86045a38d59029067
# EXP-Topic mergestate-refactor
merge: refactor code to advise fsmonitor in separate function

merge.update() is quite hard to understand, found this an easy win.

The end goal is to have better organized merge and mergestate handling and then
fix some related bugs.

Differential Revision: https://phab.mercurial-scm.org/D8740

diff --git a/mercurial/merge.py b/mercurial/merge.py
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
@@ -1477,6 +1477,49 @@ def applyupdates(
 return updateresult(updated, merged, removed, unresolved), getfiledata
 
 
+def _advertisefsmonitor(repo, num_gets, p1node):
+# Advertise fsmonitor when its presence could be useful.
+#
+# We only advertise when performing an update from an empty working
+# directory. This typically only occurs during initial clone.
+#
+# We give users a mechanism to disable the warning in case it is
+# annoying.
+#
+# We only allow on Linux and MacOS because that's where fsmonitor is
+# considered stable.
+fsmonitorwarning = repo.ui.configbool(b'fsmonitor', b'warn_when_unused')
+fsmonitorthreshold = repo.ui.configint(
+b'fsmonitor', b'warn_update_file_count'
+)
+try:
+# avoid cycle: extensions -> cmdutil -> merge
+from . import extensions
+
+extensions.find(b'fsmonitor')
+fsmonitorenabled = repo.ui.config(b'fsmonitor', b'mode') != b'off'
+# We intentionally don't look at whether fsmonitor has disabled
+# itself because a) fsmonitor may have already printed a warning
+# b) we only care about the config state here.
+except KeyError:
+fsmonitorenabled = False
+
+if (
+fsmonitorwarning
+and not fsmonitorenabled
+and p1node == nullid
+and num_gets >= fsmonitorthreshold
+and pycompat.sysplatform.startswith((b'linux', b'darwin'))
+):
+repo.ui.warn(
+_(
+b'(warning: large working directory being used without '
+b'fsmonitor enabled; enable fsmonitor to improve performance; '
+b'see "hg help -e fsmonitor")\n'
+)
+)
+
+
 UPDATECHECK_ABORT = b'abort'  # handled at higher layers
 UPDATECHECK_NONE = b'none'
 UPDATECHECK_LINEAR = b'linear'
@@ -1815,46 +1858,9 @@ def update(
 # note that we're in the middle of an update
 repo.vfs.write(b'updatestate', p2.hex())
 
-# Advertise fsmonitor when its presence could be useful.
-#
-# We only advertise when performing an update from an empty working
-# directory. This typically only occurs during initial clone.
-#
-# We give users a mechanism to disable the warning in case it is
-# annoying.
-#
-# We only allow on Linux and MacOS because that's where fsmonitor is
-# considered stable.
-fsmonitorwarning = repo.ui.configbool(b'fsmonitor', 
b'warn_when_unused')
-fsmonitorthreshold = repo.ui.configint(
-b'fsmonitor', b'warn_update_file_count'
+_advertisefsmonitor(
+repo, len(actions[mergestatemod.ACTION_GET]), p1.node()
 )
-try:
-# avoid cycle: extensions -> cmdutil -> merge
-from . import extensions
-
-extensions.find(b'fsmonitor')
-fsmonitorenabled = repo.ui.config(b'fsmonitor', b'mode') != b'off'
-# We intentionally don't look at whether fsmonitor has disabled
-# itself because a) fsmonitor may have already printed a warning
-# b) we only care about the config state here.
-except KeyError:
-fsmonitorenabled = False
-
-if (
-fsmonitorwarning
-and not fsmonitorenabled
-and p1.node() == nullid
-and len(actions[mergestatemod.ACTION_GET]) >= fsmonitorthreshold
-and pycompat.sysplatform.startswith((b'linux', b'darwin'))
-):
-repo.ui.warn(
-_(
-b'(warning: large working directory being used without '
-b'fsmonitor enabled; enable fsmonitor to improve 
performance; '
-b'see "hg help -e fsmonitor")\n'
-)
-)
 
 wantfiledata = updatedirstate and not branchmerge
 stats, getfiledata = applyupdates(

___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 10 of 13] merge: document return values of manifestmerge() and calculateupdates()

2020-07-17 Thread Pulkit Goyal
# HG changeset patch
# User Pulkit Goyal <7895pul...@gmail.com>
# Date 1594721548 -19800
#  Tue Jul 14 15:42:28 2020 +0530
# Node ID 6a87141b0721d719fcc3b8bb94743eda1a120c17
# Parent  15d0b77c5833af7c1b04e29dd4628a66d9518cde
# EXP-Topic mergestate-refactor
merge: document return values of manifestmerge() and calculateupdates()

In future patches, I want to add one more return value which represents
information which needs to stored and used at commit time.

Differential Revision: https://phab.mercurial-scm.org/D8741

diff --git a/mercurial/merge.py b/mercurial/merge.py
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
@@ -558,6 +558,13 @@ def manifestmerge(
 branchmerge and force are as passed in to update
 matcher = matcher to filter file lists
 acceptremote = accept the incoming changes without prompting
+
+Returns:
+
+actions: dict of filename as keys and action related info as values
+diverge: mapping of source name -> list of dest name for divergent renames
+renamedelete: mapping of source name -> list of destinations for files
+  deleted on one side and renamed on other.
 """
 if matcher is not None and matcher.always():
 matcher = None
@@ -875,7 +882,17 @@ def calculateupdates(
 matcher=None,
 mergeforce=False,
 ):
-"""Calculate the actions needed to merge mctx into wctx using ancestors"""
+"""
+Calculate the actions needed to merge mctx into wctx using ancestors
+
+Uses manifestmerge() to merge manifest and get list of actions required to
+perform for merging two manifests. If there are multiple ancestors, uses 
bid
+merge if enabled.
+
+Also filters out actions which are unrequired if repository is sparse.
+
+Returns same 3 element tuple as manifestmerge().
+"""
 # Avoid cycle.
 from . import sparse
 

___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 07 of 13] mergestate: rename a helpless variable name to bit helpful one

2020-07-17 Thread Pulkit Goyal
# HG changeset patch
# User Pulkit Goyal <7895pul...@gmail.com>
# Date 1594300089 -19800
#  Thu Jul 09 18:38:09 2020 +0530
# Node ID 7265d8b575ff4f3adfc392247f868344eadd43c2
# Parent  8dd9eeb56cd015f1e323fedad6c8d58de2d81bb1
# EXP-Topic mergestate-refactor
mergestate: rename a helpless variable name to bit helpful one

The old variable name `r` makes it ~impossible to understand what does it mean.
One can only understand that after going to callers and hoping that its
documented there.

I also documented return value of the function involved while I was there.

Differential Revision: https://phab.mercurial-scm.org/D8738

diff --git a/mercurial/mergestate.py b/mercurial/mergestate.py
--- a/mercurial/mergestate.py
+++ b/mercurial/mergestate.py
@@ -619,7 +619,10 @@ class mergestate(object):
 return self._stateextras.setdefault(filename, {})
 
 def _resolve(self, preresolve, dfile, wctx):
-"""rerun merge process for file path `dfile`"""
+"""rerun merge process for file path `dfile`.
+Returns whether the merge was completed and the return value of merge
+obtained from filemerge._filemerge().
+"""
 if self[dfile] in (MERGE_RECORD_RESOLVED, 
MERGE_RECORD_DRIVER_RESOLVED):
 return True, 0
 if self._state[dfile][0] == MERGE_RECORD_MERGED_OTHER:
@@ -660,7 +663,7 @@ class mergestate(object):
 f.close()
 else:
 wctx[dfile].remove(ignoremissing=True)
-complete, r, deleted = filemerge.premerge(
+complete, merge_ret, deleted = filemerge.premerge(
 self._repo,
 wctx,
 self._local,
@@ -671,7 +674,7 @@ class mergestate(object):
 labels=self._labels,
 )
 else:
-complete, r, deleted = filemerge.filemerge(
+complete, merge_ret, deleted = filemerge.filemerge(
 self._repo,
 wctx,
 self._local,
@@ -681,12 +684,12 @@ class mergestate(object):
 fca,
 labels=self._labels,
 )
-if r is None:
-# no real conflict
+if merge_ret is None:
+# If return value of merge is None, then there are no real conflict
 del self._state[dfile]
 self._stateextras.pop(dfile, None)
 self._dirty = True
-elif not r:
+elif not merge_ret:
 self.mark(dfile, MERGE_RECORD_RESOLVED)
 
 if complete:
@@ -708,9 +711,9 @@ class mergestate(object):
 else:
 action = ACTION_ADD
 # else: regular merges (no action necessary)
-self._results[dfile] = r, action
+self._results[dfile] = merge_ret, action
 
-return complete, r
+return complete, merge_ret
 
 def preresolve(self, dfile, wctx):
 """run premerge process for dfile

___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 08 of 13] mergestate: document what mergestate._results is for

2020-07-17 Thread Pulkit Goyal
# HG changeset patch
# User Pulkit Goyal <7895pul...@gmail.com>
# Date 1594300418 -19800
#  Thu Jul 09 18:43:38 2020 +0530
# Node ID 3e356397d1b4f0b07465fab86045a38d59029067
# Parent  7265d8b575ff4f3adfc392247f868344eadd43c2
# EXP-Topic mergestate-refactor
mergestate: document what mergestate._results is for

Understanding that dict is important for understanding how mergestate is
performing operations on dirstate.

Differential Revision: https://phab.mercurial-scm.org/D8739

diff --git a/mercurial/mergestate.py b/mercurial/mergestate.py
--- a/mercurial/mergestate.py
+++ b/mercurial/mergestate.py
@@ -267,6 +267,11 @@ class mergestate(object):
 self._labels = [l for l in labels if len(l) > 0]
 elif not rtype.islower():
 unsupported.add(rtype)
+# contains a mapping of form:
+# {filename : (merge_return_value, action_to_be_performed}
+# these are results of re-running merge process
+# this dict is used to perform actions on dirstate caused by re-running
+# the merge
 self._results = {}
 self._dirty = False
 

___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 05 of 13] mergestate: document mergestate records in an organized way

2020-07-17 Thread Pulkit Goyal
# HG changeset patch
# User Pulkit Goyal <7895pul...@gmail.com>
# Date 1594294541 -19800
#  Thu Jul 09 17:05:41 2020 +0530
# Node ID c571d56248d51c7ed396871495e9ddc989a8ce45
# Parent  6879b715405d2ff35deb35eac97104bb82c1aff2
# EXP-Topic mergestate-refactor
mergestate: document mergestate records in an organized way

This makes clear which mergestate record is used for what and group them based
on how they are used right now.

Differential Revision: https://phab.mercurial-scm.org/D8719

diff --git a/mercurial/mergestate.py b/mercurial/mergestate.py
--- a/mercurial/mergestate.py
+++ b/mercurial/mergestate.py
@@ -39,25 +39,40 @@ def _filectxorabsent(hexnode, ctx, f):
 
 
 # Merge state record types. See ``mergestate`` docs for more.
+
+
+# merge records which records metadata about a current merge
+# exists only once in a mergestate
+#
 RECORD_LOCAL = b'L'
 RECORD_OTHER = b'O'
-# record extra information about files
-RECORD_FILE_VALUES = b'f'
 # record merge labels
 RECORD_LABELS = b'l'
+# store info about merge driver used and it's state
+RECORD_MERGE_DRIVER_STATE = b'm'
 
+#
+# record extra information about files, with one entry containing info about 
one
+# file. Hence, multiple of them can exists
+#
+RECORD_FILE_VALUES = b'f'
+
+#
+# merge records which represents state of individual merges of files/folders
+# These are top level records for each entry containing merge related info.
+# Each record of these has info about one file. Hence multiple of them can
+# exists
+#
 RECORD_MERGED = b'F'
 RECORD_CHANGEDELETE_CONFLICT = b'C'
 RECORD_MERGE_DRIVER_MERGE = b'D'
+# the path was dir on one side of merge and file on another
 RECORD_PATH_CONFLICT = b'P'
 
-RECORD_MERGE_DRIVER_STATE = b'm'
-RECORD_OVERRIDE = b't'
-
-MERGE_DRIVER_STATE_UNMARKED = b'u'
-MERGE_DRIVER_STATE_MARKED = b'm'
-MERGE_DRIVER_STATE_SUCCESS = b's'
-
+#
+# possible state which a merge entry can have. These are stored inside 
top-level
+# merge records mentioned just above.
+#
 MERGE_RECORD_UNRESOLVED = b'u'
 MERGE_RECORD_RESOLVED = b'r'
 MERGE_RECORD_UNRESOLVED_PATH = b'pu'
@@ -67,6 +82,21 @@ MERGE_RECORD_DRIVER_RESOLVED = b'd'
 # of other version. This info is used on commit.
 MERGE_RECORD_MERGED_OTHER = b'o'
 
+#
+# top level record which stores other unknown records. Multiple of these can
+# exists
+#
+RECORD_OVERRIDE = b't'
+
+#
+# possible states which a merge driver can have. These are stored inside a
+# RECORD_MERGE_DRIVER_STATE entry
+#
+MERGE_DRIVER_STATE_UNMARKED = b'u'
+MERGE_DRIVER_STATE_MARKED = b'm'
+MERGE_DRIVER_STATE_SUCCESS = b's'
+
+
 ACTION_FORGET = b'f'
 ACTION_REMOVE = b'r'
 ACTION_ADD = b'a'

___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 06 of 13] mergestate: remove unnecessary recordactions() from mergestate class

2020-07-17 Thread Pulkit Goyal
# HG changeset patch
# User Pulkit Goyal <7895pul...@gmail.com>
# Date 1594299054 -19800
#  Thu Jul 09 18:20:54 2020 +0530
# Node ID 8dd9eeb56cd015f1e323fedad6c8d58de2d81bb1
# Parent  c571d56248d51c7ed396871495e9ddc989a8ce45
# EXP-Topic mergestate-refactor
mergestate: remove unnecessary recordactions() from mergestate class

This function is updating dirstate which sounds like not something which a
method on mergestate class should do. Also this just calls another function.
Lets directly call that function and remove this reducing mergestate
responsibility a bit.

There was single caller which is updated.

Differential Revision: https://phab.mercurial-scm.org/D8737

diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -6129,7 +6129,8 @@ def resolve(ui, repo, *pats, **opts):
 raise
 
 ms.commit()
-ms.recordactions()
+branchmerge = repo.dirstate.p2() != nullid
+mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
 
 if not didwork and pats:
 hint = None
diff --git a/mercurial/mergestate.py b/mercurial/mergestate.py
--- a/mercurial/mergestate.py
+++ b/mercurial/mergestate.py
@@ -756,11 +756,6 @@ class mergestate(object):
 actions[action].append((f, None, b"merge result"))
 return actions
 
-def recordactions(self):
-"""record remove/add/get actions in the dirstate"""
-branchmerge = self._repo.dirstate.p2() != nullid
-recordupdates(self._repo, self.actions(), branchmerge, None)
-
 def queueremove(self, f):
 """queues a file to be removed from the dirstate
 

___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 03 of 13] mergestate: add comments about couple of record types and minor reorder

2020-07-17 Thread Pulkit Goyal
# HG changeset patch
# User Pulkit Goyal <7895pul...@gmail.com>
# Date 1594292904 -19800
#  Thu Jul 09 16:38:24 2020 +0530
# Node ID ed6b80e5ed265851feb59d7855641b5d5254953b
# Parent  9e4a5e41f0ac3fa39a29d5376a1d3922e9221318
# EXP-Topic mergestate-refactor
mergestate: add comments about couple of record types and minor reorder

I am trying to divide the records into certain groups and then have dedicated
objects for them. Taking baby steps in that direction.

Differential Revision: https://phab.mercurial-scm.org/D8717

diff --git a/mercurial/mergestate.py b/mercurial/mergestate.py
--- a/mercurial/mergestate.py
+++ b/mercurial/mergestate.py
@@ -41,13 +41,17 @@ def _filectxorabsent(hexnode, ctx, f):
 # Merge state record types. See ``mergestate`` docs for more.
 RECORD_LOCAL = b'L'
 RECORD_OTHER = b'O'
+# record extra information about files
+RECORD_FILE_VALUES = b'f'
+# record merge labels
+RECORD_LABELS = b'l'
+
 RECORD_MERGED = b'F'
 RECORD_CHANGEDELETE_CONFLICT = b'C'
 RECORD_MERGE_DRIVER_MERGE = b'D'
 RECORD_PATH_CONFLICT = b'P'
+
 RECORD_MERGE_DRIVER_STATE = b'm'
-RECORD_FILE_VALUES = b'f'
-RECORD_LABELS = b'l'
 RECORD_OVERRIDE = b't'
 RECORD_UNSUPPORTED_MANDATORY = b'X'
 RECORD_UNSUPPORTED_ADVISORY = b'x'

___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 04 of 13] mergestate: remove unused unsupported related mergestate records

2020-07-17 Thread Pulkit Goyal
# HG changeset patch
# User Pulkit Goyal <7895pul...@gmail.com>
# Date 1594292982 -19800
#  Thu Jul 09 16:39:42 2020 +0530
# Node ID 6879b715405d2ff35deb35eac97104bb82c1aff2
# Parent  ed6b80e5ed265851feb59d7855641b5d5254953b
# EXP-Topic mergestate-refactor
mergestate: remove unused unsupported related mergestate records

I tried to find users of this but was unable to find. Seems like RECORD_OVERRIDE
is doing for what they were used before.

Differential Revision: https://phab.mercurial-scm.org/D8718

diff --git a/mercurial/mergestate.py b/mercurial/mergestate.py
--- a/mercurial/mergestate.py
+++ b/mercurial/mergestate.py
@@ -53,8 +53,6 @@ RECORD_PATH_CONFLICT = b'P'
 
 RECORD_MERGE_DRIVER_STATE = b'm'
 RECORD_OVERRIDE = b't'
-RECORD_UNSUPPORTED_MANDATORY = b'X'
-RECORD_UNSUPPORTED_ADVISORY = b'x'
 
 MERGE_DRIVER_STATE_UNMARKED = b'u'
 MERGE_DRIVER_STATE_MARKED = b'm'
@@ -115,8 +113,6 @@ class mergestate(object):
 m: the external merge driver defined for this merge plus its run state
(experimental)
 f: a (filename, dictionary) tuple of optional values for a given file
-X: unsupported mandatory record type (used in tests)
-x: unsupported advisory record type (used in tests)
 l: the labels for the parts of the merge.
 
 Merge driver run states (experimental):

___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 02 of 13] mergestate: remove unrequired RECORD_RESOLVED_OTHER record

2020-07-17 Thread Pulkit Goyal
# HG changeset patch
# User Pulkit Goyal <7895pul...@gmail.com>
# Date 1594290002 -19800
#  Thu Jul 09 15:50:02 2020 +0530
# Node ID 9e4a5e41f0ac3fa39a29d5376a1d3922e9221318
# Parent  66fb1ff9343a4d73b44c4314d88176e283a7839d
# EXP-Topic mergestate-refactor
mergestate: remove unrequired RECORD_RESOLVED_OTHER record

This was introduced in last cycle however while working on refactoring
mergestate, I realized it's unncessary.

This will break users who did a merge using previous version, did this kind of
storage and before commiting updated the mercurial version.

Differential Revision: https://phab.mercurial-scm.org/D8716

diff --git a/mercurial/mergestate.py b/mercurial/mergestate.py
--- a/mercurial/mergestate.py
+++ b/mercurial/mergestate.py
@@ -51,7 +51,6 @@ RECORD_LABELS = b'l'
 RECORD_OVERRIDE = b't'
 RECORD_UNSUPPORTED_MANDATORY = b'X'
 RECORD_UNSUPPORTED_ADVISORY = b'x'
-RECORD_RESOLVED_OTHER = b'R'
 
 MERGE_DRIVER_STATE_UNMARKED = b'u'
 MERGE_DRIVER_STATE_MARKED = b'm'
@@ -220,7 +219,6 @@ class mergestate(object):
 RECORD_CHANGEDELETE_CONFLICT,
 RECORD_PATH_CONFLICT,
 RECORD_MERGE_DRIVER_MERGE,
-RECORD_RESOLVED_OTHER,
 ):
 bits = record.split(b'\0')
 self._state[bits[0]] = bits[1:]
@@ -448,9 +446,7 @@ class mergestate(object):
 (RECORD_PATH_CONFLICT, b'\0'.join([filename] + v))
 )
 elif v[0] == MERGE_RECORD_MERGED_OTHER:
-records.append(
-(RECORD_RESOLVED_OTHER, b'\0'.join([filename] + v))
-)
+records.append((RECORD_MERGED, b'\0'.join([filename] + v)))
 elif v[1] == nullhex or v[6] == nullhex:
 # Change/Delete or Delete/Change conflicts. These are stored in
 # 'C' records. v[1] is the local file, and is nullhex when the

___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 01 of 13] mergestate: rename addpath() -> addpathonflict() to prevent confusion

2020-07-17 Thread Pulkit Goyal
# HG changeset patch
# User Pulkit Goyal <7895pul...@gmail.com>
# Date 1594286098 -19800
#  Thu Jul 09 14:44:58 2020 +0530
# Node ID 66fb1ff9343a4d73b44c4314d88176e283a7839d
# Parent  33524b6bef53fffcb34708e927c2b53f08fea736
# EXP-Topic mergestate-refactor
mergestate: rename addpath() -> addpathonflict() to prevent confusion

addpath() seems to imply that we are adding a new path/entry to the mergestate.

Differential Revision: https://phab.mercurial-scm.org/D8715

diff --git a/mercurial/merge.py b/mercurial/merge.py
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
@@ -1264,7 +1264,7 @@ def applyupdates(
 else:
 s(_(b"the remote file has been renamed to %s\n") % f1)
 s(_(b"resolve manually then use 'hg resolve --mark %s'\n") % f)
-ms.addpath(f, f1, fo)
+ms.addpathconflict(f, f1, fo)
 progress.increment(item=f)
 
 # When merging in-memory, we can't support worker processes, so set the
diff --git a/mercurial/mergestate.py b/mercurial/mergestate.py
--- a/mercurial/mergestate.py
+++ b/mercurial/mergestate.py
@@ -540,7 +540,7 @@ class mergestate(object):
 self._stateextras[fd] = {b'ancestorlinknode': hex(fca.node())}
 self._dirty = True
 
-def addpath(self, path, frename, forigin):
+def addpathconflict(self, path, frename, forigin):
 """add a new conflicting path to the merge state
 path:the path that conflicts
 frename: the filename the conflicting file was renamed to

___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


Re: [PATCH 1 of 2] discovery: weaken claim about returned common heads if ancestorsof are given

2020-07-17 Thread Manuel Jacob

On 2020-07-17 08:49, Pierre-Yves David wrote:

On 7/17/20 6:16 AM, Manuel Jacob wrote:

On 2020-07-17 05:15, Pierre-Yves David wrote:

This looks correct to me. Thanks of lot to Manuel for making this
clarification work.

You should consider using mercurial.util.nouideprecwarn to catch (and
have extension catch) user of the old attribute.


In the current patch, I forward the new name to the old name without 
changing the users. However, I think that changing the name at all the 
users is a good idea because then it will become more obvious in the 
code if there is a bug. We’ll need to review all places using the 
attribute (and possibly fix some). Using "ancestorsof" at all the 
users will make the fix more obvious in the patch.


I could either:

1) send a follow-up patch doing the mass-rename and adding the warning 
(this means the already sent patch stays less noisy), or
2) send a new patch combining the docstring change and the 
mass-rename.


Sending follow ups seems better.


I send such a patch in reply to the patch fixing the docstring.
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH] discovery: change users of `outgoing.missingheads` to `outgoing.ancestorsof`

2020-07-17 Thread Manuel Jacob
# HG changeset patch
# User Manuel Jacob 
# Date 1594970448 -7200
#  Fri Jul 17 09:20:48 2020 +0200
# Node ID 188143307f27defd20d67ef2ecc9adae1cf78767
# Parent  3e351fcbb83d88ec386ad8b0ffe6e0e0b0dfd46d
# EXP-Topic discovery
discovery: change users of `outgoing.missingheads` to `outgoing.ancestorsof`

The attribute `missingheads` was recently renamed to `ancestorsof`, as it,
despite the old name, doesn’t contain the missing heads but the changesets that
were requested (including ancestors) for the outgoing operation.

Changing all the users enables to print a warning if the old name is used.

There is a good chance that some of the users are buggy because of the old name.
Changing them to use the new name makes it more obvious that they are buggy. All
users need to be reviewed for bugs. When sending patches for fixing them, the
change will be more obvious without having to explain again and again the
discrepancy of the old attribute name and what it actually contained.

diff --git a/hgext/infinitepush/__init__.py b/hgext/infinitepush/__init__.py
--- a/hgext/infinitepush/__init__.py
+++ b/hgext/infinitepush/__init__.py
@@ -466,7 +466,7 @@
 
 version = b'02'
 outgoing = discovery.outgoing(
-bundlerepo, commonheads=bundleroots, missingheads=[unknownhead]
+bundlerepo, commonheads=bundleroots, ancestorsof=[unknownhead]
 )
 cgstream = changegroup.makestream(bundlerepo, outgoing, version, b'pull')
 cgstream = util.chunkbuffer(cgstream).read()
diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py
--- a/mercurial/bundle2.py
+++ b/mercurial/bundle2.py
@@ -1710,7 +1710,7 @@
 b'nbchanges', b'%d' % cg.extras[b'clcount'], mandatory=False
 )
 if opts.get(b'phases') and repo.revs(
-b'%ln and secret()', outgoing.missingheads
+b'%ln and secret()', outgoing.ancestorsof
 ):
 part.addparam(
 b'targetphase', b'%d' % phases.secret, mandatory=False
@@ -1752,7 +1752,7 @@
 # consume little memory (1M heads is 40MB) b) we don't want to send the
 # part if we don't have entries and knowing if we have entries requires
 # cache lookups.
-for node in outgoing.missingheads:
+for node in outgoing.ancestorsof:
 # Don't compute missing, as this may slow down serving.
 fnode = cache.getfnode(node, computemissing=False)
 if fnode is not None:
diff --git a/mercurial/changegroup.py b/mercurial/changegroup.py
--- a/mercurial/changegroup.py
+++ b/mercurial/changegroup.py
@@ -1629,7 +1629,7 @@
 repo = repo.unfiltered()
 commonrevs = outgoing.common
 csets = outgoing.missing
-heads = outgoing.missingheads
+heads = outgoing.ancestorsof
 # We go through the fast path if we get told to, or if all (unfiltered
 # heads have been requested (since we then know there all linkrevs will
 # be pulled by the client).
diff --git a/mercurial/discovery.py b/mercurial/discovery.py
--- a/mercurial/discovery.py
+++ b/mercurial/discovery.py
@@ -93,20 +93,17 @@
   excluded is the list of missing changeset that shouldn't be sent
   remotely.
 
-  missingheads is an alias to ancestorsof, but the name is wrong and it
-  will be removed
-
 Some members are computed on demand from the heads, unless provided upfront
 by discovery.'''
 
 def __init__(
-self, repo, commonheads=None, missingheads=None, missingroots=None
+self, repo, commonheads=None, ancestorsof=None, missingroots=None
 ):
 # at least one of them must not be set
 assert None in (commonheads, missingroots)
 cl = repo.changelog
-if missingheads is None:
-missingheads = cl.heads()
+if ancestorsof is None:
+ancestorsof = cl.heads()
 if missingroots:
 discbases = []
 for n in missingroots:
@@ -114,14 +111,14 @@
 # TODO remove call to nodesbetween.
 # TODO populate attributes on outgoing instance instead of setting
 # discbases.
-csets, roots, heads = cl.nodesbetween(missingroots, missingheads)
+csets, roots, heads = cl.nodesbetween(missingroots, ancestorsof)
 included = set(csets)
-missingheads = heads
+ancestorsof = heads
 commonheads = [n for n in discbases if n not in included]
 elif not commonheads:
 commonheads = [nullid]
 self.commonheads = commonheads
-self.missingheads = missingheads
+self.ancestorsof = ancestorsof
 self._revlog = cl
 self._common = None
 self._missing = None
@@ -129,7 +126,7 @@
 
 def _computecommonmissing(self):
 sets = self._revlog.findcommonmissing(
-self.commonheads, self.missingheads
+self.commonheads, self.ancestorsof
 )
 self._common, self._missing = sets
 
@@ -146,8 +143,15 @@
 return self._missing

Re: [PATCH 1 of 2] discovery: weaken claim about returned common heads if ancestorsof are given

2020-07-17 Thread Pierre-Yves David



On 7/17/20 6:16 AM, Manuel Jacob wrote:

On 2020-07-17 05:15, Pierre-Yves David wrote:

This looks correct to me. Thanks of lot to Manuel for making this
clarification work.

You should consider using mercurial.util.nouideprecwarn to catch (and
have extension catch) user of the old attribute.


In the current patch, I forward the new name to the old name without 
changing the users. However, I think that changing the name at all the 
users is a good idea because then it will become more obvious in the 
code if there is a bug. We’ll need to review all places using the 
attribute (and possibly fix some). Using "ancestorsof" at all the users 
will make the fix more obvious in the patch.


I could either:

1) send a follow-up patch doing the mass-rename and adding the warning 
(this means the already sent patch stays less noisy), or

2) send a new patch combining the docstring change and the mass-rename.


Sending follow ups seems better.



--
Pierre-Yves David
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 1 of 2] tests: test that push doesn’t complain about unstable changesets if no changes

2020-07-17 Thread Manuel Jacob
# HG changeset patch
# User Manuel Jacob 
# Date 1594965560 -7200
#  Fri Jul 17 07:59:20 2020 +0200
# Node ID 55626b2da7d55766ae667d91652d094c0c4aa86f
# Parent  f55099982bc517c349bf46fab53b8696f0615c17
# EXP-Topic issue6372
tests: test that push doesn’t complain about unstable changesets if no changes

When there’re no outgoing changes, push doesn’t complain about unstable
changesets.

There is currently a bug (see issue6372) that causes that there is an abort on
push when the outgoing changes contain another changeset even if that is not
obsolete or unstable. A test case and fix for that is sent in the next patch.

diff --git a/tests/test-obsolete.t b/tests/test-obsolete.t
--- a/tests/test-obsolete.t
+++ b/tests/test-obsolete.t
@@ -627,6 +627,26 @@
   abort: push includes orphan changeset: cda648ca50f5!
   [255]
 
+with --force it will work anyway
+
+  $ hg push ../tmpc/ --force
+  pushing to ../tmpc/
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 2 changesets with 2 changes to 2 files
+  1 new obsolescence markers
+  1 new orphan changesets
+
+if the orphan changeset is already on the server, pushing should work
+
+  $ hg push ../tmpc/
+  pushing to ../tmpc/
+  searching for changes
+  no changes found
+  [1]
+
 Test that extinct changeset are properly detected
 
   $ hg log -r 'extinct()'
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


[PATCH 2 of 2] exchange: check actually missing revs for obsolete / unstable revs (issue6372)

2020-07-17 Thread Manuel Jacob
# HG changeset patch
# User Manuel Jacob 
# Date 1594966891 -7200
#  Fri Jul 17 08:21:31 2020 +0200
# Node ID 91c59e59daae6b4bc0fe86b09c01fcc2e1aace9d
# Parent  55626b2da7d55766ae667d91652d094c0c4aa86f
# EXP-Topic issue6372
exchange: check actually missing revs for obsolete / unstable revs (issue6372)

The previous code was using `outgoing.missingheads`, which, despite the name,
doesn’t contain the missing heads but all changesets that were passed to the
push via `-r` (or `repo.heads()` by default), i.e. it may contain changesets
that are not heads and / or already on the server.

The actually outgoing changesets are stored in `outgoing.missing`. By checking
all outgoing changesets, we avoid the problem and can show the list of all
obsolete or unstable changesets, which is more helpful for the user.

diff --git a/mercurial/exchange.py b/mercurial/exchange.py
--- a/mercurial/exchange.py
+++ b/mercurial/exchange.py
@@ -905,27 +905,32 @@
 # if repo.obsstore == False --> no obsolete
 # then, save the iteration
 if unfi.obsstore:
-# this message are here for 80 char limit reason
-mso = _(b"push includes obsolete changeset: %s!")
-mspd = _(b"push includes phase-divergent changeset: %s!")
-mscd = _(b"push includes content-divergent changeset: %s!")
-mst = {
-b"orphan": _(b"push includes orphan changeset: %s!"),
-b"phase-divergent": mspd,
-b"content-divergent": mscd,
-}
-# If we are to push if there is at least one
-# obsolete or unstable changeset in missing, at
-# least one of the missinghead will be obsolete or
-# unstable. So checking heads only is ok
-for node in outgoing.missingheads:
+obsoletes = []
+unstables = []
+for node in outgoing.missing:
 ctx = unfi[node]
 if ctx.obsolete():
-raise error.Abort(mso % ctx)
+obsoletes.append(ctx)
 elif ctx.isunstable():
-# TODO print more than one instability in the abort
-# message
-raise error.Abort(mst[ctx.instabilities()[0]] % ctx)
+unstables.append(ctx)
+if obsoletes or unstables:
+msg = b""
+if obsoletes:
+msg += _(b"push includes obsolete changesets:\n")
+msg += b"\n".join(b'  %s' % ctx for ctx in obsoletes)
+if unstables:
+if msg:
+msg += b"\n"
+msg += _(b"push includes unstable changesets:\n")
+msg += b"\n".join(
+b'  %s (%s)'
+% (
+ctx,
+b", ".join(_(ins) for ins in ctx.instabilities()),
+)
+for ctx in unstables
+)
+raise error.Abort(msg)
 
 discovery.checkheads(pushop)
 return True
diff --git a/tests/test-obsolete-divergent.t b/tests/test-obsolete-divergent.t
--- a/tests/test-obsolete-divergent.t
+++ b/tests/test-obsolete-divergent.t
@@ -118,7 +118,9 @@
   $ hg push ../other
   pushing to ../other
   searching for changes
-  abort: push includes content-divergent changeset: 392fd25390da!
+  abort: push includes unstable changesets:
+82623d38b9ba (content-divergent)
+392fd25390da (content-divergent)
   [255]
 
   $ cd ..
diff --git a/tests/test-obsolete.t b/tests/test-obsolete.t
--- a/tests/test-obsolete.t
+++ b/tests/test-obsolete.t
@@ -251,7 +251,8 @@
   $ hg push ../tmpa
   pushing to ../tmpa
   searching for changes
-  abort: push includes phase-divergent changeset: 5601fb93a350!
+  abort: push includes unstable changesets:
+5601fb93a350 (phase-divergent)
   [255]
 
 Fixing "bumped" situation
@@ -616,7 +617,8 @@
   $ hg push ../tmpc/ -r 'desc("original_d")'
   pushing to ../tmpc/
   searching for changes
-  abort: push includes obsolete changeset: 94b33453f93b!
+  abort: push includes obsolete changesets:
+94b33453f93b
   [255]
 
 refuse to push unstable changeset
@@ -624,7 +626,10 @@
   $ hg push ../tmpc/
   pushing to ../tmpc/
   searching for changes
-  abort: push includes orphan changeset: cda648ca50f5!
+  abort: push includes obsolete changesets:
+94b33453f93b
+  push includes unstable changesets:
+cda648ca50f5 (orphan)
   [255]
 
 with --force it will work anyway
@@ -647,6 +652,26 @@
   no changes found
   [1]
 
+pushing should work even if the outgoing changes contain an unrelated changeset
+(neither obsolete nor unstable) (issue6372)
+
+  $ hg up 1 -q
+  $ hg branch new -q
+  $ mkcommit c
+
+  $ hg push ../tmpc/ --new-branch
+  pushing to ../tmpc/
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+