Skip to content
This repository was archived by the owner on Sep 11, 2020. It is now read-only.

Commit 24de5ef

Browse files
authored
Merge pull request #1146 from novas0x2a/fix-tag-oid
improve ResolveRevision's Ref lookup path
2 parents 52fcf7d + 33f05f3 commit 24de5ef

File tree

2 files changed

+42
-49
lines changed

2 files changed

+42
-49
lines changed

repository.go

+37-44
Original file line numberDiff line numberDiff line change
@@ -1306,16 +1306,6 @@ func (r *Repository) Worktree() (*Worktree, error) {
13061306
return &Worktree{r: r, Filesystem: r.wt}, nil
13071307
}
13081308

1309-
func countTrue(vals ...bool) int {
1310-
sum := 0
1311-
for _, v := range vals {
1312-
if v {
1313-
sum++
1314-
}
1315-
}
1316-
return sum
1317-
}
1318-
13191309
// ResolveRevision resolves revision to corresponding hash. It will always
13201310
// resolve to a commit hash, not a tree or annotated tag.
13211311
//
@@ -1336,54 +1326,57 @@ func (r *Repository) ResolveRevision(rev plumbing.Revision) (*plumbing.Hash, err
13361326
switch item.(type) {
13371327
case revision.Ref:
13381328
revisionRef := item.(revision.Ref)
1339-
var ref *plumbing.Reference
1340-
var hashCommit, refCommit, tagCommit *object.Commit
1341-
var rErr, hErr, tErr error
1329+
1330+
var tryHashes []plumbing.Hash
1331+
1332+
maybeHash := plumbing.NewHash(string(revisionRef))
1333+
1334+
if !maybeHash.IsZero() {
1335+
tryHashes = append(tryHashes, maybeHash)
1336+
}
13421337

13431338
for _, rule := range append([]string{"%s"}, plumbing.RefRevParseRules...) {
1344-
ref, err = storer.ResolveReference(r.Storer, plumbing.ReferenceName(fmt.Sprintf(rule, revisionRef)))
1339+
ref, err := storer.ResolveReference(r.Storer, plumbing.ReferenceName(fmt.Sprintf(rule, revisionRef)))
13451340

13461341
if err == nil {
1342+
tryHashes = append(tryHashes, ref.Hash())
13471343
break
13481344
}
13491345
}
13501346

1351-
if ref != nil {
1352-
tag, tObjErr := r.TagObject(ref.Hash())
1353-
if tObjErr != nil {
1354-
tErr = tObjErr
1355-
} else {
1356-
tagCommit, tErr = tag.Commit()
1347+
// in ambiguous cases, `git rev-parse` will emit a warning, but
1348+
// will always return the oid in preference to a ref; we don't have
1349+
// the ability to emit a warning here, so (for speed purposes)
1350+
// don't bother to detect the ambiguity either, just return in the
1351+
// priority that git would.
1352+
gotOne := false
1353+
for _, hash := range tryHashes {
1354+
commitObj, err := r.CommitObject(hash)
1355+
if err == nil {
1356+
commit = commitObj
1357+
gotOne = true
1358+
break
13571359
}
1358-
refCommit, rErr = r.CommitObject(ref.Hash())
1359-
} else {
1360-
rErr = plumbing.ErrReferenceNotFound
1361-
tErr = plumbing.ErrReferenceNotFound
1362-
}
13631360

1364-
maybeHash := plumbing.NewHash(string(revisionRef)).String() == string(revisionRef)
1365-
if maybeHash {
1366-
hashCommit, hErr = r.CommitObject(plumbing.NewHash(string(revisionRef)))
1367-
} else {
1368-
hErr = plumbing.ErrReferenceNotFound
1361+
tagObj, err := r.TagObject(hash)
1362+
if err == nil {
1363+
// If the tag target lookup fails here, this most likely
1364+
// represents some sort of repo corruption, so let the
1365+
// error bubble up.
1366+
tagCommit, err := tagObj.Commit()
1367+
if err != nil {
1368+
return &plumbing.ZeroHash, err
1369+
}
1370+
commit = tagCommit
1371+
gotOne = true
1372+
break
1373+
}
13691374
}
13701375

1371-
isTag := tErr == nil
1372-
isCommit := rErr == nil
1373-
isHash := hErr == nil
1374-
1375-
switch {
1376-
case countTrue(isTag, isCommit, isHash) > 1:
1377-
return &plumbing.ZeroHash, fmt.Errorf(`refname "%s" is ambiguous`, revisionRef)
1378-
case isTag:
1379-
commit = tagCommit
1380-
case isCommit:
1381-
commit = refCommit
1382-
case isHash:
1383-
commit = hashCommit
1384-
default:
1376+
if !gotOne {
13851377
return &plumbing.ZeroHash, plumbing.ErrReferenceNotFound
13861378
}
1379+
13871380
case revision.CaretPath:
13881381
depth := item.(revision.CaretPath).Depth
13891382

repository_test.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -2415,7 +2415,7 @@ func (s *RepositorySuite) TestResolveRevision(c *C) {
24152415
for rev, hash := range datas {
24162416
h, err := r.ResolveRevision(plumbing.Revision(rev))
24172417

2418-
c.Assert(err, IsNil)
2418+
c.Assert(err, IsNil, Commentf("while checking %s", rev))
24192419
c.Check(h.String(), Equals, hash, Commentf("while checking %s", rev))
24202420
}
24212421
}
@@ -2427,13 +2427,14 @@ func (s *RepositorySuite) TestResolveRevisionAnnotated(c *C) {
24272427
c.Assert(err, IsNil)
24282428

24292429
datas := map[string]string{
2430-
"refs/tags/annotated-tag": "f7b877701fbf855b44c0a9e86f3fdce2c298b07f",
2430+
"refs/tags/annotated-tag": "f7b877701fbf855b44c0a9e86f3fdce2c298b07f",
2431+
"b742a2a9fa0afcfa9a6fad080980fbc26b007c69": "f7b877701fbf855b44c0a9e86f3fdce2c298b07f",
24312432
}
24322433

24332434
for rev, hash := range datas {
24342435
h, err := r.ResolveRevision(plumbing.Revision(rev))
24352436

2436-
c.Assert(err, IsNil)
2437+
c.Assert(err, IsNil, Commentf("while checking %s", rev))
24372438
c.Check(h.String(), Equals, hash, Commentf("while checking %s", rev))
24382439
}
24392440
}
@@ -2459,12 +2460,11 @@ func (s *RepositorySuite) TestResolveRevisionWithErrors(c *C) {
24592460
"HEAD^3": `Revision invalid : "3" found must be 0, 1 or 2 after "^"`,
24602461
"HEAD^{/whatever}": `No commit message match regexp : "whatever"`,
24612462
"4e1243bd22c66e76c2ba9eddc1f91394e57f9f83": "reference not found",
2462-
"918c48b83bd081e863dbe1b80f8998f058cd8294": `refname "918c48b83bd081e863dbe1b80f8998f058cd8294" is ambiguous`,
24632463
}
24642464

24652465
for rev, rerr := range datas {
24662466
_, err := r.ResolveRevision(plumbing.Revision(rev))
2467-
2467+
c.Assert(err, NotNil)
24682468
c.Assert(err.Error(), Equals, rerr)
24692469
}
24702470
}

0 commit comments

Comments
 (0)