aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--repository.go45
-rw-r--r--repository_test.go21
2 files changed, 55 insertions, 11 deletions
diff --git a/repository.go b/repository.go
index ddf6727..651425d 100644
--- a/repository.go
+++ b/repository.go
@@ -1171,7 +1171,18 @@ func (r *Repository) Worktree() (*Worktree, error) {
return &Worktree{r: r, Filesystem: r.wt}, nil
}
-// ResolveRevision resolves revision to corresponding hash.
+func countTrue(vals ...bool) int {
+ sum := 0
+ for _, v := range vals {
+ if v {
+ sum++
+ }
+ }
+ return sum
+}
+
+// ResolveRevision resolves revision to corresponding hash. It will always
+// resolve to a commit hash, not a tree or annotated tag.
//
// Implemented resolvers : HEAD, branch, tag, heads/branch, refs/heads/branch,
// refs/tags/tag, refs/remotes/origin/branch, refs/remotes/origin/HEAD, tilde and caret (HEAD~1, master~^, tag~2, ref/heads/master~1, ...), selection by text (HEAD^{/fix nasty bug})
@@ -1191,8 +1202,8 @@ func (r *Repository) ResolveRevision(rev plumbing.Revision) (*plumbing.Hash, err
case revision.Ref:
revisionRef := item.(revision.Ref)
var ref *plumbing.Reference
- var hashCommit, refCommit *object.Commit
- var rErr, hErr error
+ var hashCommit, refCommit, tagCommit *object.Commit
+ var rErr, hErr, tErr error
for _, rule := range append([]string{"%s"}, plumbing.RefRevParseRules...) {
ref, err = storer.ResolveReference(r.Storer, plumbing.ReferenceName(fmt.Sprintf(rule, revisionRef)))
@@ -1203,24 +1214,38 @@ func (r *Repository) ResolveRevision(rev plumbing.Revision) (*plumbing.Hash, err
}
if ref != nil {
+ tag, tObjErr := r.TagObject(ref.Hash())
+ if tObjErr != nil {
+ tErr = tObjErr
+ } else {
+ tagCommit, tErr = tag.Commit()
+ }
refCommit, rErr = r.CommitObject(ref.Hash())
} else {
rErr = plumbing.ErrReferenceNotFound
+ tErr = plumbing.ErrReferenceNotFound
}
- isHash := plumbing.NewHash(string(revisionRef)).String() == string(revisionRef)
-
- if isHash {
+ maybeHash := plumbing.NewHash(string(revisionRef)).String() == string(revisionRef)
+ if maybeHash {
hashCommit, hErr = r.CommitObject(plumbing.NewHash(string(revisionRef)))
+ } else {
+ hErr = plumbing.ErrReferenceNotFound
}
+ isTag := tErr == nil
+ isCommit := rErr == nil
+ isHash := hErr == nil
+
switch {
- case rErr == nil && !isHash:
+ case countTrue(isTag, isCommit, isHash) > 1:
+ return &plumbing.ZeroHash, fmt.Errorf(`refname "%s" is ambiguous`, revisionRef)
+ case isTag:
+ commit = tagCommit
+ case isCommit:
commit = refCommit
- case rErr != nil && isHash && hErr == nil:
+ case isHash:
commit = hashCommit
- case rErr == nil && isHash && hErr == nil:
- return &plumbing.ZeroHash, fmt.Errorf(`refname "%s" is ambiguous`, revisionRef)
default:
return &plumbing.ZeroHash, plumbing.ErrReferenceNotFound
}
diff --git a/repository_test.go b/repository_test.go
index 6d34d42..6959933 100644
--- a/repository_test.go
+++ b/repository_test.go
@@ -2065,7 +2065,26 @@ func (s *RepositorySuite) TestResolveRevision(c *C) {
h, err := r.ResolveRevision(plumbing.Revision(rev))
c.Assert(err, IsNil)
- c.Assert(h.String(), Equals, hash)
+ c.Check(h.String(), Equals, hash, Commentf("while checking %s", rev))
+ }
+}
+
+func (s *RepositorySuite) TestResolveRevisionAnnotated(c *C) {
+ f := fixtures.ByURL("https://github.com/git-fixtures/tags.git").One()
+ sto, err := filesystem.NewStorage(f.DotGit())
+ c.Assert(err, IsNil)
+ r, err := Open(sto, f.DotGit())
+ c.Assert(err, IsNil)
+
+ datas := map[string]string{
+ "refs/tags/annotated-tag": "f7b877701fbf855b44c0a9e86f3fdce2c298b07f",
+ }
+
+ for rev, hash := range datas {
+ h, err := r.ResolveRevision(plumbing.Revision(rev))
+
+ c.Assert(err, IsNil)
+ c.Check(h.String(), Equals, hash, Commentf("while checking %s", rev))
}
}