2

I'm trying to script hg diff and want to accept an argument that will be passed to the -r option, and if no argument is given, to default to the working directory. However, it appears there is no value that can be passed to -r to indicate "working directory", and instead the option must be omitted entirely, which leads to the following logic in my script:

if [ -z "${to_rev}" ]; then
  to_rev_args=""
else
  to_rev_args="-r ${to_rev}"
fi

hg diff ... ${to_rev_args}

Am I correct in believing this is the only way? We can assume that making the script accept a -r argument and passing the whole thing on to Mercurial is not an option; the arguments must conform to a style used by a suite of tools.

John Freeman
  • 2,552
  • 1
  • 27
  • 34
  • 1
    Well, `hg diff` without options is equivalent to `hg diff -r .`, and `.` denotes the *parent* of the working directory. With one revision argument, Mercurial will compare the working directory to whatever the specified revision is (and if omitted, to `.`). Can you be more specific, i.e. what are you trying to diff the working directory (or any other revision) against? – Reimer Behrends Feb 04 '16 at 16:24
  • I want to find diffs between two states. By default, the "before" state is the last public ancestor of the current parent, and the "after" state is the working directory, but the script may accept arguments for either state and pass them on to hg diff. It easier to unconditionally pass arguments to hg diff than to conditionally pass them based on the value of the script's arguments, therefore, I would like to know a value for the script's default "after" argument that is equivalent to "working directory" when passed to hg diff. – John Freeman Feb 05 '16 at 22:50

1 Answers1

1

The following Mercurial extension should do what you need, by allowing you to specify the working directory as a pseudo revision named "=".

"""wdir diff

Allows specifying the working directory as a pseudo revision.
"""

testedwith = "3.5"
wdir_pseudo_rev = "="

from mercurial import commands, extensions

def wrap_diff(original_cmd, ui, repo, *pats, **opts):
  revargs = opts["rev"]
  if len(revargs) == 1:
    if revargs[0] == wdir_pseudo_rev:
      return
  elif len(revargs) == 2:
    if revargs[0] == wdir_pseudo_rev:
      if revargs[1] == wdir_pseudo_rev:
        return
      else:
        revargs.remove(wdir_pseudo_rev)
    elif revargs[1] == wdir_pseudo_rev:
      revargs.remove(wdir_pseudo_rev)
      opts["reverse"] = not opts["reverse"]
  return original_cmd(ui, repo, *pats, **opts)

def uisetup(ui):
  extensions.wrapcommand(commands.table, "diff", wrap_diff)

The same logic can also fairly easily be encoded in a script or other program code if you don't want the hassle of dealing with an extension, you just have to distinguish between four different cases:

Assume that you want to diff REV1 and REV2, where either revision may be the working directory:

  1. If both REV1 and REV2 represent the working directory, do nothing.
  2. If REV1 represents the working directory, and REV2 is an actual revision, use hg diff -r REV2.
  3. If REV1 is an actual revision, and REV2 represents the working directory, use hg diff --reverse -r REV1.
  4. If both REV1 and REV2 are actual revisions, use hg diff -r REV1 -r REV2.
Reimer Behrends
  • 8,600
  • 15
  • 19
  • I haven't checked to make sure this works, but its existence means the answer to my question is "no", and I appreciate the contribution of a patch. – John Freeman Feb 09 '16 at 18:37
  • Correct, there is no way to specify the working directory as a revision and I was describing a workaround; my apologies if that wasn't clear. – Reimer Behrends Feb 09 '16 at 21:45