diff --git a/pip/vcs/git.py b/pip/vcs/git.py index 7cb089ab9..16acebdc4 100644 --- a/pip/vcs/git.py +++ b/pip/vcs/git.py @@ -67,8 +67,7 @@ class Git(VersionControl): and branches may need origin/ as a prefix. Returns the SHA1 of the branch or tag if found. """ - revisions = self.get_tag_revs(dest) - revisions.update(self.get_branch_revs(dest)) + revisions = self.get_refs(dest) origin_rev = 'origin/%s' % rev if origin_rev in revisions: @@ -129,30 +128,24 @@ class Git(VersionControl): [self.cmd, 'rev-parse', 'HEAD'], show_stdout=False, cwd=location) return current_rev.strip() - def get_tag_revs(self, location): - tags = self._get_all_tag_names(location) - tag_revs = {} - for line in tags.splitlines(): - tag = line.strip() - rev = self._get_revision_from_rev_parse(tag, location) - tag_revs[tag] = rev.strip() - return tag_revs - - def get_branch_revs(self, location): - rev_names = call_subprocess([self.cmd, 'show-ref'], - show_stdout=False, cwd=location) - branch_revs = {} - for line in rev_names.strip().splitlines(): - rev, ref = line.split(' ', 1) + def get_refs(self, location): + """Return map of named refs (branches or tags) to commit hashes.""" + output = call_subprocess([self.cmd, 'show-ref'], + show_stdout=False, cwd=location) + rv = {} + for line in output.strip().splitlines(): + commit, ref = line.split(' ', 1) ref = ref.strip() - branch = None + ref_name = None if ref.startswith('refs/remotes/'): - branch = ref[len('refs/remotes/'):] + ref_name = ref[len('refs/remotes/'):] elif ref.startswith('refs/heads/'): - branch = ref[len('refs/heads/'):] - if branch is not None: - branch_revs[branch] = rev.strip() - return branch_revs + ref_name = ref[len('refs/heads/'):] + elif ref.startswith('refs/tags/'): + ref_name = ref[len('refs/tags/'):] + if ref_name is not None: + rv[ref_name] = commit.strip() + return rv def get_src_requirement(self, dist, location, find_tags): repo = self.get_url(location) @@ -162,19 +155,14 @@ class Git(VersionControl): if not repo: return None current_rev = self.get_revision(location) - tag_revs = self.get_tag_revs(location) - branch_revs = self.get_branch_revs(location) + refs = self.get_refs(location) + # refs maps names to commit hashes; we need the inverse + # if multiple names map to a single commit, this arbitrarily picks one + names_by_commit = dict((commit, ref) for ref, commit in refs.items()) - if current_rev in tag_revs: + if current_rev in names_by_commit: # It's a tag - full_egg_name = '%s-%s' % (egg_project_name, tag_revs[current_rev]) - elif (current_rev in branch_revs and - branch_revs[current_rev] != 'origin/master'): - # It's the head of a branch - full_egg_name = '%s-%s' % ( - egg_project_name, - branch_revs[current_rev].replace('origin/', '') - ) + full_egg_name = '%s-%s' % (egg_project_name, names_by_commit[current_rev]) else: full_egg_name = '%s-dev' % egg_project_name @@ -197,16 +185,6 @@ class Git(VersionControl): return url, rev - def _get_all_tag_names(self, location): - return call_subprocess([self.cmd, 'tag', '-l'], - show_stdout=False, - raise_on_returncode=False, - cwd=location) - - def _get_revision_from_rev_parse(self, name, location): - return call_subprocess([self.cmd, 'rev-parse', name], - show_stdout=False, cwd=location) - def update_submodules(self, location): if not os.path.exists(os.path.join(location, '.gitmodules')): return diff --git a/tests/test_freeze.py b/tests/test_freeze.py index 1210a8c52..90ca5369e 100644 --- a/tests/test_freeze.py +++ b/tests/test_freeze.py @@ -107,7 +107,7 @@ def test_freeze_git_clone(): Script result: pip freeze -f %(repo)s#egg=pip_test_package -- stdout: -------------------- -f %(repo)s#egg=pip_test_package... - -e %(repo)s@...#egg=pip_test_package-dev + -e %(repo)s@...#egg=pip_test_package-0.1.1 ...""" % {'repo': local_checkout('git+http://github.com/pypa/pip-test-package.git')}) _check_output(result, expected) diff --git a/tests/test_vcs_git.py b/tests/test_vcs_git.py index a15afc9be..049e6ce26 100644 --- a/tests/test_vcs_git.py +++ b/tests/test_vcs_git.py @@ -11,7 +11,7 @@ from tests.git_submodule_helpers import ( ) -def test_get_tag_revs_should_return_tag_name_and_commit_pair(): +def test_get_refs_should_return_tag_name_and_commit_pair(): env = reset_env() version_pkg_path = _create_test_package(env) env.run('git', 'tag', '0.1', cwd=version_pkg_path) @@ -19,22 +19,24 @@ def test_get_tag_revs_should_return_tag_name_and_commit_pair(): commit = env.run('git', 'rev-parse', 'HEAD', cwd=version_pkg_path).stdout.strip() git = Git() - result = git.get_tag_revs(version_pkg_path) - assert result == {'0.1': commit, '0.2': commit}, result + result = git.get_refs(version_pkg_path) + assert result['0.1'] == commit, result + assert result['0.2'] == commit, result -def test_get_branch_revs_should_return_branch_name_and_commit_pair(): +def test_get_refs_should_return_branch_name_and_commit_pair(): env = reset_env() version_pkg_path = _create_test_package(env) env.run('git', 'branch', 'branch0.1', cwd=version_pkg_path) commit = env.run('git', 'rev-parse', 'HEAD', cwd=version_pkg_path).stdout.strip() git = Git() - result = git.get_branch_revs(version_pkg_path) - assert result == {'master': commit, 'branch0.1': commit}, result + result = git.get_refs(version_pkg_path) + assert result['master'] == commit, result + assert result['branch0.1'] == commit, result -def test_get_branch_revs_should_ignore_no_branch(): +def test_get_refs_should_ignore_no_branch(): env = reset_env() version_pkg_path = _create_test_package(env) env.run('git', 'branch', 'branch0.1', cwd=version_pkg_path) @@ -44,40 +46,32 @@ def test_get_branch_revs_should_ignore_no_branch(): env.run('git', 'checkout', commit, cwd=version_pkg_path, expect_stderr=True) git = Git() - result = git.get_branch_revs(version_pkg_path) - assert result == {'master': commit, 'branch0.1': commit}, result + result = git.get_refs(version_pkg_path) + assert result['master'] == commit, result + assert result['branch0.1'] == commit, result -@patch('pip.vcs.git.Git.get_tag_revs') -@patch('pip.vcs.git.Git.get_branch_revs') -def test_check_rev_options_should_handle_branch_name(branches_revs_mock, - tags_revs_mock): - branches_revs_mock.return_value = {'master': '123456'} - tags_revs_mock.return_value = {'0.1': '123456'} +@patch('pip.vcs.git.Git.get_refs') +def test_check_rev_options_should_handle_branch_name(get_refs_mock): + get_refs_mock.return_value = {'master': '123456', '0.1': '123456'} git = Git() result = git.check_rev_options('master', '.', []) assert result == ['123456'] -@patch('pip.vcs.git.Git.get_tag_revs') -@patch('pip.vcs.git.Git.get_branch_revs') -def test_check_rev_options_should_handle_tag_name(branches_revs_mock, - tags_revs_mock): - branches_revs_mock.return_value = {'master': '123456'} - tags_revs_mock.return_value = {'0.1': '123456'} +@patch('pip.vcs.git.Git.get_refs') +def test_check_rev_options_should_handle_tag_name(get_refs_mock): + get_refs_mock.return_value = {'master': '123456', '0.1': '123456'} git = Git() result = git.check_rev_options('0.1', '.', []) assert result == ['123456'] -@patch('pip.vcs.git.Git.get_tag_revs') -@patch('pip.vcs.git.Git.get_branch_revs') -def test_check_rev_options_should_handle_ambiguous_commit(branches_revs_mock, - tags_revs_mock): - branches_revs_mock.return_value = {'master': '123456'} - tags_revs_mock.return_value = {'0.1': '123456'} +@patch('pip.vcs.git.Git.get_refs') +def test_check_rev_options_should_handle_ambiguous_commit(get_refs_mock): + get_refs_mock.return_value = {'master': '123456', '0.1': '123456'} git = Git() result = git.check_rev_options('0.1', '.', [])