Detailed changes
  
  
    
    @@ -141,11 +141,8 @@ func TestGithubPushPull(t *testing.T) {
 	// create repo backend
 	repo := repository.CreateGoGitTestRepo(t, false)
 
-	backend, events, err := cache.NewRepoCache(repo)
+	backend, err := cache.NewRepoCacheNoEvents(repo)
 	require.NoError(t, err)
-	for event := range events {
-		require.NoError(t, event.Err)
-	}
 
 	// set author identity
 	login := "identity-test"
@@ -220,11 +217,8 @@ func TestGithubPushPull(t *testing.T) {
 	repoTwo := repository.CreateGoGitTestRepo(t, false)
 
 	// create a second backend
-	backendTwo, events, err := cache.NewRepoCache(repoTwo)
+	backendTwo, err := cache.NewRepoCacheNoEvents(repoTwo)
 	require.NoError(t, err)
-	for event := range events {
-		require.NoError(t, event.Err)
-	}
 
 	importer := &githubImporter{}
 	err = importer.Init(ctx, backend, core.Configuration{
  
  
  
    
    @@ -34,11 +34,9 @@ func TestGithubImporterIntegration(t *testing.T) {
 
 	// arrange
 	repo := repository.CreateGoGitTestRepo(t, false)
-	backend, buildEvents, err := cache.NewRepoCache(repo)
+	backend, err := cache.NewRepoCacheNoEvents(repo)
 	require.NoError(t, err)
-	for event := range buildEvents {
-		require.NoError(t, event.Err)
-	}
+
 	defer backend.Close()
 	interrupt.RegisterCleaner(backend.Close)
 	require.NoError(t, err)
  
  
  
    
    @@ -28,11 +28,8 @@ func TestGithubImporter(t *testing.T) {
 
 	repo := repository.CreateGoGitTestRepo(t, false)
 
-	backend, buildEvents, err := cache.NewRepoCache(repo)
+	backend, err := cache.NewRepoCacheNoEvents(repo)
 	require.NoError(t, err)
-	for event := range buildEvents {
-		require.NoError(t, event.Err)
-	}
 
 	defer backend.Close()
 	interrupt.RegisterCleaner(backend.Close)
  
  
  
    
    @@ -147,11 +147,8 @@ func TestGitlabPushPull(t *testing.T) {
 	// create repo backend
 	repo := repository.CreateGoGitTestRepo(t, false)
 
-	backend, events, err := cache.NewRepoCache(repo)
+	backend, err := cache.NewRepoCacheNoEvents(repo)
 	require.NoError(t, err)
-	for event := range events {
-		require.NoError(t, event.Err)
-	}
 
 	// set author identity
 	login := "test-identity"
@@ -223,11 +220,8 @@ func TestGitlabPushPull(t *testing.T) {
 	repoTwo := repository.CreateGoGitTestRepo(t, false)
 
 	// create a second backend
-	backendTwo, events, err := cache.NewRepoCache(repoTwo)
+	backendTwo, err := cache.NewRepoCacheNoEvents(repoTwo)
 	require.NoError(t, err)
-	for event := range events {
-		require.NoError(t, event.Err)
-	}
 
 	importer := &gitlabImporter{}
 	err = importer.Init(ctx, backend, core.Configuration{
  
  
  
    
    @@ -33,11 +33,8 @@ func TestGitlabImport(t *testing.T) {
 
 	repo := repository.CreateGoGitTestRepo(t, false)
 
-	backend, buildEvents, err := cache.NewRepoCache(repo)
+	backend, err := cache.NewRepoCacheNoEvents(repo)
 	require.NoError(t, err)
-	for event := range buildEvents {
-		require.NoError(t, event.Err)
-	}
 
 	defer backend.Close()
 	interrupt.RegisterCleaner(backend.Close)
  
  
  
    
    @@ -44,7 +44,7 @@ func NewRepoCacheBug(repo repository.ClockedRepo,
 	sc := NewSubCache[*bug.Bug, *BugExcerpt, *BugCache](
 		repo, resolvers, getUserIdentity,
 		makeCached, NewBugExcerpt, makeIndexData, actions,
-		"bug", "bugs",
+		bug.Typename, bug.Namespace,
 		formatVersion, defaultMaxLoadedBugs,
 	)
 
@@ -124,7 +124,7 @@ func (c *RepoCacheBug) Query(q *query.Query) ([]entity.Id, error) {
 	if q.Search != nil {
 		foundBySearch = map[entity.Id]*BugExcerpt{}
 
-		index, err := c.repo.GetIndex("bug")
+		index, err := c.repo.GetIndex("bugs")
 		if err != nil {
 			return nil, err
 		}
  
  
  
    
    @@ -9,6 +9,8 @@ import (
 	"github.com/MichaelMure/git-bug/util/lamport"
 )
 
+var _ CacheEntity = &CachedEntityBase[dag.Snapshot, dag.Operation]{}
+
 // CachedEntityBase provide the base function of an entity managed by the cache.
 type CachedEntityBase[SnapT dag.Snapshot, OpT dag.Operation] struct {
 	repo            repository.ClockedRepo
@@ -92,6 +94,10 @@ func (e *CachedEntityBase[SnapT, OpT]) NeedCommit() bool {
 	return e.entity.NeedCommit()
 }
 
+func (e *CachedEntityBase[SnapT, OpT]) Lock() {
+	e.mu.Lock()
+}
+
 func (e *CachedEntityBase[SnapT, OpT]) CreateLamportTime() lamport.Time {
 	return e.entity.CreateLamportTime()
 }
  
  
  
    
    @@ -1,18 +1,22 @@
 package cache
 
 import (
+	"sync"
+
 	"github.com/MichaelMure/git-bug/entities/identity"
 	"github.com/MichaelMure/git-bug/entity"
 	"github.com/MichaelMure/git-bug/repository"
 )
 
 var _ identity.Interface = &IdentityCache{}
+var _ CacheEntity = &IdentityCache{}
 
 // IdentityCache is a wrapper around an Identity for caching.
 type IdentityCache struct {
 	repo          repository.ClockedRepo
 	entityUpdated func(id entity.Id) error
 
+	mu sync.Mutex
 	*identity.Identity
 }
 
@@ -29,7 +33,9 @@ func (i *IdentityCache) notifyUpdated() error {
 }
 
 func (i *IdentityCache) Mutate(repo repository.RepoClock, f func(*identity.Mutator)) error {
+	i.mu.Lock()
 	err := i.Identity.Mutate(repo, f)
+	i.mu.Unlock()
 	if err != nil {
 		return err
 	}
@@ -37,7 +43,9 @@ func (i *IdentityCache) Mutate(repo repository.RepoClock, f func(*identity.Mutat
 }
 
 func (i *IdentityCache) Commit() error {
+	i.mu.Lock()
 	err := i.Identity.Commit(i.repo)
+	i.mu.Unlock()
 	if err != nil {
 		return err
 	}
@@ -45,9 +53,15 @@ func (i *IdentityCache) Commit() error {
 }
 
 func (i *IdentityCache) CommitAsNeeded() error {
+	i.mu.Lock()
 	err := i.Identity.CommitAsNeeded(i.repo)
+	i.mu.Unlock()
 	if err != nil {
 		return err
 	}
 	return i.notifyUpdated()
 }
+
+func (i *IdentityCache) Lock() {
+	i.mu.Lock()
+}
  
  
  
    
    @@ -48,7 +48,7 @@ func NewRepoCacheIdentity(repo repository.ClockedRepo,
 	sc := NewSubCache[*identity.Identity, *IdentityExcerpt, *IdentityCache](
 		repo, resolvers, getUserIdentity,
 		makeCached, NewIdentityExcerpt, makeIndex, actions,
-		"identity", "identities",
+		identity.Typename, identity.Namespace,
 		formatVersion, defaultMaxLoadedBugs,
 	)
 
  
  
  
    
    @@ -21,13 +21,13 @@ func NewMultiRepoCache() *MultiRepoCache {
 }
 
 // RegisterRepository register a named repository. Use this for multi-repo setup
-func (c *MultiRepoCache) RegisterRepository(ref string, repo repository.ClockedRepo) (*RepoCache, chan BuildEvent, error) {
-	r, events, err := NewRepoCache(repo)
+func (c *MultiRepoCache) RegisterRepository(name string, repo repository.ClockedRepo) (*RepoCache, chan BuildEvent, error) {
+	r, events, err := NewNamedRepoCache(repo, name)
 	if err != nil {
 		return nil, nil, err
 	}
 
-	c.repos[ref] = r
+	c.repos[name] = r
 	return r, events, nil
 }
 
@@ -55,9 +55,9 @@ func (c *MultiRepoCache) DefaultRepo() (*RepoCache, error) {
 	panic("unreachable")
 }
 
-// ResolveRepo retrieve a repository with a reference
-func (c *MultiRepoCache) ResolveRepo(ref string) (*RepoCache, error) {
-	r, ok := c.repos[ref]
+// ResolveRepo retrieve a repository by name
+func (c *MultiRepoCache) ResolveRepo(name string) (*RepoCache, error) {
+	r, ok := c.repos[name]
 	if !ok {
 		return nil, fmt.Errorf("unknown repo")
 	}
  
  
  
    
    @@ -27,6 +27,7 @@ var _ repository.RepoCommon = &RepoCache{}
 var _ repository.RepoConfig = &RepoCache{}
 var _ repository.RepoKeyring = &RepoCache{}
 
+// cacheMgmt is the expected interface for a sub-cache.
 type cacheMgmt interface {
 	Typename() string
 	Load() error
@@ -58,7 +59,7 @@ type RepoCache struct {
 	// the name of the repository, as defined in the MultiRepoCache
 	name string
 
-	// resolvers for all known entities
+	// resolvers for all known entities and excerpts
 	resolvers entity.Resolvers
 
 	bugs       *RepoCacheBug
@@ -71,10 +72,16 @@ type RepoCache struct {
 	userIdentityId entity.Id
 }
 
+// NewRepoCache create or open an unnamed (aka default) cache on top of a raw repository.
+// If the returned BuildEvent channel is not nil, the caller is expected to read all events before the cache is considered
+// ready to use.
 func NewRepoCache(r repository.ClockedRepo) (*RepoCache, chan BuildEvent, error) {
 	return NewNamedRepoCache(r, "")
 }
 
+// NewNamedRepoCache create or open a named cache on top of a raw repository.
+// If the returned BuildEvent channel is not nil, the caller is expected to read all events before the cache is considered
+// ready to use.
 func NewNamedRepoCache(r repository.ClockedRepo, name string) (*RepoCache, chan BuildEvent, error) {
 	c := &RepoCache{
 		repo: r,
@@ -96,16 +103,12 @@ func NewNamedRepoCache(r repository.ClockedRepo, name string) (*RepoCache, chan
 
 	err := c.lock()
 	if err != nil {
-		closed := make(chan BuildEvent)
-		close(closed)
-		return &RepoCache{}, closed, err
+		return &RepoCache{}, nil, err
 	}
 
 	err = c.load()
 	if err == nil {
-		closed := make(chan BuildEvent)
-		close(closed)
-		return c, closed, nil
+		return c, nil, nil
 	}
 
 	// Cache is either missing, broken or outdated. Rebuilding.
@@ -114,6 +117,23 @@ func NewNamedRepoCache(r repository.ClockedRepo, name string) (*RepoCache, chan
 	return c, events, nil
 }
 
+func NewRepoCacheNoEvents(r repository.ClockedRepo) (*RepoCache, error) {
+	cache, events, err := NewRepoCache(r)
+	if err != nil {
+		return nil, err
+	}
+	if events != nil {
+		for event := range events {
+			if event.Err != nil {
+				for range events {
+				}
+				return nil, err
+			}
+		}
+	}
+	return cache, nil
+}
+
 // Bugs gives access to the Bug entities
 func (c *RepoCache) Bugs() *RepoCacheBug {
 	return c.bugs
  
  
  
    
    @@ -8,23 +8,17 @@ import (
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 
+	"github.com/MichaelMure/git-bug/entities/bug"
+	"github.com/MichaelMure/git-bug/entities/identity"
 	"github.com/MichaelMure/git-bug/entity"
 	"github.com/MichaelMure/git-bug/query"
 	"github.com/MichaelMure/git-bug/repository"
 )
 
-func noBuildEventErrors(t *testing.T, c chan BuildEvent) {
-	t.Helper()
-	for event := range c {
-		require.NoError(t, event.Err)
-	}
-}
-
 func TestCache(t *testing.T) {
 	repo := repository.CreateGoGitTestRepo(t, false)
 
-	cache, events, err := NewRepoCache(repo)
-	noBuildEventErrors(t, events)
+	cache, err := NewRepoCacheNoEvents(repo)
 	require.NoError(t, err)
 
 	// Create, set and get user identity
@@ -43,17 +37,27 @@ func TestCache(t *testing.T) {
 	// Two identical identities yield a different id
 	require.NotEqual(t, iden1.Id(), iden2.Id())
 
+	indexCount := func(name string) uint64 {
+		idx, err := repo.GetIndex(name)
+		require.NoError(t, err)
+		count, err := idx.DocCount()
+		require.NoError(t, err)
+		return count
+	}
+
 	// There is now two identities in the cache
 	require.Len(t, cache.Identities().AllIds(), 2)
 	require.Len(t, cache.identities.excerpts, 2)
 	require.Len(t, cache.identities.cached, 2)
+	require.Equal(t, uint64(2), indexCount(identity.Namespace))
+	require.Equal(t, uint64(0), indexCount(bug.Namespace))
 
 	// Create a bug
 	bug1, _, err := cache.Bugs().New("title", "message")
 	require.NoError(t, err)
 
 	// It's possible to create two identical bugs
-	bug2, _, err := cache.Bugs().New("title", "message")
+	bug2, _, err := cache.Bugs().New("title", "marker")
 	require.NoError(t, err)
 
 	// two identical bugs yield a different id
@@ -63,6 +67,8 @@ func TestCache(t *testing.T) {
 	require.Len(t, cache.Bugs().AllIds(), 2)
 	require.Len(t, cache.bugs.excerpts, 2)
 	require.Len(t, cache.bugs.cached, 2)
+	require.Equal(t, uint64(2), indexCount(identity.Namespace))
+	require.Equal(t, uint64(2), indexCount(bug.Namespace))
 
 	// Resolving
 	_, err = cache.Identities().Resolve(iden1.Id())
@@ -86,6 +92,12 @@ func TestCache(t *testing.T) {
 	require.NoError(t, err)
 	require.Len(t, res, 2)
 
+	q, err = query.Parse("status:open marker") // full-text search
+	require.NoError(t, err)
+	res, err = cache.Bugs().Query(q)
+	require.NoError(t, err)
+	require.Len(t, res, 1)
+
 	// Close
 	require.NoError(t, cache.Close())
 	require.Empty(t, cache.bugs.cached)
@@ -95,13 +107,14 @@ func TestCache(t *testing.T) {
 
 	// Reload, only excerpt are loaded, but as we need to load the identities used in the bugs
 	// to check the signatures, we also load the identity used above
-	cache, events, err = NewRepoCache(repo)
-	noBuildEventErrors(t, events)
+	cache, err = NewRepoCacheNoEvents(repo)
 	require.NoError(t, err)
 	require.Len(t, cache.bugs.cached, 0)
 	require.Len(t, cache.bugs.excerpts, 2)
 	require.Len(t, cache.identities.cached, 0)
 	require.Len(t, cache.identities.excerpts, 2)
+	require.Equal(t, uint64(2), indexCount(identity.Namespace))
+	require.Equal(t, uint64(2), indexCount(bug.Namespace))
 
 	// Resolving load from the disk
 	_, err = cache.Identities().Resolve(iden1.Id())
@@ -122,12 +135,10 @@ func TestCache(t *testing.T) {
 func TestCachePushPull(t *testing.T) {
 	repoA, repoB, _ := repository.SetupGoGitReposAndRemote(t)
 
-	cacheA, events, err := NewRepoCache(repoA)
-	noBuildEventErrors(t, events)
+	cacheA, err := NewRepoCacheNoEvents(repoA)
 	require.NoError(t, err)
 
-	cacheB, events, err := NewRepoCache(repoB)
-	noBuildEventErrors(t, events)
+	cacheB, err := NewRepoCacheNoEvents(repoB)
 	require.NoError(t, err)
 
 	// Create, set and get user identity
@@ -190,8 +201,7 @@ func TestRemove(t *testing.T) {
 	err = repo.AddRemote("remoteB", remoteB.GetLocalRemote())
 	require.NoError(t, err)
 
-	repoCache, events, err := NewRepoCache(repo)
-	noBuildEventErrors(t, events)
+	repoCache, err := NewRepoCacheNoEvents(repo)
 	require.NoError(t, err)
 
 	rene, err := repoCache.Identities().New("RenΓ© Descartes", "rene@descartes.fr")
@@ -230,8 +240,7 @@ func TestRemove(t *testing.T) {
 
 func TestCacheEviction(t *testing.T) {
 	repo := repository.CreateGoGitTestRepo(t, false)
-	repoCache, events, err := NewRepoCache(repo)
-	noBuildEventErrors(t, events)
+	repoCache, err := NewRepoCacheNoEvents(repo)
 	require.NoError(t, err)
 	repoCache.setCacheSize(2)
 
@@ -299,8 +308,7 @@ func TestLongDescription(t *testing.T) {
 
 	repo := repository.CreateGoGitTestRepo(t, false)
 
-	backend, events, err := NewRepoCache(repo)
-	noBuildEventErrors(t, events)
+	backend, err := NewRepoCacheNoEvents(repo)
 	require.NoError(t, err)
 
 	i, err := backend.Identities().New("RenΓ© Descartes", "rene@descartes.fr")
  
  
  
    
    @@ -4,6 +4,7 @@ import (
 	"bytes"
 	"encoding/gob"
 	"fmt"
+	"path/filepath"
 	"sync"
 
 	"github.com/pkg/errors"
@@ -21,6 +22,7 @@ type Excerpt interface {
 type CacheEntity interface {
 	Id() entity.Id
 	NeedCommit() bool
+	Lock()
 }
 
 type getUserIdentityFunc func() (*IdentityCache, error)
@@ -94,7 +96,7 @@ func (sc *SubCache[EntityT, ExcerptT, CacheT]) Load() error {
 	sc.mu.Lock()
 	defer sc.mu.Unlock()
 
-	f, err := sc.repo.LocalStorage().Open(sc.namespace + "-file")
+	f, err := sc.repo.LocalStorage().Open(filepath.Join("cache", sc.namespace))
 	if err != nil {
 		return err
 	}
@@ -123,7 +125,7 @@ func (sc *SubCache[EntityT, ExcerptT, CacheT]) Load() error {
 
 	sc.excerpts = aux.Excerpts
 
-	index, err := sc.repo.GetIndex(sc.typename)
+	index, err := sc.repo.GetIndex(sc.namespace)
 	if err != nil {
 		return err
 	}
@@ -162,7 +164,7 @@ func (sc *SubCache[EntityT, ExcerptT, CacheT]) write() error {
 		return err
 	}
 
-	f, err := sc.repo.LocalStorage().Create(sc.namespace + "-file")
+	f, err := sc.repo.LocalStorage().Create(filepath.Join("cache", sc.namespace))
 	if err != nil {
 		return err
 	}
@@ -180,7 +182,7 @@ func (sc *SubCache[EntityT, ExcerptT, CacheT]) Build() error {
 
 	allEntities := sc.actions.ReadAllWithResolver(sc.repo, sc.resolvers())
 
-	index, err := sc.repo.GetIndex(sc.typename)
+	index, err := sc.repo.GetIndex(sc.namespace)
 	if err != nil {
 		return err
 	}
@@ -462,7 +464,7 @@ func (sc *SubCache[EntityT, ExcerptT, CacheT]) entityUpdated(id entity.Id) error
 	sc.excerpts[id] = sc.makeExcerpt(e)
 	sc.mu.Unlock()
 
-	index, err := sc.repo.GetIndex(sc.typename)
+	index, err := sc.repo.GetIndex(sc.namespace)
 	if err != nil {
 		return err
 	}
@@ -489,8 +491,10 @@ func (sc *SubCache[EntityT, ExcerptT, CacheT]) evictIfNeeded() {
 			continue
 		}
 
-		// TODO
-		// b.Lock()
+		// as a form of assurance that evicted entities don't get manipulated, we lock them here.
+		// if something try to do it anyway, it will lock the program and make it obvious.
+		b.Lock()
+
 		sc.lru.Remove(id)
 		delete(sc.cached, id)
 
  
  
  
    
    @@ -13,11 +13,8 @@ import (
 func TestSelect(t *testing.T) {
 	repo := repository.CreateGoGitTestRepo(t, false)
 
-	repoCache, events, err := cache.NewRepoCache(repo)
+	repoCache, err := cache.NewRepoCacheNoEvents(repo)
 	require.NoError(t, err)
-	for event := range events {
-		require.NoError(t, event.Err)
-	}
 
 	_, _, err = ResolveBug(repoCache, []string{})
 	require.Equal(t, ErrNoValidId, err)
  
  
  
    
    @@ -136,19 +136,17 @@ func LoadBackend(env *Env) func(*cobra.Command, []string) error {
 
 		if events != nil {
 			env.Err.Println("Building cache... ")
-		}
-
-		for event := range events {
-			if event.Err != nil {
-				env.Err.Printf("Cache building error [%s]: %v\n", event.Typename, event.Err)
-				continue
-			}
-
-			switch event.Event {
-			case cache.BuildEventStarted:
-				env.Err.Printf("[%s] started\n", event.Typename)
-			case cache.BuildEventFinished:
-				env.Err.Printf("[%s] done\n", event.Typename)
+			for event := range events {
+				if event.Err != nil {
+					env.Err.Printf("Cache building error [%s]: %v\n", event.Typename, event.Err)
+					continue
+				}
+				switch event.Event {
+				case cache.BuildEventStarted:
+					env.Err.Printf("[%s] started\n", event.Typename)
+				case cache.BuildEventFinished:
+					env.Err.Printf("[%s] done\n", event.Typename)
+				}
 			}
 		}
 
  
  
  
    
    @@ -34,11 +34,8 @@ func NewTestEnv(t *testing.T) *Env {
 
 	buf := new(bytes.Buffer)
 
-	backend, events, err := cache.NewRepoCache(repo)
+	backend, err := cache.NewRepoCacheNoEvents(repo)
 	require.NoError(t, err)
-	for event := range events {
-		require.NoError(t, event.Err)
-	}
 
 	t.Cleanup(func() {
 		backend.Close()
  
  
  
    
    @@ -61,7 +61,7 @@ the same git remote you are already using to collaborate with other people.
 	const remoteGroup = "remote"
 
 	cmd.AddGroup(&cobra.Group{ID: entityGroup, Title: "Entities"})
-	cmd.AddGroup(&cobra.Group{ID: uiGroup, Title: "User interfaces"})
+	cmd.AddGroup(&cobra.Group{ID: uiGroup, Title: "Interactive interfaces"})
 	cmd.AddGroup(&cobra.Group{ID: remoteGroup, Title: "Interaction with the outside world"})
 
 	addCmdWithGroup := func(child *cobra.Command, groupID string) {
  
  
  
    
    @@ -110,17 +110,19 @@ func runWebUI(env *execenv.Env, opts webUIOptions) error {
 		return err
 	}
 
-	for event := range events {
-		if event.Err != nil {
-			env.Err.Printf("Cache building error [%s]: %v\n", event.Typename, event.Err)
-			continue
-		}
-
-		switch event.Event {
-		case cache.BuildEventStarted:
-			env.Err.Printf("[%s] started\n", event.Typename)
-		case cache.BuildEventFinished:
-			env.Err.Printf("[%s] done\n", event.Typename)
+	if events != nil {
+		env.Err.Println("Building cache... ")
+		for event := range events {
+			if event.Err != nil {
+				env.Err.Printf("Cache building error [%s]: %v\n", event.Typename, event.Err)
+				continue
+			}
+			switch event.Event {
+			case cache.BuildEventStarted:
+				env.Err.Printf("[%s] started\n", event.Typename)
+			case cache.BuildEventFinished:
+				env.Err.Printf("[%s] done\n", event.Typename)
+			}
 		}
 	}
 
  
  
  
    
    @@ -20,9 +20,12 @@ var _ entity.Interface = &Bug{}
 // 4: with DAG entity framework
 const formatVersion = 4
 
+const Typename = "bug"
+const Namespace = "bugs"
+
 var def = dag.Definition{
-	Typename:             "bug",
-	Namespace:            "bugs",
+	Typename:             Typename,
+	Namespace:            Namespace,
 	OperationUnmarshaler: operationUnmarshaler,
 	FormatVersion:        formatVersion,
 }
  
  
  
    
    @@ -19,6 +19,9 @@ const identityRemoteRefPattern = "refs/remotes/%s/identities/"
 const versionEntryName = "version"
 const identityConfigKey = "git-bug.identity"
 
+const Typename = "identity"
+const Namespace = "identities"
+
 var ErrNonFastForwardMerge = errors.New("non fast-forward identity merge")
 var ErrNoIdentitySet = errors.New("No identity is set.\n" +
 	"To interact with bugs, an identity first needs to be created using " +
@@ -105,7 +108,7 @@ func read(repo repository.Repo, ref string) (*Identity, error) {
 
 	hashes, err := repo.ListCommits(ref)
 	if err != nil {
-		return nil, entity.NewErrNotFound("identity")
+		return nil, entity.NewErrNotFound(Typename)
 	}
 	if len(hashes) == 0 {
 		return nil, fmt.Errorf("empty identity")
@@ -170,7 +173,7 @@ func RemoveIdentity(repo repository.ClockedRepo, id entity.Id) error {
 		return err
 	}
 	if len(refs) > 1 {
-		return entity.NewErrMultipleMatch("identity", entity.RefsToIds(refs))
+		return entity.NewErrMultipleMatch(Typename, entity.RefsToIds(refs))
 	}
 	if len(refs) == 1 {
 		// we have the identity locally
@@ -189,7 +192,7 @@ func RemoveIdentity(repo repository.ClockedRepo, id entity.Id) error {
 			return err
 		}
 		if len(remoteRefs) > 1 {
-			return entity.NewErrMultipleMatch("identity", entity.RefsToIds(refs))
+			return entity.NewErrMultipleMatch(Typename, entity.RefsToIds(refs))
 		}
 		if len(remoteRefs) == 1 {
 			// found the identity in a remote
@@ -198,7 +201,7 @@ func RemoveIdentity(repo repository.ClockedRepo, id entity.Id) error {
 	}
 
 	if len(fullMatches) == 0 {
-		return entity.NewErrNotFound("identity")
+		return entity.NewErrNotFound(Typename)
 	}
 
 	for _, ref := range fullMatches {
  
  
  
    
    @@ -13,12 +13,12 @@ import (
 // Fetch retrieve updates from a remote
 // This does not change the local identities state
 func Fetch(repo repository.Repo, remote string) (string, error) {
-	return repo.FetchRefs(remote, "identities")
+	return repo.FetchRefs(remote, Namespace)
 }
 
 // Push update a remote with the local changes
 func Push(repo repository.Repo, remote string) (string, error) {
-	return repo.PushRefs(remote, "identities")
+	return repo.PushRefs(remote, Namespace)
 }
 
 // Pull will do a Fetch + MergeAll
  
  
  
    
    @@ -217,11 +217,12 @@ func isGitDir(path string) (bool, error) {
 
 func (repo *GoGitRepo) Close() error {
 	var firstErr error
-	for _, index := range repo.indexes {
+	for name, index := range repo.indexes {
 		err := index.Close()
 		if err != nil && firstErr == nil {
 			firstErr = err
 		}
+		delete(repo.indexes, name)
 	}
 	return firstErr
 }
  
  
  
    
    @@ -63,7 +63,7 @@ func (g *ErrWaitGroup) Go(f func() error) {
 
 		if err := f(); err != nil {
 			g.mu.Lock()
-			err = Join(g.err, err)
+			g.err = Join(g.err, err)
 			g.mu.Unlock()
 		}
 	}()