From cfcb7e12942d826c0c84c01966c0a47483b1d618 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Rowlands=20=28=EB=B3=80=EA=B8=B0=ED=98=B8=29?= Date: Sat, 3 Jul 2021 00:00:47 +0900 Subject: [PATCH] pygit: handle annotated tags in resolve_refish (#6274) --- dvc/scm/git/backend/pygit2.py | 21 +++++++++++++++------ tests/unit/scm/test_git.py | 27 +++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/dvc/scm/git/backend/pygit2.py b/dvc/scm/git/backend/pygit2.py index fe6b97d96f..aeee30579b 100644 --- a/dvc/scm/git/backend/pygit2.py +++ b/dvc/scm/git/backend/pygit2.py @@ -94,6 +94,15 @@ def _refdb(self): return RefdbFsBackend(self.repo) + def _resolve_refish(self, refish: str): + from pygit2 import GIT_OBJ_COMMIT, Tag + + commit, ref = self.repo.resolve_refish(refish) + if isinstance(commit, Tag): + ref = commit + commit = commit.peel(GIT_OBJ_COMMIT) + return commit, ref + @property def default_signature(self): try: @@ -153,7 +162,7 @@ def checkout( if branch == "-": branch = "@{-1}" try: - commit, ref = self.repo.resolve_refish(branch) + commit, ref = self._resolve_refish(branch) except (KeyError, GitError): raise RevError(f"unknown Git revision '{branch}'") self.repo.checkout_tree(commit, strategy=checkout_strategy) @@ -213,7 +222,7 @@ def resolve_rev(self, rev: str) -> str: from pygit2 import GitError try: - commit, _ref = self.repo.resolve_refish(rev) + commit, _ref = self._resolve_refish(rev) return str(commit.id) except (KeyError, GitError): pass @@ -233,7 +242,7 @@ def resolve_commit(self, rev: str) -> "GitCommit": from pygit2 import GitError try: - commit, _ref = self.repo.resolve_refish(rev) + commit, _ref = self._resolve_refish(rev) except (KeyError, GitError): raise SCMError(f"Invalid commit '{rev}'") return GitCommit( @@ -307,12 +316,12 @@ def get_refs_containing(self, rev: str, pattern: Optional[str] = None): from pygit2 import GitError def _contains(repo, ref, search_commit): - commit, _ref = self.repo.resolve_refish(ref) + commit, _ref = self._resolve_refish(ref) base = repo.merge_base(search_commit.id, commit.id) return base == search_commit.id try: - search_commit, _ref = self.repo.resolve_refish(rev) + search_commit, _ref = self._resolve_refish(rev) except (KeyError, GitError): raise SCMError(f"Invalid rev '{rev}'") @@ -397,7 +406,7 @@ def _apply(index): # libgit2 stash apply only accepts refs/stash items by index. If rev is # not in refs/stash, we will push it onto the stash, and then pop it - commit, _ref = self.repo.resolve_refish(rev) + commit, _ref = self._resolve_refish(rev) stash = self.repo.references.get(Stash.DEFAULT_STASH) if stash: for i, entry in enumerate(stash.log()): diff --git a/tests/unit/scm/test_git.py b/tests/unit/scm/test_git.py index 3303b21b67..1c3b09daa5 100644 --- a/tests/unit/scm/test_git.py +++ b/tests/unit/scm/test_git.py @@ -553,3 +553,30 @@ def test_add(tmp_dir, scm, git): assert set(staged["modify"]) == {"dir/baz"} assert len(unstaged) == 1 assert len(untracked) == 1 + + +@pytest.mark.parametrize("use_sha", [True, False]) +def test_pygit_resolve_refish(tmp_dir, scm, git, use_sha): + import pygit2 + + if git.test_backend != "pygit2": + pytest.skip() + + tmp_dir.scm_gen("foo", "foo", commit="foo") + head = scm.get_rev() + tag = "my_tag" + scm.gitpython.git.tag("-a", tag, "-m", "create annotated tag") + + if use_sha: + # refish will be annotated tag SHA (not commit SHA) + ref = git.pygit2.repo.references.get(f"refs/tags/{tag}") + refish = str(ref.target) + else: + refish = tag + + assert refish != head + commit, ref = git.pygit2._resolve_refish(refish) + assert isinstance(commit, pygit2.Commit) + assert str(commit.id) == head + if not use_sha: + assert ref.name == f"refs/tags/{tag}"