Merge pull request #485 from mcuadros/fetch-tags

remote: fetch, correct behavior on tags
diff --git a/remote.go b/remote.go
index b2c5d1c..8f1da2f 100644
--- a/remote.go
+++ b/remote.go
@@ -362,20 +362,30 @@
 		return nil, err
 	}
 
-	var haves []plumbing.Hash
+	haves := map[plumbing.Hash]bool{}
 	err = iter.ForEach(func(ref *plumbing.Reference) error {
+		if haves[ref.Hash()] == true {
+			return nil
+		}
+
 		if ref.Type() != plumbing.HashReference {
 			return nil
 		}
 
-		haves = append(haves, ref.Hash())
+		haves[ref.Hash()] = true
 		return nil
 	})
+
 	if err != nil {
 		return nil, err
 	}
 
-	return haves, nil
+	var result []plumbing.Hash
+	for h := range haves {
+		result = append(result, h)
+	}
+
+	return result, nil
 }
 
 func calculateRefs(spec []config.RefSpec,
diff --git a/remote_test.go b/remote_test.go
index 2c02877..7ffe040 100644
--- a/remote_test.go
+++ b/remote_test.go
@@ -553,6 +553,25 @@
 	c.Assert(err, ErrorMatches, ".*remote names don't match.*")
 }
 
+func (s *RemoteSuite) TestGetHaves(c *C) {
+	st := memory.NewStorage()
+	st.SetReference(plumbing.NewReferenceFromStrings(
+		"foo", "f7b877701fbf855b44c0a9e86f3fdce2c298b07f",
+	))
+
+	st.SetReference(plumbing.NewReferenceFromStrings(
+		"bar", "fe6cb94756faa81e5ed9240f9191b833db5f40ae",
+	))
+
+	st.SetReference(plumbing.NewReferenceFromStrings(
+		"qux", "f7b877701fbf855b44c0a9e86f3fdce2c298b07f",
+	))
+
+	l, err := getHaves(st)
+	c.Assert(err, IsNil)
+	c.Assert(l, HasLen, 2)
+}
+
 const bareConfig = `[core]
 repositoryformatversion = 0
 filemode = true
diff --git a/utils/merkletrie/iter.go b/utils/merkletrie/iter.go
index c84f6fc..e3f3055 100644
--- a/utils/merkletrie/iter.go
+++ b/utils/merkletrie/iter.go
@@ -83,6 +83,10 @@
 		base: base,
 	}
 
+	if root == nil {
+		return ret, nil
+	}
+
 	frame, err := frame.New(root)
 	if err != nil {
 		return nil, err
diff --git a/utils/merkletrie/iter_test.go b/utils/merkletrie/iter_test.go
index 7e8c302..b334cf1 100644
--- a/utils/merkletrie/iter_test.go
+++ b/utils/merkletrie/iter_test.go
@@ -19,13 +19,13 @@
 // A test is a list of operations we want to perform on an iterator and
 // their expected results.
 //
-// The operations are expresed as a sequence of `n` and `s`,
+// The operations are expressed as a sequence of `n` and `s`,
 // representing the amount of next and step operations we want to call
 // on the iterator and their order.  For example, an operations value of
 // "nns" means: call a `n`ext, then another `n`ext and finish with a
 // `s`tep.
 //
-// The expeced is the full path of the noders returned by the
+// The expected is the full path of the noders returned by the
 // operations, separated by spaces.
 //
 // For instance:
@@ -446,6 +446,13 @@
 	return nil, fmt.Errorf("mock error")
 }
 
+func (s *IterSuite) TestNewIterNil(c *C) {
+	i, err := merkletrie.NewIter(nil)
+	c.Assert(err, IsNil)
+	_, err = i.Next()
+	c.Assert(err, Equals, io.EOF)
+}
+
 func (s *IterSuite) TestNewIterFailsOnChildrenErrors(c *C) {
 	_, err := merkletrie.NewIter(&errorNoder{})
 	c.Assert(err, ErrorMatches, "mock error")
diff --git a/worktree_status.go b/worktree_status.go
index 728d7a0..a662516 100644
--- a/worktree_status.go
+++ b/worktree_status.go
@@ -24,16 +24,18 @@
 
 // Status returns the working tree status.
 func (w *Worktree) Status() (Status, error) {
-	ref, err := w.r.Head()
-	if err == plumbing.ErrReferenceNotFound {
-		return make(Status, 0), nil
-	}
+	var hash plumbing.Hash
 
-	if err != nil {
+	ref, err := w.r.Head()
+	if err != nil && err != plumbing.ErrReferenceNotFound {
 		return nil, err
 	}
 
-	return w.status(ref.Hash())
+	if err == nil {
+		hash = ref.Hash()
+	}
+
+	return w.status(hash)
 }
 
 func (w *Worktree) status(commit plumbing.Hash) (Status, error) {
@@ -182,19 +184,22 @@
 		return nil, err
 	}
 
-	c, err := w.r.CommitObject(commit)
-	if err != nil {
-		return nil, err
-	}
+	var from noder.Noder
+	if !commit.IsZero() {
+		c, err := w.r.CommitObject(commit)
+		if err != nil {
+			return nil, err
+		}
 
-	t, err := c.Tree()
-	if err != nil {
-		return nil, err
+		t, err := c.Tree()
+		if err != nil {
+			return nil, err
+		}
+
+		from = object.NewTreeRootNode(t)
 	}
 
 	to := mindex.NewRootNode(idx)
-	from := object.NewTreeRootNode(t)
-
 	if reverse {
 		return merkletrie.DiffTree(to, from, diffTreeIsEquals)
 	}
diff --git a/worktree_test.go b/worktree_test.go
index 864e19e..4c9907b 100644
--- a/worktree_test.go
+++ b/worktree_test.go
@@ -344,6 +344,25 @@
 	c.Assert(status, NotNil)
 }
 
+func (s *WorktreeSuite) TestStatusEmptyDirty(c *C) {
+	fs := memfs.New()
+	err := util.WriteFile(fs, "foo", []byte("foo"), 0755)
+	c.Assert(err, IsNil)
+
+	storage := memory.NewStorage()
+
+	r, err := Init(storage, fs)
+	c.Assert(err, IsNil)
+
+	w, err := r.Worktree()
+	c.Assert(err, IsNil)
+
+	status, err := w.Status()
+	c.Assert(err, IsNil)
+	c.Assert(status.IsClean(), Equals, false)
+	c.Assert(status, HasLen, 1)
+}
+
 func (s *WorktreeSuite) TestReset(c *C) {
 	fs := memfs.New()
 	w := &Worktree{