aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--repository.go12
-rw-r--r--repository_test.go4
-rw-r--r--storage/seekable/internal/gitdir/gitdir.go5
-rw-r--r--storage/seekable/storage.go46
4 files changed, 65 insertions, 2 deletions
diff --git a/repository.go b/repository.go
index 0cda947..866f9ff 100644
--- a/repository.go
+++ b/repository.go
@@ -226,6 +226,10 @@ func (r *Repository) Head(remote string) (core.Hash, error) {
return r.localHead()
}
+ return r.remoteHead(remote)
+}
+
+func (r *Repository) remoteHead(remote string) (core.Hash, error) {
rem, ok := r.Remotes[remote]
if !ok {
return core.ZeroHash, fmt.Errorf("unable to find remote %q", remote)
@@ -235,5 +239,11 @@ func (r *Repository) Head(remote string) (core.Hash, error) {
}
func (r *Repository) localHead() (core.Hash, error) {
- return core.ZeroHash, nil
+ storage, ok := r.Storage.(*seekable.ObjectStorage)
+ if !ok {
+ return core.ZeroHash,
+ fmt.Errorf("cannot retrieve local head: no local data found")
+ }
+
+ return storage.Head()
}
diff --git a/repository_test.go b/repository_test.go
index da02a4d..eafbdf7 100644
--- a/repository_test.go
+++ b/repository_test.go
@@ -260,4 +260,8 @@ func (s *SuiteRepository) TestHeadFromRemoteError(c *C) {
remote := "not found"
_, err = r.Head(remote)
c.Assert(err, ErrorMatches, fmt.Sprintf("unable to find remote %q", remote))
+
+ remote = ""
+ _, err = r.Head(remote)
+ c.Assert(err, ErrorMatches, "cannot retrieve local head: no local data found")
}
diff --git a/storage/seekable/internal/gitdir/gitdir.go b/storage/seekable/internal/gitdir/gitdir.go
index bfdf030..eea980b 100644
--- a/storage/seekable/internal/gitdir/gitdir.go
+++ b/storage/seekable/internal/gitdir/gitdir.go
@@ -25,6 +25,9 @@ var (
// ErrPackfileNotFound is returned by Packfile when the packfile is not found
// on the repository.
ErrPackfileNotFound = errors.New("packfile not found")
+ // ErrHeadfileNotFound is returned by Headfile when the HEAD file is not found
+ // on the repository.
+ ErrHeadfileNotFound = errors.New("headfile not found")
)
// The GitDir type represents a local git repository on disk. This
@@ -126,7 +129,7 @@ func (d *GitDir) Packfile() (fs.FS, string, error) {
return nil, "", ErrPackfileNotFound
}
-// Packfile returns the path of the idx file (really, it returns the
+// Idxfile returns the path of the idx file (really, it returns the
// path of the first file in the "objects/pack/" directory with an
// ".idx" extension.
func (d *GitDir) Idxfile() (fs.FS, string, error) {
diff --git a/storage/seekable/storage.go b/storage/seekable/storage.go
index 8d75700..db436c8 100644
--- a/storage/seekable/storage.go
+++ b/storage/seekable/storage.go
@@ -3,6 +3,7 @@ package seekable
import (
"fmt"
"os"
+ "strings"
"gopkg.in/src-d/go-git.v3/core"
"gopkg.in/src-d/go-git.v3/formats/packfile"
@@ -150,3 +151,48 @@ func (s *ObjectStorage) Iter(t core.ObjectType) (core.ObjectIter, error) {
return core.NewObjectSliceIter(objects), nil
}
+
+const (
+ headErrPrefix = "cannot get HEAD reference:"
+ symrefCapability = "symref"
+ headRefPrefix = "HEAD:"
+)
+
+// Head returns the hash of the HEAD reference
+func (s *ObjectStorage) Head() (core.Hash, error) {
+ cap, err := s.dir.Capabilities()
+ if err != nil {
+ return core.ZeroHash, fmt.Errorf("%s %s", headErrPrefix, err)
+ }
+
+ ok := cap.Supports(symrefCapability)
+ if !ok {
+ return core.ZeroHash,
+ fmt.Errorf("%s symref capability not supported", headErrPrefix)
+ }
+
+ symrefs := cap.Get(symrefCapability)
+ var headRef string
+ for _, ref := range symrefs.Values {
+ if strings.HasPrefix(ref, headRefPrefix) {
+ headRef = strings.TrimPrefix(ref, headRefPrefix)
+ }
+ }
+ if headRef == "" {
+ return core.ZeroHash, fmt.Errorf("%s HEAD reference not found",
+ headErrPrefix)
+ }
+
+ refs, err := s.dir.Refs()
+ if err != nil {
+ return core.ZeroHash, fmt.Errorf("%s %s", headErrPrefix, err)
+ }
+
+ head, ok := refs[headRef]
+ if !ok {
+ return core.ZeroHash, fmt.Errorf("%s reference %q not found",
+ headErrPrefix, headRef)
+ }
+
+ return head, nil
+}