aboutsummaryrefslogtreecommitdiffstats
path: root/repository.go
diff options
context:
space:
mode:
authorMáximo Cuadros <mcuadros@gmail.com>2019-05-16 01:16:48 +0200
committerGitHub <noreply@github.com>2019-05-16 01:16:48 +0200
commit24de5efe77a202ddba83abb4d14095474dcdf1f6 (patch)
treedbbf58de086de41ce326264585964bb774aa36d0 /repository.go
parent52fcf7d8a3c2da58769e105a26240e3e697fedeb (diff)
parent33f05f3773e1c1e6b4fdde5ee984f6b1935afbfc (diff)
downloadgo-git-24de5efe77a202ddba83abb4d14095474dcdf1f6.tar.gz
Merge pull request #1146 from novas0x2a/fix-tag-oid
improve ResolveRevision's Ref lookup path
Diffstat (limited to 'repository.go')
-rw-r--r--repository.go81
1 files changed, 37 insertions, 44 deletions
diff --git a/repository.go b/repository.go
index e5b12b0..a94dc2f 100644
--- a/repository.go
+++ b/repository.go
@@ -1306,16 +1306,6 @@ func (r *Repository) Worktree() (*Worktree, error) {
return &Worktree{r: r, Filesystem: r.wt}, nil
}
-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.
//
@@ -1336,54 +1326,57 @@ func (r *Repository) ResolveRevision(rev plumbing.Revision) (*plumbing.Hash, err
switch item.(type) {
case revision.Ref:
revisionRef := item.(revision.Ref)
- var ref *plumbing.Reference
- var hashCommit, refCommit, tagCommit *object.Commit
- var rErr, hErr, tErr error
+
+ var tryHashes []plumbing.Hash
+
+ maybeHash := plumbing.NewHash(string(revisionRef))
+
+ if !maybeHash.IsZero() {
+ tryHashes = append(tryHashes, maybeHash)
+ }
for _, rule := range append([]string{"%s"}, plumbing.RefRevParseRules...) {
- ref, err = storer.ResolveReference(r.Storer, plumbing.ReferenceName(fmt.Sprintf(rule, revisionRef)))
+ ref, err := storer.ResolveReference(r.Storer, plumbing.ReferenceName(fmt.Sprintf(rule, revisionRef)))
if err == nil {
+ tryHashes = append(tryHashes, ref.Hash())
break
}
}
- if ref != nil {
- tag, tObjErr := r.TagObject(ref.Hash())
- if tObjErr != nil {
- tErr = tObjErr
- } else {
- tagCommit, tErr = tag.Commit()
+ // in ambiguous cases, `git rev-parse` will emit a warning, but
+ // will always return the oid in preference to a ref; we don't have
+ // the ability to emit a warning here, so (for speed purposes)
+ // don't bother to detect the ambiguity either, just return in the
+ // priority that git would.
+ gotOne := false
+ for _, hash := range tryHashes {
+ commitObj, err := r.CommitObject(hash)
+ if err == nil {
+ commit = commitObj
+ gotOne = true
+ break
}
- refCommit, rErr = r.CommitObject(ref.Hash())
- } else {
- rErr = plumbing.ErrReferenceNotFound
- tErr = plumbing.ErrReferenceNotFound
- }
- maybeHash := plumbing.NewHash(string(revisionRef)).String() == string(revisionRef)
- if maybeHash {
- hashCommit, hErr = r.CommitObject(plumbing.NewHash(string(revisionRef)))
- } else {
- hErr = plumbing.ErrReferenceNotFound
+ tagObj, err := r.TagObject(hash)
+ if err == nil {
+ // If the tag target lookup fails here, this most likely
+ // represents some sort of repo corruption, so let the
+ // error bubble up.
+ tagCommit, err := tagObj.Commit()
+ if err != nil {
+ return &plumbing.ZeroHash, err
+ }
+ commit = tagCommit
+ gotOne = true
+ break
+ }
}
- isTag := tErr == nil
- isCommit := rErr == nil
- isHash := hErr == nil
-
- switch {
- 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 isHash:
- commit = hashCommit
- default:
+ if !gotOne {
return &plumbing.ZeroHash, plumbing.ErrReferenceNotFound
}
+
case revision.CaretPath:
depth := item.(revision.CaretPath).Depth