Detailed changes
  
  
    
    @@ -138,7 +138,7 @@ func (opp *OperationPack) Validate() error {
 
 // Write will serialize and store the OperationPack as a git blob and return
 // its hash
-func (opp *OperationPack) Write(repo repository.Repo) (git.Hash, error) {
+func (opp *OperationPack) Write(repo repository.ClockedRepo) (git.Hash, error) {
 	// make sure we don't write invalid data
 	err := opp.Validate()
 	if err != nil {
  
  
  
    
    @@ -712,7 +712,7 @@ func (c *RepoCache) ResolveIdentityPrefix(prefix string) (*IdentityCache, error)
 	// preallocate but empty
 	matching := make([]string, 0, 5)
 
-	for id := range c.identities {
+	for id := range c.identitiesExcerpts {
 		if strings.HasPrefix(id, prefix) {
 			matching = append(matching, id)
 		}
  
  
  
    
    @@ -23,8 +23,6 @@ func runUser(cmd *cobra.Command, args []string) error {
 
 	var id *cache.IdentityCache
 	if len(args) == 1 {
-		// TODO
-		return errors.New("this is not working yet, cache need to be hacked on")
 		id, err = backend.ResolveIdentityPrefix(args[0])
 	} else {
 		id, err = backend.GetUserIdentity()
  
  
  
    
    @@ -65,6 +65,7 @@ func (i *Bare) UnmarshalJSON(data []byte) error {
 	return nil
 }
 
+// Id return the Identity identifier
 func (i *Bare) Id() string {
 	// We don't have a proper ID at hand, so let's hash all the data to get one.
 	// Hopefully the
@@ -84,18 +85,22 @@ func (i *Bare) Id() string {
 	return i.id
 }
 
+// Name return the last version of the name
 func (i *Bare) Name() string {
 	return i.name
 }
 
+// Email return the last version of the email
 func (i *Bare) Email() string {
 	return i.email
 }
 
+// Login return the last version of the login
 func (i *Bare) Login() string {
 	return i.login
 }
 
+// AvatarUrl return the last version of the Avatar URL
 func (i *Bare) AvatarUrl() string {
 	return i.avatarUrl
 }
@@ -164,12 +169,14 @@ func (i *Bare) Validate() error {
 
 // Write the identity into the Repository. In particular, this ensure that
 // the Id is properly set.
-func (i *Bare) Commit(repo repository.Repo) error {
+func (i *Bare) Commit(repo repository.ClockedRepo) error {
 	// Nothing to do, everything is directly embedded
 	return nil
 }
 
-func (i *Bare) CommitAsNeeded(repo repository.Repo) error {
+// If needed, write the identity into the Repository. In particular, this
+// ensure that the Id is properly set.
+func (i *Bare) CommitAsNeeded(repo repository.ClockedRepo) error {
 	// Nothing to do, everything is directly embedded
 	return nil
 }
  
  
  
    
    @@ -5,6 +5,7 @@ import (
 	"encoding/json"
 	"fmt"
 	"strings"
+	"time"
 
 	"github.com/pkg/errors"
 
@@ -252,8 +253,8 @@ func (i *Identity) AddVersion(version *Version) {
 
 // Write the identity into the Repository. In particular, this ensure that
 // the Id is properly set.
-func (i *Identity) Commit(repo repository.Repo) error {
-	// Todo: check for mismatch between memory and commited data
+func (i *Identity) Commit(repo repository.ClockedRepo) error {
+	// Todo: check for mismatch between memory and commit data
 
 	if !i.NeedCommit() {
 		return fmt.Errorf("can't commit an identity with no pending version")
@@ -266,10 +267,14 @@ func (i *Identity) Commit(repo repository.Repo) error {
 	for _, v := range i.versions {
 		if v.commitHash != "" {
 			i.lastCommit = v.commitHash
-			// ignore already commited versions
+			// ignore already commit versions
 			continue
 		}
 
+		// get the times where new versions starts to be valid
+		v.time = repo.EditTime()
+		v.unixTime = time.Now().Unix()
+
 		blobHash, err := v.Write(repo)
 		if err != nil {
 			return err
@@ -319,7 +324,7 @@ func (i *Identity) Commit(repo repository.Repo) error {
 	return nil
 }
 
-func (i *Identity) CommitAsNeeded(repo repository.Repo) error {
+func (i *Identity) CommitAsNeeded(repo repository.ClockedRepo) error {
 	if !i.NeedCommit() {
 		return nil
 	}
  
  
  
    
    @@ -76,11 +76,11 @@ func (IdentityStub) Validate() error {
 	panic("identities needs to be properly loaded with identity.ReadLocal()")
 }
 
-func (IdentityStub) Commit(repo repository.Repo) error {
+func (IdentityStub) Commit(repo repository.ClockedRepo) error {
 	panic("identities needs to be properly loaded with identity.ReadLocal()")
 }
 
-func (i *IdentityStub) CommitAsNeeded(repo repository.Repo) error {
+func (i *IdentityStub) CommitAsNeeded(repo repository.ClockedRepo) error {
 	panic("identities needs to be properly loaded with identity.ReadLocal()")
 }
 
  
  
  
    
    @@ -6,13 +6,17 @@ import (
 )
 
 type Interface interface {
+	// Id return the Identity identifier
 	Id() string
 
+	// Name return the last version of the name
 	Name() string
+	// Email return the last version of the email
 	Email() string
+	// Login return the last version of the login
 	Login() string
+	// AvatarUrl return the last version of the Avatar URL
 	AvatarUrl() string
-
 	// Keys return the last version of the valid keys
 	Keys() []Key
 
@@ -28,11 +32,11 @@ type Interface interface {
 
 	// Write the identity into the Repository. In particular, this ensure that
 	// the Id is properly set.
-	Commit(repo repository.Repo) error
+	Commit(repo repository.ClockedRepo) error
 
 	// If needed, write the identity into the Repository. In particular, this
 	// ensure that the Id is properly set.
-	CommitAsNeeded(repo repository.Repo) error
+	CommitAsNeeded(repo repository.ClockedRepo) error
 
 	// IsProtected return true if the chain of git commits started to be signed.
 	// If that's the case, only signed commit with a valid key for this identity can be added.
  
  
  
    
    @@ -17,14 +17,11 @@ const formatVersion = 1
 
 // Version is a complete set of information about an Identity at a point in time.
 type Version struct {
-	// Not serialized
-	commitHash git.Hash
-
-	// Todo: add unix timestamp for ordering with identical lamport time ?
-
 	// The lamport time at which this version become effective
 	// The reference time is the bug edition lamport clock
-	time lamport.Time
+	// It must be the first field in this struct due to https://github.com/golang/go/issues/599
+	time     lamport.Time
+	unixTime int64
 
 	name      string
 	email     string
@@ -43,6 +40,9 @@ type Version struct {
 
 	// A set of arbitrary key/value to store metadata about a version or about an Identity in general.
 	metadata map[string]string
+
+	// Not serialized
+	commitHash git.Hash
 }
 
 type VersionJSON struct {
@@ -50,6 +50,7 @@ type VersionJSON struct {
 	FormatVersion uint `json:"version"`
 
 	Time      lamport.Time      `json:"time"`
+	UnixTime  int64             `json:"unix_time"`
 	Name      string            `json:"name"`
 	Email     string            `json:"email"`
 	Login     string            `json:"login"`
@@ -63,6 +64,7 @@ func (v *Version) MarshalJSON() ([]byte, error) {
 	return json.Marshal(VersionJSON{
 		FormatVersion: formatVersion,
 		Time:          v.time,
+		UnixTime:      v.unixTime,
 		Name:          v.name,
 		Email:         v.email,
 		Login:         v.login,
@@ -85,6 +87,7 @@ func (v *Version) UnmarshalJSON(data []byte) error {
 	}
 
 	v.time = aux.Time
+	v.unixTime = aux.UnixTime
 	v.name = aux.Name
 	v.email = aux.Email
 	v.login = aux.Login
@@ -97,6 +100,10 @@ func (v *Version) UnmarshalJSON(data []byte) error {
 }
 
 func (v *Version) Validate() error {
+	if v.unixTime == 0 {
+		return fmt.Errorf("unix time not set")
+	}
+
 	if text.Empty(v.name) && text.Empty(v.login) {
 		return fmt.Errorf("either name or login should be set")
 	}
  
  
  
    
    @@ -20,6 +20,8 @@ const editClockFile = "/.git/git-bug/edit-clock"
 // ErrNotARepo is the error returned when the git repo root wan't be found
 var ErrNotARepo = errors.New("not a git repository")
 
+var _ ClockedRepo = &GitRepo{}
+
 // GitRepo represents an instance of a (local) git repository.
 type GitRepo struct {
 	Path        string
@@ -440,11 +442,21 @@ func (repo *GitRepo) WriteClocks() error {
 	return nil
 }
 
+// CreateTime return the current value of the creation clock
+func (repo *GitRepo) CreateTime() lamport.Time {
+	return repo.createClock.Time()
+}
+
 // CreateTimeIncrement increment the creation clock and return the new value.
 func (repo *GitRepo) CreateTimeIncrement() (lamport.Time, error) {
 	return repo.createClock.Increment()
 }
 
+// EditTime return the current value of the edit clock
+func (repo *GitRepo) EditTime() lamport.Time {
+	return repo.editClock.Time()
+}
+
 // EditTimeIncrement increment the edit clock and return the new value.
 func (repo *GitRepo) EditTimeIncrement() (lamport.Time, error) {
 	return repo.editClock.Increment()
  
  
  
    
    @@ -9,6 +9,8 @@ import (
 	"github.com/MichaelMure/git-bug/util/lamport"
 )
 
+var _ ClockedRepo = &mockRepoForTest{}
+
 // mockRepoForTest defines an instance of Repo that can be used for testing.
 type mockRepoForTest struct {
 	config      map[string]string
@@ -227,10 +229,18 @@ func (r *mockRepoForTest) WriteClocks() error {
 	return nil
 }
 
+func (r *mockRepoForTest) CreateTime() lamport.Time {
+	return r.createClock.Time()
+}
+
 func (r *mockRepoForTest) CreateTimeIncrement() (lamport.Time, error) {
 	return r.createClock.Increment(), nil
 }
 
+func (r *mockRepoForTest) EditTime() lamport.Time {
+	return r.editClock.Time()
+}
+
 func (r *mockRepoForTest) EditTimeIncrement() (lamport.Time, error) {
 	return r.editClock.Increment(), nil
 }
  
  
  
    
    @@ -83,6 +83,7 @@ type Repo interface {
 	GetTreeHash(commit git.Hash) (git.Hash, error)
 }
 
+// ClockedRepo is a Repo that also has Lamport clocks
 type ClockedRepo interface {
 	Repo
 
@@ -92,9 +93,15 @@ type ClockedRepo interface {
 	// WriteClocks write the clocks values into the repo
 	WriteClocks() error
 
+	// CreateTime return the current value of the creation clock
+	CreateTime() lamport.Time
+
 	// CreateTimeIncrement increment the creation clock and return the new value.
 	CreateTimeIncrement() (lamport.Time, error)
 
+	// EditTime return the current value of the edit clock
+	EditTime() lamport.Time
+
 	// EditTimeIncrement increment the edit clock and return the new value.
 	EditTimeIncrement() (lamport.Time, error)