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

fix Repository.ResolveRevision for branch and tag #660

Merged
merged 9 commits into from
Dec 1, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions _examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ Here you can find a list of annotated _go-git_ examples:
- [remotes](remotes/main.go) - Working with remotes: adding, removing, etc
- [progress](progress/main.go) - Printing the progress information from the sideband
- [push](push/main.go) - Push repository to default remote (origin)
- [checkout](checkout/main.go) - check out a specific commit from a repository
- [tag](tag/main.go) - list/print repository tags
- [pull](pull/main.go) - pull changes from a remote repository
- [checkout](checkout/main.go) - Check out a specific commit from a repository
- [tag](tag/main.go) - List/print repository tags
- [pull](pull/main.go) - Pull changes from a remote repository
- [revision](revision/main.go) - Solve a revision into a commit
### Advanced
- [custom_http](custom_http/main.go) - Replacing the HTTP client using a custom one
- [storage](storage/README.md) - Implementing a custom storage system
2 changes: 1 addition & 1 deletion _examples/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"strings"
)

// CheckArgs should be used to esnure the right command line arguments are
// CheckArgs should be used to ensure the right command line arguments are
// passed before executing an example.
func CheckArgs(arg ...string) {
if len(os.Args) < len(arg)+1 {
Expand Down
1 change: 1 addition & 0 deletions _examples/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ var args = map[string][]string{
"open": {cloneRepository(defaultURL, tempFolder())},
"progress": {defaultURL, tempFolder()},
"push": {setEmptyRemote(cloneRepository(defaultURL, tempFolder()))},
"revision": {cloneRepository(defaultURL, tempFolder()), "master~2^"},
"showcase": {defaultURL, tempFolder()},
"tag": {cloneRepository(defaultURL, tempFolder())},
"pull": {createRepositoryWithRemote(tempFolder(), defaultURL)},
Expand Down
32 changes: 32 additions & 0 deletions _examples/revision/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package main

import (
"fmt"
"os"

"gopkg.in/src-d/go-git.v4"
. "gopkg.in/src-d/go-git.v4/_examples"
"gopkg.in/src-d/go-git.v4/plumbing"
)

// Example how to resolve a revision into its commit counterpart
func main() {
CheckArgs("<path>", "<revision>")

path := os.Args[1]
revision := os.Args[2]

// We instantiate a new repository targeting the given path (the .git folder)
r, err := git.PlainOpen(path)
CheckIfError(err)

// Resolve revision into a sha1 commit, only some revisions are resolved
// look at the doc to get more details
Info("git rev-parse %s", revision)

h, err := r.ResolveRevision(plumbing.Revision(revision))

CheckIfError(err)

fmt.Println(h.String())
}
6 changes: 3 additions & 3 deletions plumbing/reference.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ const (
symrefPrefix = "ref: "
)

// refRevParseRules are a set of rules to parse references into short names.
// RefRevParseRules are a set of rules to parse references into short names.
// These are the same rules as used by git in shorten_unambiguous_ref.
// See: https://github.com/git/git/blob/e0aaa1b6532cfce93d87af9bc813fb2e7a7ce9d7/refs.c#L417
var refRevParseRules = []string{
var RefRevParseRules = []string{
"refs/%s",
"refs/tags/%s",
"refs/heads/%s",
Expand Down Expand Up @@ -83,7 +83,7 @@ func (r ReferenceName) String() string {
func (r ReferenceName) Short() string {
s := string(r)
res := s
for _, format := range refRevParseRules {
for _, format := range RefRevParseRules {
_, err := fmt.Sscanf(s, format, &res)
if err == nil {
continue
Expand Down
43 changes: 15 additions & 28 deletions repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -891,6 +891,9 @@ func (r *Repository) Worktree() (*Worktree, error) {
}

// ResolveRevision resolves revision to corresponding hash.
//
// 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})
func (r *Repository) ResolveRevision(rev plumbing.Revision) (*plumbing.Hash, error) {
p := revision.NewParserFromString(string(rev))

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

if err != nil {
return &plumbing.ZeroHash, err
for _, rule := range append([]string{"%s"}, plumbing.RefRevParseRules...) {
ref, err = storer.ResolveReference(r.Storer, plumbing.ReferenceName(fmt.Sprintf(rule, revisionRef)))

if err == nil {
break
}
}

h := ref.Hash()
if ref == nil {
return &plumbing.ZeroHash, plumbing.ErrReferenceNotFound
}

commit, err = r.CommitObject(h)
commit, err = r.CommitObject(ref.Hash())

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

commit = c
case revision.AtDate:
history := object.NewCommitPreorderIter(commit, nil, nil)

date := item.(revision.AtDate).Date

var c *object.Commit
err := history.ForEach(func(hc *object.Commit) error {
if date.Equal(hc.Committer.When.UTC()) || hc.Committer.When.UTC().Before(date) {
c = hc
return storer.ErrStop
}

return nil
})
if err != nil {
return &plumbing.ZeroHash, err
}

if c == nil {
return &plumbing.ZeroHash, fmt.Errorf(`No commit exists prior to date "%s"`, date.String())
}

Copy link
Contributor Author

@antham antham Nov 28, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed this part because it's a bad implementation,I misread the spec, it must follows this : This suffix may only be used immediately following a ref name and the ref must have an existing log ($GIT_DIR/logs/<ref>).

commit = c
}
}
Expand Down
45 changes: 26 additions & 19 deletions repository_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1265,24 +1265,32 @@ func (s *RepositorySuite) TestWorktreeBare(c *C) {
}

func (s *RepositorySuite) TestResolveRevision(c *C) {
url := s.GetLocalRepositoryURL(
fixtures.ByURL("https://github.com/git-fixtures/basic.git").One(),
)

r, _ := Init(memory.NewStorage(), nil)
err := r.clone(context.Background(), &CloneOptions{URL: url})
f := fixtures.ByURL("https://github.com/git-fixtures/basic.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{
"HEAD": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
"refs/heads/master~2^^~": "b029517f6300c2da0f4b651b8642506cd6aaf45d",
"HEAD~2^^~": "b029517f6300c2da0f4b651b8642506cd6aaf45d",
"HEAD~3^2": "a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69",
"HEAD~3^2^0": "a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69",
"HEAD~2^{/binary file}": "35e85108805c84807bc66a02d91535e1e24b38b9",
"HEAD~^{!-some}": "1669dce138d9b841a518c64b10914d88f5e488ea",
"HEAD@{2015-03-31T11:56:18Z}": "918c48b83bd081e863dbe1b80f8998f058cd8294",
"HEAD@{2015-03-31T11:49:00Z}": "1669dce138d9b841a518c64b10914d88f5e488ea",
"HEAD": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
"heads/master": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
"heads/master~1": "918c48b83bd081e863dbe1b80f8998f058cd8294",
"refs/heads/master": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
"refs/heads/master~2^^~": "b029517f6300c2da0f4b651b8642506cd6aaf45d",
"refs/tags/v1.0.0": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
"refs/remotes/origin/master": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
"refs/remotes/origin/HEAD": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
"HEAD~2^^~": "b029517f6300c2da0f4b651b8642506cd6aaf45d",
"HEAD~3^2": "a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69",
"HEAD~3^2^0": "a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69",
"HEAD~2^{/binary file}": "35e85108805c84807bc66a02d91535e1e24b38b9",
"HEAD~^{/!-some}": "1669dce138d9b841a518c64b10914d88f5e488ea",
"master": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
"branch": "e8d3ffab552895c19b9fcf7aa264d277cde33881",
"v1.0.0": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5",
Copy link
Contributor Author

@antham antham Nov 28, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This tag exists here but I can't find it on https://github.com/git-fixtures/basic.git

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extrange... but trust on the fixture.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe you could add it to the original repository ? It's convenient when you need to test on the repository and it will fit what is defined in fixtures.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe, I will check it.

"branch~1": "918c48b83bd081e863dbe1b80f8998f058cd8294",
"v1.0.0~1": "918c48b83bd081e863dbe1b80f8998f058cd8294",
"master~1": "918c48b83bd081e863dbe1b80f8998f058cd8294",
}

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

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

for rev, rerr := range datas {
Expand Down