Skip to content
This repository was archived by the owner on May 23, 2023. It is now read-only.

Commit 44c364f

Browse files
anthammcuadros
authored andcommitted
Fix revision solver for branch and tag (go-git#660)
fix Repository.ResolveRevision for branch and tag
1 parent e20d334 commit 44c364f

File tree

7 files changed

+82
-54
lines changed

7 files changed

+82
-54
lines changed

_examples/README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@ Here you can find a list of annotated _go-git_ examples:
1111
- [remotes](remotes/main.go) - Working with remotes: adding, removing, etc
1212
- [progress](progress/main.go) - Printing the progress information from the sideband
1313
- [push](push/main.go) - Push repository to default remote (origin)
14-
- [checkout](checkout/main.go) - check out a specific commit from a repository
15-
- [tag](tag/main.go) - list/print repository tags
16-
- [pull](pull/main.go) - pull changes from a remote repository
14+
- [checkout](checkout/main.go) - Check out a specific commit from a repository
15+
- [tag](tag/main.go) - List/print repository tags
16+
- [pull](pull/main.go) - Pull changes from a remote repository
17+
- [revision](revision/main.go) - Solve a revision into a commit
1718
### Advanced
1819
- [custom_http](custom_http/main.go) - Replacing the HTTP client using a custom one
1920
- [storage](storage/README.md) - Implementing a custom storage system

_examples/common.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import (
66
"strings"
77
)
88

9-
// CheckArgs should be used to esnure the right command line arguments are
9+
// CheckArgs should be used to ensure the right command line arguments are
1010
// passed before executing an example.
1111
func CheckArgs(arg ...string) {
1212
if len(os.Args) < len(arg)+1 {

_examples/common_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ var args = map[string][]string{
2323
"open": {cloneRepository(defaultURL, tempFolder())},
2424
"progress": {defaultURL, tempFolder()},
2525
"push": {setEmptyRemote(cloneRepository(defaultURL, tempFolder()))},
26+
"revision": {cloneRepository(defaultURL, tempFolder()), "master~2^"},
2627
"showcase": {defaultURL, tempFolder()},
2728
"tag": {cloneRepository(defaultURL, tempFolder())},
2829
"pull": {createRepositoryWithRemote(tempFolder(), defaultURL)},

_examples/revision/main.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"os"
6+
7+
"gopkg.in/src-d/go-git.v4"
8+
. "gopkg.in/src-d/go-git.v4/_examples"
9+
"gopkg.in/src-d/go-git.v4/plumbing"
10+
)
11+
12+
// Example how to resolve a revision into its commit counterpart
13+
func main() {
14+
CheckArgs("<path>", "<revision>")
15+
16+
path := os.Args[1]
17+
revision := os.Args[2]
18+
19+
// We instantiate a new repository targeting the given path (the .git folder)
20+
r, err := git.PlainOpen(path)
21+
CheckIfError(err)
22+
23+
// Resolve revision into a sha1 commit, only some revisions are resolved
24+
// look at the doc to get more details
25+
Info("git rev-parse %s", revision)
26+
27+
h, err := r.ResolveRevision(plumbing.Revision(revision))
28+
29+
CheckIfError(err)
30+
31+
fmt.Println(h.String())
32+
}

plumbing/reference.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ const (
1515
symrefPrefix = "ref: "
1616
)
1717

18-
// refRevParseRules are a set of rules to parse references into short names.
18+
// RefRevParseRules are a set of rules to parse references into short names.
1919
// These are the same rules as used by git in shorten_unambiguous_ref.
2020
// See: https://github.com/git/git/blob/e0aaa1b6532cfce93d87af9bc813fb2e7a7ce9d7/refs.c#L417
21-
var refRevParseRules = []string{
21+
var RefRevParseRules = []string{
2222
"refs/%s",
2323
"refs/tags/%s",
2424
"refs/heads/%s",
@@ -83,7 +83,7 @@ func (r ReferenceName) String() string {
8383
func (r ReferenceName) Short() string {
8484
s := string(r)
8585
res := s
86-
for _, format := range refRevParseRules {
86+
for _, format := range RefRevParseRules {
8787
_, err := fmt.Sscanf(s, format, &res)
8888
if err == nil {
8989
continue

repository.go

Lines changed: 15 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -891,6 +891,9 @@ func (r *Repository) Worktree() (*Worktree, error) {
891891
}
892892

893893
// ResolveRevision resolves revision to corresponding hash.
894+
//
895+
// Implemented resolvers : HEAD, branch, tag, heads/branch, refs/heads/branch,
896+
// 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})
894897
func (r *Repository) ResolveRevision(rev plumbing.Revision) (*plumbing.Hash, error) {
895898
p := revision.NewParserFromString(string(rev))
896899

@@ -905,15 +908,22 @@ func (r *Repository) ResolveRevision(rev plumbing.Revision) (*plumbing.Hash, err
905908
for _, item := range items {
906909
switch item.(type) {
907910
case revision.Ref:
908-
ref, err := storer.ResolveReference(r.Storer, plumbing.ReferenceName(item.(revision.Ref)))
911+
revisionRef := item.(revision.Ref)
912+
var ref *plumbing.Reference
909913

910-
if err != nil {
911-
return &plumbing.ZeroHash, err
914+
for _, rule := range append([]string{"%s"}, plumbing.RefRevParseRules...) {
915+
ref, err = storer.ResolveReference(r.Storer, plumbing.ReferenceName(fmt.Sprintf(rule, revisionRef)))
916+
917+
if err == nil {
918+
break
919+
}
912920
}
913921

914-
h := ref.Hash()
922+
if ref == nil {
923+
return &plumbing.ZeroHash, plumbing.ErrReferenceNotFound
924+
}
915925

916-
commit, err = r.CommitObject(h)
926+
commit, err = r.CommitObject(ref.Hash())
917927

918928
if err != nil {
919929
return &plumbing.ZeroHash, err
@@ -985,29 +995,6 @@ func (r *Repository) ResolveRevision(rev plumbing.Revision) (*plumbing.Hash, err
985995
return &plumbing.ZeroHash, fmt.Errorf(`No commit message match regexp : "%s"`, re.String())
986996
}
987997

988-
commit = c
989-
case revision.AtDate:
990-
history := object.NewCommitPreorderIter(commit, nil, nil)
991-
992-
date := item.(revision.AtDate).Date
993-
994-
var c *object.Commit
995-
err := history.ForEach(func(hc *object.Commit) error {
996-
if date.Equal(hc.Committer.When.UTC()) || hc.Committer.When.UTC().Before(date) {
997-
c = hc
998-
return storer.ErrStop
999-
}
1000-
1001-
return nil
1002-
})
1003-
if err != nil {
1004-
return &plumbing.ZeroHash, err
1005-
}
1006-
1007-
if c == nil {
1008-
return &plumbing.ZeroHash, fmt.Errorf(`No commit exists prior to date "%s"`, date.String())
1009-
}
1010-
1011998
commit = c
1012999
}
10131000
}

repository_test.go

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1265,24 +1265,32 @@ func (s *RepositorySuite) TestWorktreeBare(c *C) {
12651265
}
12661266

12671267
func (s *RepositorySuite) TestResolveRevision(c *C) {
1268-
url := s.GetLocalRepositoryURL(
1269-
fixtures.ByURL("https://github.com/git-fixtures/basic.git").One(),
1270-
)
1271-
1272-
r, _ := Init(memory.NewStorage(), nil)
1273-
err := r.clone(context.Background(), &CloneOptions{URL: url})
1268+
f := fixtures.ByURL("https://github.com/git-fixtures/basic.git").One()
1269+
sto, err := filesystem.NewStorage(f.DotGit())
1270+
c.Assert(err, IsNil)
1271+
r, err := Open(sto, f.DotGit())
12741272
c.Assert(err, IsNil)
12751273

12761274
datas := map[string]string{
1277-
"HEAD": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
1278-
"refs/heads/master~2^^~": "b029517f6300c2da0f4b651b8642506cd6aaf45d",
1279-
"HEAD~2^^~": "b029517f6300c2da0f4b651b8642506cd6aaf45d",
1280-
"HEAD~3^2": "a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69",
1281-
"HEAD~3^2^0": "a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69",
1282-
"HEAD~2^{/binary file}": "35e85108805c84807bc66a02d91535e1e24b38b9",
1283-
"HEAD~^{!-some}": "1669dce138d9b841a518c64b10914d88f5e488ea",
1284-
"HEAD@{2015-03-31T11:56:18Z}": "918c48b83bd081e863dbe1b80f8998f058cd8294",
1285-
"HEAD@{2015-03-31T11:49:00Z}": "1669dce138d9b841a518c64b10914d88f5e488ea",
1275+
"HEAD": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
1276+
"heads/master": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
1277+
"heads/master~1": "918c48b83bd081e863dbe1b80f8998f058cd8294",
1278+
"refs/heads/master": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
1279+
"refs/heads/master~2^^~": "b029517f6300c2da0f4b651b8642506cd6aaf45d",
1280+
"refs/tags/v1.0.0": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
1281+
"refs/remotes/origin/master": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
1282+
"refs/remotes/origin/HEAD": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
1283+
"HEAD~2^^~": "b029517f6300c2da0f4b651b8642506cd6aaf45d",
1284+
"HEAD~3^2": "a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69",
1285+
"HEAD~3^2^0": "a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69",
1286+
"HEAD~2^{/binary file}": "35e85108805c84807bc66a02d91535e1e24b38b9",
1287+
"HEAD~^{/!-some}": "1669dce138d9b841a518c64b10914d88f5e488ea",
1288+
"master": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
1289+
"branch": "e8d3ffab552895c19b9fcf7aa264d277cde33881",
1290+
"v1.0.0": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
1291+
"branch~1": "918c48b83bd081e863dbe1b80f8998f058cd8294",
1292+
"v1.0.0~1": "918c48b83bd081e863dbe1b80f8998f058cd8294",
1293+
"master~1": "918c48b83bd081e863dbe1b80f8998f058cd8294",
12861294
}
12871295

12881296
for rev, hash := range datas {
@@ -1303,10 +1311,9 @@ func (s *RepositorySuite) TestResolveRevisionWithErrors(c *C) {
13031311
c.Assert(err, IsNil)
13041312

13051313
datas := map[string]string{
1306-
"efs/heads/master~": "reference not found",
1307-
"HEAD^3": `Revision invalid : "3" found must be 0, 1 or 2 after "^"`,
1308-
"HEAD^{/whatever}": `No commit message match regexp : "whatever"`,
1309-
"HEAD@{2015-03-31T09:49:00Z}": `No commit exists prior to date "2015-03-31 09:49:00 +0000 UTC"`,
1314+
"efs/heads/master~": "reference not found",
1315+
"HEAD^3": `Revision invalid : "3" found must be 0, 1 or 2 after "^"`,
1316+
"HEAD^{/whatever}": `No commit message match regexp : "whatever"`,
13101317
}
13111318

13121319
for rev, rerr := range datas {

0 commit comments

Comments
 (0)