Repository: airspeed-velocity/asv

Issue:
compare should understand any committish - rev-parse call is missing?
ATM (with 0.3.dev1232+cba62ac1) you must specify commit hexshas to `compare`:

```shell
$> asv compare -m hopa 0.9.x master             
· Did not find results for commit 0.9.x
```

and what is needed is just to run `git rev-parse` on every entry there:

```shell
$> grp(){git rev-parse $1;}; asv compare -m hopa $(grp 0.9.x) $(grp master)

All benchmarks:

       before           after         ratio
     [b619eca4]       [7635f467]
-           1.87s            1.54s     0.82  api.supers.time_createadd
-           1.85s            1.56s     0.84  api.supers.time_createadd_to_dataset
-           5.57s            4.40s     0.79  api.supers.time_installr
          145±6ms          145±6ms     1.00  api.supers.time_ls
-           4.59s            2.17s     0.47  api.supers.time_remove
          427±1ms          434±8ms     1.02  api.testds.time_create_test_dataset1
-           4.10s            3.37s     0.82  api.testds.time_create_test_dataset2x2
      1.81±0.07ms      1.73±0.04ms     0.96  core.runner.time_echo
       2.30±0.2ms      2.04±0.03ms    ~0.89  core.runner.time_echo_gitrunner
+        420±10ms          535±3ms     1.27  core.startup.time_help_np
          111±6ms          107±3ms     0.96  core.startup.time_import
+         334±6ms          466±4ms     1.39  core.startup.time_import_api
```
which also would work with any other committish known to git:

```shell
$> grp(){git rev-parse $1;}; asv compare -m hopa $(grp HEAD^) $(grp HEAD)                     
                                 
All benchmarks:

       before           after         ratio
     [1c69998e]       [b619eca4]
-           2.16s            1.87s     0.87  api.supers.time_createadd
            1.98s            1.85s     0.93  api.supers.time_createadd_to_dataset
-           6.15s            5.57s     0.91  api.supers.time_installr
          144±7ms          145±6ms     1.01  api.supers.time_ls
+           4.04s            4.59s     1.14  api.supers.time_remove
        453±0.7ms          427±1ms     0.94  api.testds.time_create_test_dataset1
+           3.66s            4.10s     1.12  api.testds.time_create_test_dataset2x2
       2.34±0.1ms      1.81±0.07ms    ~0.77  core.runner.time_echo
       2.62±0.2ms       2.30±0.2ms    ~0.88  core.runner.time_echo_gitrunner
         299±20ms         420±10ms    ~1.41  core.startup.time_help_np
         86.6±5ms          111±6ms    ~1.28  core.startup.time_import
         292±30ms          334±6ms    ~1.15  core.startup.time_import_api
```

(I think smth like that done already for `continuous`, `run` etc)

Discussion:

Patch:
diff --git a/asv/commands/compare.py b/asv/commands/compare.py
index 55c54b8..7a6e69d 100644
--- a/asv/commands/compare.py
+++ b/asv/commands/compare.py
@@ -9,6 +9,7 @@ import itertools
 from . import Command
 from ..machine import iter_machine_files
 from ..results import iter_results_for_machine_and_hash
+from ..repo import get_repo, NoSuchNameError
 from ..util import human_value, load_json
 from ..console import log, color_print
 from ..environment import get_environments
@@ -126,6 +127,17 @@ class Compare(Command):
     def run(cls, conf, hash_1, hash_2, factor=None, split=False, only_changed=False,
             sort='name', machine=None, env_spec=None):
 
+        repo = get_repo(conf)
+        try:
+            hash_1 = repo.get_hash_from_name(hash_1)
+        except NoSuchNameError:
+            pass
+
+        try:
+            hash_2 = repo.get_hash_from_name(hash_2)
+        except NoSuchNameError:
+            pass
+
         if env_spec:
             env_names = ([env.name for env in get_environments(conf, env_spec, verbose=False)]
                          + list(env_spec))
diff --git a/asv/commands/continuous.py b/asv/commands/continuous.py
index 17f1f16..c475ba4 100644
--- a/asv/commands/continuous.py
+++ b/asv/commands/continuous.py
@@ -11,7 +11,7 @@ from . import Command
 from .run import Run
 from .compare import Compare
 
-from ..repo import get_repo
+from ..repo import get_repo, NoSuchNameError
 from ..console import color_print, log
 from .. import results
 from .. import util
@@ -74,12 +74,16 @@ class Continuous(Command):
 
         if branch is None:
             branch = conf.branches[0]
-        head = repo.get_hash_from_name(branch)
 
-        if base is None:
-            parent = repo.get_hash_from_parent(head)
-        else:
-            parent = repo.get_hash_from_name(base)
+        try:
+            head = repo.get_hash_from_name(branch)
+
+            if base is None:
+                parent = repo.get_hash_from_parent(head)
+            else:
+                parent = repo.get_hash_from_name(base)
+        except NoSuchNameError as exc:
+            raise util.UserError("Unknown commit {0}".format(exc))
 
         commit_hashes = [head, parent]
         run_objs = {}
diff --git a/asv/commands/profiling.py b/asv/commands/profiling.py
index 8028862..cc669a8 100644
--- a/asv/commands/profiling.py
+++ b/asv/commands/profiling.py
@@ -17,7 +17,7 @@ from ..console import log, color_print
 from ..environment import get_environments, is_existing_only
 from ..machine import Machine
 from ..profiling import ProfilerGui
-from ..repo import get_repo
+from ..repo import get_repo, NoSuchNameError
 from ..results import iter_results_for_machine
 from ..runner import run_benchmarks
 from ..util import hash_equal, iter_subclasses
@@ -126,7 +126,11 @@ class Profile(Command):
             rev = conf.branches[0]
         else:
             rev = revision
-        commit_hash = repo.get_hash_from_name(rev)
+
+        try:
+            commit_hash = repo.get_hash_from_name(rev)
+        except NoSuchNameError as exc:
+            raise util.UserError("Unknown commit {0}".format(exc))
 
         profile_data = None
         checked_out = set()
diff --git a/asv/commands/run.py b/asv/commands/run.py
index 353e5cc..33ff568 100644
--- a/asv/commands/run.py
+++ b/asv/commands/run.py
@@ -14,7 +14,7 @@ from . import Command
 from ..benchmarks import Benchmarks
 from ..console import log
 from ..machine import Machine
-from ..repo import get_repo
+from ..repo import get_repo, NoSuchNameError
 from ..results import (Results, get_existing_hashes,
                        iter_results_for_machine_and_hash)
 from ..runner import run_benchmarks, skip_benchmarks
@@ -153,7 +153,10 @@ class Run(Command):
             repo.pull()
 
         if range_spec is None:
-            commit_hashes = list(set([repo.get_hash_from_name(branch) for branch in conf.branches]))
+            try:
+                commit_hashes = list(set([repo.get_hash_from_name(branch) for branch in conf.branches]))
+            except NoSuchNameError as exc:
+                raise util.UserError('Unknown branch {0} in configuration'.format(exc))
         elif range_spec == 'EXISTING':
             commit_hashes = get_existing_hashes(conf.results_dir)
         elif range_spec == "NEW":
diff --git a/asv/plugins/git.py b/asv/plugins/git.py
index 04ee9d5..dc32389 100644
--- a/asv/plugins/git.py
+++ b/asv/plugins/git.py
@@ -130,6 +130,7 @@ class Git(Repo):
 
         try:
             return self._run_git(['rev-parse', name],
+                                 display_error=False,
                                  dots=False).strip().split()[0]
         except util.ProcessError as err:
             if err.stdout.strip() == name:


Test patch:
diff --git a/test/test_compare.py b/test/test_compare.py
index c843623..3674c31 100644
--- a/test/test_compare.py
+++ b/test/test_compare.py
@@ -6,17 +6,24 @@ from __future__ import (absolute_import, division, print_function,
 
 import os
 from os.path import abspath, dirname, join
-import sys
 
 import six
+import pytest
+import shutil
 
 from asv import config
+from asv import util
 
 from asv.commands.compare import Compare
-from argparse import Namespace
 
 from . import tools
 
+try:
+    import hglib
+except ImportError:
+    hglib = None
+
+
 RESULT_DIR = abspath(join(dirname(__file__), 'example_results'))
 MACHINE_FILE = abspath(join(dirname(__file__), 'asv-machine.json'))
 
@@ -166,3 +173,47 @@ def test_compare(capsys, tmpdir):
                                  split=False, only_changed=True, sort='ratio')
     text, err = capsys.readouterr()
     assert text.strip() == REFERENCE_ONLY_CHANGED_MULTIENV.strip()
+
+
+@pytest.mark.parametrize("dvcs_type", [
+    "git",
+    pytest.mark.skipif(hglib is None, reason="needs hglib")("hg"),
+])
+def test_compare_name_lookup(dvcs_type, capsys, tmpdir):
+    tmpdir = six.text_type(tmpdir)
+    os.chdir(tmpdir)
+
+    repo = tools.generate_test_repo(tmpdir, dvcs_type=dvcs_type)
+    branch_name = 'master' if dvcs_type == 'git' else 'default'
+    commit_hash = repo.get_branch_hashes(branch_name)[0]
+
+    result_dir = os.path.join(tmpdir, 'results')
+
+    src = os.path.join(RESULT_DIR, 'cheetah')
+    dst = os.path.join(result_dir, 'cheetah')
+    os.makedirs(dst)
+
+    for fn in ['feea15ca-py2.7-Cython-numpy1.8.json', 'machine.json']:
+        shutil.copyfile(os.path.join(src, fn), os.path.join(dst, fn))
+
+    # Copy to different commit
+    fn_1 = os.path.join(dst, 'feea15ca-py2.7-Cython-numpy1.8.json')
+    fn_2 = os.path.join(dst, commit_hash[:8] + '-py2.7-Cython-numpy1.8.json')
+    data = util.load_json(fn_1, cleanup=False)
+    data['commit_hash'] = commit_hash
+    util.write_json(fn_2, data)
+
+    conf = config.Config.from_json(
+        {'results_dir': result_dir,
+         'repo': repo.path,
+         'project': 'asv',
+         'environment_type': "shouldn't matter what"})
+
+    # Lookup with symbolic name
+    tools.run_asv_with_conf(conf, 'compare', branch_name, 'feea15ca', '--machine=cheetah',
+                            '--factor=2', '--environment=py2.7-Cython-numpy1.8',
+                            '--only-changed')
+
+    # Nothing should be printed since no results were changed
+    text, err = capsys.readouterr()
+    assert text.strip() == ''