fix everything following the hash-->id change

Michael Muré created

Change summary

bridge/github/export.go           |  59 +----
bridge/github/export_test.go      |  10 
bridge/github/import.go           |  35 +--
bridge/gitlab/import.go           |  23 +-
bug/snapshot.go                   |   5 
cache/bug_cache.go                |  20 -
graphql/graph/gen_graph.go        | 290 ++++++++++++++++----------------
graphql/schema/operations.graphql |  30 +-
graphql/schema/timeline.graphql   |  24 +-
termui/show_bug.go                |   9 
termui/termui.go                  |   8 
11 files changed, 230 insertions(+), 283 deletions(-)

Detailed changes

bridge/github/export.go 🔗

@@ -17,7 +17,6 @@ import (
 	"github.com/MichaelMure/git-bug/bridge/core"
 	"github.com/MichaelMure/git-bug/bug"
 	"github.com/MichaelMure/git-bug/cache"
-	"github.com/MichaelMure/git-bug/util/git"
 )
 
 var (
@@ -144,7 +143,6 @@ func (ge *githubExporter) exportBug(b *cache.BugCache, since time.Time, out chan
 
 	var bugGithubID string
 	var bugGithubURL string
-	var bugCreationHash string
 
 	// Special case:
 	// if a user try to export a bug that is not already exported to Github (or imported
@@ -209,15 +207,8 @@ func (ge *githubExporter) exportBug(b *cache.BugCache, since time.Time, out chan
 
 		out <- core.NewExportBug(b.Id())
 
-		hash, err := createOp.Hash()
-		if err != nil {
-			err := errors.Wrap(err, "comment hash")
-			out <- core.NewExportError(err, b.Id())
-			return
-		}
-
 		// mark bug creation operation as exported
-		if err := markOperationAsExported(b, hash, id, url); err != nil {
+		if err := markOperationAsExported(b, createOp.ID(), id, url); err != nil {
 			err := errors.Wrap(err, "marking operation as exported")
 			out <- core.NewExportError(err, b.Id())
 			return
@@ -235,17 +226,8 @@ func (ge *githubExporter) exportBug(b *cache.BugCache, since time.Time, out chan
 		bugGithubURL = url
 	}
 
-	// get createOp hash
-	hash, err := createOp.Hash()
-	if err != nil {
-		out <- core.NewExportError(err, b.Id())
-		return
-	}
-
-	bugCreationHash = hash.String()
-
 	// cache operation github id
-	ge.cachedOperationIDs[bugCreationHash] = bugGithubID
+	ge.cachedOperationIDs[createOp.ID()] = bugGithubID
 
 	for _, op := range snapshot.Operations[1:] {
 		// ignore SetMetadata operations
@@ -253,26 +235,18 @@ func (ge *githubExporter) exportBug(b *cache.BugCache, since time.Time, out chan
 			continue
 		}
 
-		// get operation hash
-		hash, err := op.Hash()
-		if err != nil {
-			err := errors.Wrap(err, "operation hash")
-			out <- core.NewExportError(err, b.Id())
-			return
-		}
-
 		// ignore operations already existing in github (due to import or export)
 		// cache the ID of already exported or imported issues and events from Github
 		if id, ok := op.GetMetadata(keyGithubId); ok {
-			ge.cachedOperationIDs[hash.String()] = id
-			out <- core.NewExportNothing(hash.String(), "already exported operation")
+			ge.cachedOperationIDs[op.ID()] = id
+			out <- core.NewExportNothing(op.ID(), "already exported operation")
 			continue
 		}
 
 		opAuthor := op.GetAuthor()
 		client, err := ge.getIdentityClient(opAuthor.Id())
 		if err != nil {
-			out <- core.NewExportNothing(hash.String(), "missing operation author token")
+			out <- core.NewExportNothing(op.ID(), "missing operation author token")
 			continue
 		}
 
@@ -289,18 +263,17 @@ func (ge *githubExporter) exportBug(b *cache.BugCache, since time.Time, out chan
 				return
 			}
 
-			out <- core.NewExportComment(hash.String())
+			out <- core.NewExportComment(op.ID())
 
 			// cache comment id
-			ge.cachedOperationIDs[hash.String()] = id
+			ge.cachedOperationIDs[op.ID()] = id
 
 		case *bug.EditCommentOperation:
 
 			opr := op.(*bug.EditCommentOperation)
-			targetHash := opr.Target.String()
 
 			// Since github doesn't consider the issue body as a comment
-			if targetHash == bugCreationHash {
+			if opr.Target == createOp.ID() {
 
 				// case bug creation operation: we need to edit the Github issue
 				if err := updateGithubIssueBody(client, bugGithubID, opr.Message); err != nil {
@@ -309,7 +282,7 @@ func (ge *githubExporter) exportBug(b *cache.BugCache, since time.Time, out chan
 					return
 				}
 
-				out <- core.NewExportCommentEdition(hash.String())
+				out <- core.NewExportCommentEdition(op.ID())
 
 				id = bugGithubID
 				url = bugGithubURL
@@ -317,7 +290,7 @@ func (ge *githubExporter) exportBug(b *cache.BugCache, since time.Time, out chan
 			} else {
 
 				// case comment edition operation: we need to edit the Github comment
-				commentID, ok := ge.cachedOperationIDs[targetHash]
+				commentID, ok := ge.cachedOperationIDs[opr.ID()]
 				if !ok {
 					panic("unexpected error: comment id not found")
 				}
@@ -329,7 +302,7 @@ func (ge *githubExporter) exportBug(b *cache.BugCache, since time.Time, out chan
 					return
 				}
 
-				out <- core.NewExportCommentEdition(hash.String())
+				out <- core.NewExportCommentEdition(op.ID())
 
 				// use comment id/url instead of issue id/url
 				id = eid
@@ -344,7 +317,7 @@ func (ge *githubExporter) exportBug(b *cache.BugCache, since time.Time, out chan
 				return
 			}
 
-			out <- core.NewExportStatusChange(hash.String())
+			out <- core.NewExportStatusChange(op.ID())
 
 			id = bugGithubID
 			url = bugGithubURL
@@ -357,7 +330,7 @@ func (ge *githubExporter) exportBug(b *cache.BugCache, since time.Time, out chan
 				return
 			}
 
-			out <- core.NewExportTitleEdition(hash.String())
+			out <- core.NewExportTitleEdition(op.ID())
 
 			id = bugGithubID
 			url = bugGithubURL
@@ -370,7 +343,7 @@ func (ge *githubExporter) exportBug(b *cache.BugCache, since time.Time, out chan
 				return
 			}
 
-			out <- core.NewExportLabelChange(hash.String())
+			out <- core.NewExportLabelChange(op.ID())
 
 			id = bugGithubID
 			url = bugGithubURL
@@ -380,7 +353,7 @@ func (ge *githubExporter) exportBug(b *cache.BugCache, since time.Time, out chan
 		}
 
 		// mark operation as exported
-		if err := markOperationAsExported(b, hash, id, url); err != nil {
+		if err := markOperationAsExported(b, op.ID(), id, url); err != nil {
 			err := errors.Wrap(err, "marking operation as exported")
 			out <- core.NewExportError(err, b.Id())
 			return
@@ -438,7 +411,7 @@ func getRepositoryNodeID(owner, project, token string) (string, error) {
 	return aux.NodeID, nil
 }
 
-func markOperationAsExported(b *cache.BugCache, target git.Hash, githubID, githubURL string) error {
+func markOperationAsExported(b *cache.BugCache, target string, githubID, githubURL string) error {
 	_, err := b.SetMetadata(
 		target,
 		map[string]string{

bridge/github/export_test.go 🔗

@@ -58,19 +58,13 @@ func testCases(t *testing.T, repo *cache.RepoCache, identity *cache.IdentityCach
 	bugWithCommentEditions, createOp, err := repo.NewBug("bug with comments editions", "new bug")
 	require.NoError(t, err)
 
-	createOpHash, err := createOp.Hash()
-	require.NoError(t, err)
-
-	_, err = bugWithCommentEditions.EditComment(createOpHash, "first comment edited")
+	_, err = bugWithCommentEditions.EditComment(createOp.ID(), "first comment edited")
 	require.NoError(t, err)
 
 	commentOp, err := bugWithCommentEditions.AddComment("first comment")
 	require.NoError(t, err)
 
-	commentOpHash, err := commentOp.Hash()
-	require.NoError(t, err)
-
-	_, err = bugWithCommentEditions.EditComment(commentOpHash, "first comment edited")
+	_, err = bugWithCommentEditions.EditComment(commentOp.ID(), "first comment edited")
 	require.NoError(t, err)
 
 	// bug status changed

bridge/github/import.go 🔗

@@ -11,7 +11,6 @@ import (
 	"github.com/MichaelMure/git-bug/bug"
 	"github.com/MichaelMure/git-bug/cache"
 	"github.com/MichaelMure/git-bug/identity"
-	"github.com/MichaelMure/git-bug/util/git"
 	"github.com/MichaelMure/git-bug/util/text"
 )
 
@@ -93,7 +92,7 @@ func (gi *githubImporter) ensureIssue(repo *cache.RepoCache, issue issueTimeline
 	}
 
 	// get issue edits
-	issueEdits := []userContentEdit{}
+	var issueEdits []userContentEdit
 	for gi.iterator.NextIssueEdit() {
 		issueEdits = append(issueEdits, gi.iterator.IssueEditValue())
 	}
@@ -307,15 +306,14 @@ func (gi *githubImporter) ensureTimelineComment(repo *cache.RepoCache, b *cache.
 		return err
 	}
 
-	var target git.Hash
-	target, err = b.ResolveOperationWithMetadata(keyGithubId, parseId(item.Id))
+	targetOpID, err := b.ResolveOperationWithMetadata(keyGithubId, parseId(item.Id))
 	if err != nil && err != cache.ErrNoMatchingOp {
 		// real error
 		return err
 	}
+
 	// if no edits are given we create the comment
 	if len(edits) == 0 {
-
 		// if comment doesn't exist
 		if err == cache.ErrNoMatchingOp {
 			cleanText, err := text.Cleanup(string(item.Body))
@@ -324,7 +322,7 @@ func (gi *githubImporter) ensureTimelineComment(repo *cache.RepoCache, b *cache.
 			}
 
 			// add comment operation
-			op, err := b.AddCommentRaw(
+			_, err = b.AddCommentRaw(
 				author,
 				item.CreatedAt.Unix(),
 				cleanText,
@@ -334,19 +332,11 @@ func (gi *githubImporter) ensureTimelineComment(repo *cache.RepoCache, b *cache.
 					keyGithubUrl: parseId(item.Url.String()),
 				},
 			)
-			if err != nil {
-				return err
-			}
-
-			// set hash
-			target, err = op.Hash()
-			if err != nil {
-				return err
-			}
+			return err
 		}
 	} else {
 		for i, edit := range edits {
-			if i == 0 && target != "" {
+			if i == 0 && targetOpID != "" {
 				// The first edit in the github result is the comment creation itself, we already have that
 				continue
 			}
@@ -358,7 +348,7 @@ func (gi *githubImporter) ensureTimelineComment(repo *cache.RepoCache, b *cache.
 			}
 
 			// create comment when target is empty
-			if target == "" {
+			if targetOpID == "" {
 				cleanText, err := text.Cleanup(string(*edit.Diff))
 				if err != nil {
 					return err
@@ -378,16 +368,13 @@ func (gi *githubImporter) ensureTimelineComment(repo *cache.RepoCache, b *cache.
 					return err
 				}
 
-				// set hash
-				target, err = op.Hash()
-				if err != nil {
-					return err
-				}
+				// set target for the nexr edit now that the comment is created
+				targetOpID = op.ID()
 
 				continue
 			}
 
-			err = gi.ensureCommentEdit(repo, b, target, edit)
+			err = gi.ensureCommentEdit(repo, b, targetOpID, edit)
 			if err != nil {
 				return err
 			}
@@ -396,7 +383,7 @@ func (gi *githubImporter) ensureTimelineComment(repo *cache.RepoCache, b *cache.
 	return nil
 }
 
-func (gi *githubImporter) ensureCommentEdit(repo *cache.RepoCache, b *cache.BugCache, target git.Hash, edit userContentEdit) error {
+func (gi *githubImporter) ensureCommentEdit(repo *cache.RepoCache, b *cache.BugCache, target string, edit userContentEdit) error {
 	_, err := b.ResolveOperationWithMetadata(keyGithubId, parseId(edit.Id))
 	if err == nil {
 		// already imported

bridge/gitlab/import.go 🔗

@@ -11,7 +11,6 @@ import (
 	"github.com/MichaelMure/git-bug/bug"
 	"github.com/MichaelMure/git-bug/cache"
 	"github.com/MichaelMure/git-bug/identity"
-	"github.com/MichaelMure/git-bug/util/git"
 	"github.com/MichaelMure/git-bug/util/text"
 )
 
@@ -130,10 +129,10 @@ func (gi *gitlabImporter) ensureIssue(repo *cache.RepoCache, issue *gitlab.Issue
 }
 
 func (gi *gitlabImporter) ensureNote(repo *cache.RepoCache, b *cache.BugCache, note *gitlab.Note) error {
-	id := parseID(note.ID)
+	gitlabID := parseID(note.ID)
 
-	hash, errResolve := b.ResolveOperationWithMetadata(keyGitlabId, id)
-	if errResolve != nil && errResolve != cache.ErrNoMatchingOp {
+	id, errResolve := b.ResolveOperationWithMetadata(keyGitlabId, gitlabID)
+	if errResolve != cache.ErrNoMatchingOp {
 		return errResolve
 	}
 
@@ -154,7 +153,7 @@ func (gi *gitlabImporter) ensureNote(repo *cache.RepoCache, b *cache.BugCache, n
 			author,
 			note.CreatedAt.Unix(),
 			map[string]string{
-				keyGitlabId: id,
+				keyGitlabId: gitlabID,
 			},
 		)
 		return err
@@ -168,7 +167,7 @@ func (gi *gitlabImporter) ensureNote(repo *cache.RepoCache, b *cache.BugCache, n
 			author,
 			note.CreatedAt.Unix(),
 			map[string]string{
-				keyGitlabId: id,
+				keyGitlabId: gitlabID,
 			},
 		)
 		return err
@@ -185,10 +184,10 @@ func (gi *gitlabImporter) ensureNote(repo *cache.RepoCache, b *cache.BugCache, n
 			_, err = b.EditCommentRaw(
 				author,
 				note.UpdatedAt.Unix(),
-				git.Hash(firstComment.Id()),
+				firstComment.Id(),
 				issue.Description,
 				map[string]string{
-					keyGitlabId: id,
+					keyGitlabId: gitlabID,
 				},
 			)
 
@@ -211,7 +210,7 @@ func (gi *gitlabImporter) ensureNote(repo *cache.RepoCache, b *cache.BugCache, n
 				cleanText,
 				nil,
 				map[string]string{
-					keyGitlabId: id,
+					keyGitlabId: gitlabID,
 				},
 			)
 
@@ -221,7 +220,7 @@ func (gi *gitlabImporter) ensureNote(repo *cache.RepoCache, b *cache.BugCache, n
 		// if comment was already exported
 
 		// search for last comment update
-		comment, err := b.Snapshot().SearchComment(hash)
+		comment, err := b.Snapshot().SearchComment(id)
 		if err != nil {
 			return err
 		}
@@ -232,7 +231,7 @@ func (gi *gitlabImporter) ensureNote(repo *cache.RepoCache, b *cache.BugCache, n
 			_, err = b.EditCommentRaw(
 				author,
 				note.UpdatedAt.Unix(),
-				git.Hash(comment.Id()),
+				comment.Id(),
 				cleanText,
 				nil,
 			)
@@ -253,7 +252,7 @@ func (gi *gitlabImporter) ensureNote(repo *cache.RepoCache, b *cache.BugCache, n
 			note.CreatedAt.Unix(),
 			body,
 			map[string]string{
-				keyGitlabId: id,
+				keyGitlabId: gitlabID,
 			},
 		)
 

bug/snapshot.go 🔗

@@ -5,7 +5,6 @@ import (
 	"time"
 
 	"github.com/MichaelMure/git-bug/identity"
-	"github.com/MichaelMure/git-bug/util/git"
 )
 
 // Snapshot is a compiled form of the Bug data structure used for storage and merge
@@ -71,9 +70,9 @@ func (snap *Snapshot) SearchTimelineItem(ID string) (TimelineItem, error) {
 }
 
 // SearchComment will search for a comment matching the given hash
-func (snap *Snapshot) SearchComment(hash git.Hash) (*Comment, error) {
+func (snap *Snapshot) SearchComment(id string) (*Comment, error) {
 	for _, c := range snap.Comments {
-		if c.id == hash.String() {
+		if c.id == id {
 			return &c, nil
 		}
 	}

cache/bug_cache.go 🔗

@@ -44,7 +44,7 @@ func (c *BugCache) notifyUpdated() error {
 var ErrNoMatchingOp = fmt.Errorf("no matching operation found")
 
 type ErrMultipleMatchOp struct {
-	Matching []git.Hash
+	Matching []string
 }
 
 func (e ErrMultipleMatchOp) Error() string {
@@ -58,20 +58,16 @@ func (e ErrMultipleMatchOp) Error() string {
 }
 
 // ResolveOperationWithMetadata will find an operation that has the matching metadata
-func (c *BugCache) ResolveOperationWithMetadata(key string, value string) (git.Hash, error) {
+func (c *BugCache) ResolveOperationWithMetadata(key string, value string) (string, error) {
 	// preallocate but empty
-	matching := make([]git.Hash, 0, 5)
+	matching := make([]string, 0, 5)
 
 	it := bug.NewOperationIterator(c.bug)
 	for it.Next() {
 		op := it.Value()
 		opValue, ok := op.GetMetadata(key)
 		if ok && value == opValue {
-			h, err := op.Hash()
-			if err != nil {
-				return "", err
-			}
-			matching = append(matching, h)
+			matching = append(matching, op.ID())
 		}
 	}
 
@@ -232,7 +228,7 @@ func (c *BugCache) SetTitleRaw(author *IdentityCache, unixTime int64, title stri
 	return op, c.notifyUpdated()
 }
 
-func (c *BugCache) EditComment(target git.Hash, message string) (*bug.EditCommentOperation, error) {
+func (c *BugCache) EditComment(target string, message string) (*bug.EditCommentOperation, error) {
 	author, err := c.repoCache.GetUserIdentity()
 	if err != nil {
 		return nil, err
@@ -241,7 +237,7 @@ func (c *BugCache) EditComment(target git.Hash, message string) (*bug.EditCommen
 	return c.EditCommentRaw(author, time.Now().Unix(), target, message, nil)
 }
 
-func (c *BugCache) EditCommentRaw(author *IdentityCache, unixTime int64, target git.Hash, message string, metadata map[string]string) (*bug.EditCommentOperation, error) {
+func (c *BugCache) EditCommentRaw(author *IdentityCache, unixTime int64, target string, message string, metadata map[string]string) (*bug.EditCommentOperation, error) {
 	op, err := bug.EditComment(c.bug, author.Identity, unixTime, target, message)
 	if err != nil {
 		return nil, err
@@ -254,7 +250,7 @@ func (c *BugCache) EditCommentRaw(author *IdentityCache, unixTime int64, target
 	return op, c.notifyUpdated()
 }
 
-func (c *BugCache) SetMetadata(target git.Hash, newMetadata map[string]string) (*bug.SetMetadataOperation, error) {
+func (c *BugCache) SetMetadata(target string, newMetadata map[string]string) (*bug.SetMetadataOperation, error) {
 	author, err := c.repoCache.GetUserIdentity()
 	if err != nil {
 		return nil, err
@@ -263,7 +259,7 @@ func (c *BugCache) SetMetadata(target git.Hash, newMetadata map[string]string) (
 	return c.SetMetadataRaw(author, time.Now().Unix(), target, newMetadata)
 }
 
-func (c *BugCache) SetMetadataRaw(author *IdentityCache, unixTime int64, target git.Hash, newMetadata map[string]string) (*bug.SetMetadataOperation, error) {
+func (c *BugCache) SetMetadataRaw(author *IdentityCache, unixTime int64, target string, newMetadata map[string]string) (*bug.SetMetadataOperation, error) {
 	op, err := bug.SetMetadata(c.bug, author.Identity, unixTime, target, newMetadata)
 	if err != nil {
 		return nil, err

graphql/graph/gen_graph.go 🔗

@@ -71,7 +71,7 @@ type ComplexityRoot struct {
 		Author  func(childComplexity int) int
 		Date    func(childComplexity int) int
 		Files   func(childComplexity int) int
-		Hash    func(childComplexity int) int
+		ID      func(childComplexity int) int
 		Message func(childComplexity int) int
 	}
 
@@ -86,8 +86,8 @@ type ComplexityRoot struct {
 		CreatedAt      func(childComplexity int) int
 		Edited         func(childComplexity int) int
 		Files          func(childComplexity int) int
-		Hash           func(childComplexity int) int
 		History        func(childComplexity int) int
+		ID             func(childComplexity int) int
 		LastEdit       func(childComplexity int) int
 		Message        func(childComplexity int) int
 		MessageIsEmpty func(childComplexity int) int
@@ -177,7 +177,7 @@ type ComplexityRoot struct {
 		Author  func(childComplexity int) int
 		Date    func(childComplexity int) int
 		Files   func(childComplexity int) int
-		Hash    func(childComplexity int) int
+		ID      func(childComplexity int) int
 		Message func(childComplexity int) int
 		Title   func(childComplexity int) int
 	}
@@ -187,8 +187,8 @@ type ComplexityRoot struct {
 		CreatedAt      func(childComplexity int) int
 		Edited         func(childComplexity int) int
 		Files          func(childComplexity int) int
-		Hash           func(childComplexity int) int
 		History        func(childComplexity int) int
+		ID             func(childComplexity int) int
 		LastEdit       func(childComplexity int) int
 		Message        func(childComplexity int) int
 		MessageIsEmpty func(childComplexity int) int
@@ -198,7 +198,7 @@ type ComplexityRoot struct {
 		Author  func(childComplexity int) int
 		Date    func(childComplexity int) int
 		Files   func(childComplexity int) int
-		Hash    func(childComplexity int) int
+		ID      func(childComplexity int) int
 		Message func(childComplexity int) int
 		Target  func(childComplexity int) int
 	}
@@ -235,7 +235,7 @@ type ComplexityRoot struct {
 		Added   func(childComplexity int) int
 		Author  func(childComplexity int) int
 		Date    func(childComplexity int) int
-		Hash    func(childComplexity int) int
+		ID      func(childComplexity int) int
 		Removed func(childComplexity int) int
 	}
 
@@ -248,7 +248,7 @@ type ComplexityRoot struct {
 		Added   func(childComplexity int) int
 		Author  func(childComplexity int) int
 		Date    func(childComplexity int) int
-		Hash    func(childComplexity int) int
+		ID      func(childComplexity int) int
 		Removed func(childComplexity int) int
 	}
 
@@ -311,21 +311,21 @@ type ComplexityRoot struct {
 	SetStatusOperation struct {
 		Author func(childComplexity int) int
 		Date   func(childComplexity int) int
-		Hash   func(childComplexity int) int
+		ID     func(childComplexity int) int
 		Status func(childComplexity int) int
 	}
 
 	SetStatusTimelineItem struct {
 		Author func(childComplexity int) int
 		Date   func(childComplexity int) int
-		Hash   func(childComplexity int) int
+		ID     func(childComplexity int) int
 		Status func(childComplexity int) int
 	}
 
 	SetTitleOperation struct {
 		Author func(childComplexity int) int
 		Date   func(childComplexity int) int
-		Hash   func(childComplexity int) int
+		ID     func(childComplexity int) int
 		Title  func(childComplexity int) int
 		Was    func(childComplexity int) int
 	}
@@ -339,7 +339,7 @@ type ComplexityRoot struct {
 	SetTitleTimelineItem struct {
 		Author func(childComplexity int) int
 		Date   func(childComplexity int) int
-		Hash   func(childComplexity int) int
+		ID     func(childComplexity int) int
 		Title  func(childComplexity int) int
 		Was    func(childComplexity int) int
 	}
@@ -488,12 +488,12 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
 
 		return e.complexity.AddCommentOperation.Files(childComplexity), true
 
-	case "AddCommentOperation.hash":
-		if e.complexity.AddCommentOperation.Hash == nil {
+	case "AddCommentOperation.id":
+		if e.complexity.AddCommentOperation.ID == nil {
 			break
 		}
 
-		return e.complexity.AddCommentOperation.Hash(childComplexity), true
+		return e.complexity.AddCommentOperation.ID(childComplexity), true
 
 	case "AddCommentOperation.message":
 		if e.complexity.AddCommentOperation.Message == nil {
@@ -551,19 +551,19 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
 
 		return e.complexity.AddCommentTimelineItem.Files(childComplexity), true
 
-	case "AddCommentTimelineItem.hash":
-		if e.complexity.AddCommentTimelineItem.Hash == nil {
+	case "AddCommentTimelineItem.history":
+		if e.complexity.AddCommentTimelineItem.History == nil {
 			break
 		}
 
-		return e.complexity.AddCommentTimelineItem.Hash(childComplexity), true
+		return e.complexity.AddCommentTimelineItem.History(childComplexity), true
 
-	case "AddCommentTimelineItem.history":
-		if e.complexity.AddCommentTimelineItem.History == nil {
+	case "AddCommentTimelineItem.id":
+		if e.complexity.AddCommentTimelineItem.ID == nil {
 			break
 		}
 
-		return e.complexity.AddCommentTimelineItem.History(childComplexity), true
+		return e.complexity.AddCommentTimelineItem.ID(childComplexity), true
 
 	case "AddCommentTimelineItem.lastEdit":
 		if e.complexity.AddCommentTimelineItem.LastEdit == nil {
@@ -940,12 +940,12 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
 
 		return e.complexity.CreateOperation.Files(childComplexity), true
 
-	case "CreateOperation.hash":
-		if e.complexity.CreateOperation.Hash == nil {
+	case "CreateOperation.id":
+		if e.complexity.CreateOperation.ID == nil {
 			break
 		}
 
-		return e.complexity.CreateOperation.Hash(childComplexity), true
+		return e.complexity.CreateOperation.ID(childComplexity), true
 
 	case "CreateOperation.message":
 		if e.complexity.CreateOperation.Message == nil {
@@ -989,19 +989,19 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
 
 		return e.complexity.CreateTimelineItem.Files(childComplexity), true
 
-	case "CreateTimelineItem.hash":
-		if e.complexity.CreateTimelineItem.Hash == nil {
+	case "CreateTimelineItem.history":
+		if e.complexity.CreateTimelineItem.History == nil {
 			break
 		}
 
-		return e.complexity.CreateTimelineItem.Hash(childComplexity), true
+		return e.complexity.CreateTimelineItem.History(childComplexity), true
 
-	case "CreateTimelineItem.history":
-		if e.complexity.CreateTimelineItem.History == nil {
+	case "CreateTimelineItem.id":
+		if e.complexity.CreateTimelineItem.ID == nil {
 			break
 		}
 
-		return e.complexity.CreateTimelineItem.History(childComplexity), true
+		return e.complexity.CreateTimelineItem.ID(childComplexity), true
 
 	case "CreateTimelineItem.lastEdit":
 		if e.complexity.CreateTimelineItem.LastEdit == nil {
@@ -1045,12 +1045,12 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
 
 		return e.complexity.EditCommentOperation.Files(childComplexity), true
 
-	case "EditCommentOperation.hash":
-		if e.complexity.EditCommentOperation.Hash == nil {
+	case "EditCommentOperation.id":
+		if e.complexity.EditCommentOperation.ID == nil {
 			break
 		}
 
-		return e.complexity.EditCommentOperation.Hash(childComplexity), true
+		return e.complexity.EditCommentOperation.ID(childComplexity), true
 
 	case "EditCommentOperation.message":
 		if e.complexity.EditCommentOperation.Message == nil {
@@ -1199,12 +1199,12 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
 
 		return e.complexity.LabelChangeOperation.Date(childComplexity), true
 
-	case "LabelChangeOperation.hash":
-		if e.complexity.LabelChangeOperation.Hash == nil {
+	case "LabelChangeOperation.id":
+		if e.complexity.LabelChangeOperation.ID == nil {
 			break
 		}
 
-		return e.complexity.LabelChangeOperation.Hash(childComplexity), true
+		return e.complexity.LabelChangeOperation.ID(childComplexity), true
 
 	case "LabelChangeOperation.removed":
 		if e.complexity.LabelChangeOperation.Removed == nil {
@@ -1248,12 +1248,12 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
 
 		return e.complexity.LabelChangeTimelineItem.Date(childComplexity), true
 
-	case "LabelChangeTimelineItem.hash":
-		if e.complexity.LabelChangeTimelineItem.Hash == nil {
+	case "LabelChangeTimelineItem.id":
+		if e.complexity.LabelChangeTimelineItem.ID == nil {
 			break
 		}
 
-		return e.complexity.LabelChangeTimelineItem.Hash(childComplexity), true
+		return e.complexity.LabelChangeTimelineItem.ID(childComplexity), true
 
 	case "LabelChangeTimelineItem.removed":
 		if e.complexity.LabelChangeTimelineItem.Removed == nil {
@@ -1565,12 +1565,12 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
 
 		return e.complexity.SetStatusOperation.Date(childComplexity), true
 
-	case "SetStatusOperation.hash":
-		if e.complexity.SetStatusOperation.Hash == nil {
+	case "SetStatusOperation.id":
+		if e.complexity.SetStatusOperation.ID == nil {
 			break
 		}
 
-		return e.complexity.SetStatusOperation.Hash(childComplexity), true
+		return e.complexity.SetStatusOperation.ID(childComplexity), true
 
 	case "SetStatusOperation.status":
 		if e.complexity.SetStatusOperation.Status == nil {
@@ -1593,12 +1593,12 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
 
 		return e.complexity.SetStatusTimelineItem.Date(childComplexity), true
 
-	case "SetStatusTimelineItem.hash":
-		if e.complexity.SetStatusTimelineItem.Hash == nil {
+	case "SetStatusTimelineItem.id":
+		if e.complexity.SetStatusTimelineItem.ID == nil {
 			break
 		}
 
-		return e.complexity.SetStatusTimelineItem.Hash(childComplexity), true
+		return e.complexity.SetStatusTimelineItem.ID(childComplexity), true
 
 	case "SetStatusTimelineItem.status":
 		if e.complexity.SetStatusTimelineItem.Status == nil {
@@ -1621,12 +1621,12 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
 
 		return e.complexity.SetTitleOperation.Date(childComplexity), true
 
-	case "SetTitleOperation.hash":
-		if e.complexity.SetTitleOperation.Hash == nil {
+	case "SetTitleOperation.id":
+		if e.complexity.SetTitleOperation.ID == nil {
 			break
 		}
 
-		return e.complexity.SetTitleOperation.Hash(childComplexity), true
+		return e.complexity.SetTitleOperation.ID(childComplexity), true
 
 	case "SetTitleOperation.title":
 		if e.complexity.SetTitleOperation.Title == nil {
@@ -1677,12 +1677,12 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
 
 		return e.complexity.SetTitleTimelineItem.Date(childComplexity), true
 
-	case "SetTitleTimelineItem.hash":
-		if e.complexity.SetTitleTimelineItem.Hash == nil {
+	case "SetTitleTimelineItem.id":
+		if e.complexity.SetTitleTimelineItem.ID == nil {
 			break
 		}
 
-		return e.complexity.SetTitleTimelineItem.Hash(childComplexity), true
+		return e.complexity.SetTitleTimelineItem.ID(childComplexity), true
 
 	case "SetTitleTimelineItem.title":
 		if e.complexity.SetTitleTimelineItem.Title == nil {
@@ -2126,8 +2126,8 @@ type CommitAsNeededPayload {
 `},
 	&ast.Source{Name: "schema/operations.graphql", Input: `"""An operation applied to a bug."""
 interface Operation {
-    """The hash of the operation"""
-    hash: Hash!
+    """The identifier of the operation"""
+    id: String!
     """The operations author."""
     author: Identity!
     """The datetime when this operation was issued."""
@@ -2153,8 +2153,8 @@ type OperationEdge {
 # Operations
 
 type CreateOperation implements Operation & Authored {
-    """The hash of the operation"""
-    hash: Hash!
+    """The identifier of the operation"""
+    id: String!
     """The author of this object."""
     author: Identity!
     """The datetime when this operation was issued."""
@@ -2166,8 +2166,8 @@ type CreateOperation implements Operation & Authored {
 }
 
 type SetTitleOperation implements Operation & Authored {
-    """The hash of the operation"""
-    hash: Hash!
+    """The identifier of the operation"""
+    id: String!
     """The author of this object."""
     author: Identity!
     """The datetime when this operation was issued."""
@@ -2178,8 +2178,8 @@ type SetTitleOperation implements Operation & Authored {
 }
 
 type AddCommentOperation implements Operation & Authored {
-    """The hash of the operation"""
-    hash: Hash!
+    """The identifier of the operation"""
+    id: String!
     """The author of this object."""
     author: Identity!
     """The datetime when this operation was issued."""
@@ -2190,21 +2190,21 @@ type AddCommentOperation implements Operation & Authored {
 }
 
 type EditCommentOperation implements Operation & Authored {
-    """The hash of the operation"""
-    hash: Hash!
+    """The identifier of the operation"""
+    id: String!
     """The author of this object."""
     author: Identity!
     """The datetime when this operation was issued."""
     date: Time!
 
-    target: Hash!
+    target: String!
     message: String!
     files: [Hash!]!
 }
 
 type SetStatusOperation implements Operation & Authored {
-    """The hash of the operation"""
-    hash: Hash!
+    """The identifier of the operation"""
+    id: String!
     """The author of this object."""
     author: Identity!
     """The datetime when this operation was issued."""
@@ -2214,8 +2214,8 @@ type SetStatusOperation implements Operation & Authored {
 }
 
 type LabelChangeOperation implements Operation & Authored {
-    """The hash of the operation"""
-    hash: Hash!
+    """The identifier of the operation"""
+    id: String!
     """The author of this object."""
     author: Identity!
     """The datetime when this operation was issued."""
@@ -2291,8 +2291,8 @@ type Mutation {
 `},
 	&ast.Source{Name: "schema/timeline.graphql", Input: `"""An item in the timeline of events"""
 interface TimelineItem {
-    """The hash of the source operation"""
-    hash: Hash!
+    """The identifier of the source operation"""
+    id: String!
 }
 
 """CommentHistoryStep hold one version of a message in the history"""
@@ -2321,8 +2321,8 @@ type TimelineItemEdge {
 
 """CreateTimelineItem is a TimelineItem that represent the creation of a bug and its message edition history"""
 type CreateTimelineItem implements TimelineItem & Authored {
-    """The hash of the source operation"""
-    hash: Hash!
+    """The identifier of the source operation"""
+    id: String!
     author: Identity!
     message: String!
     messageIsEmpty: Boolean!
@@ -2335,8 +2335,8 @@ type CreateTimelineItem implements TimelineItem & Authored {
 
 """AddCommentTimelineItem is a TimelineItem that represent a Comment and its edition history"""
 type AddCommentTimelineItem implements TimelineItem & Authored {
-    """The hash of the source operation"""
-    hash: Hash!
+    """The identifier of the source operation"""
+    id: String!
     author: Identity!
     message: String!
     messageIsEmpty: Boolean!
@@ -2349,8 +2349,8 @@ type AddCommentTimelineItem implements TimelineItem & Authored {
 
 """LabelChangeTimelineItem is a TimelineItem that represent a change in the labels of a bug"""
 type LabelChangeTimelineItem implements TimelineItem & Authored {
-    """The hash of the source operation"""
-    hash: Hash!
+    """The identifier of the source operation"""
+    id: String!
     author: Identity!
     date: Time!
     added: [Label!]!
@@ -2359,8 +2359,8 @@ type LabelChangeTimelineItem implements TimelineItem & Authored {
 
 """SetStatusTimelineItem is a TimelineItem that represent a change in the status of a bug"""
 type SetStatusTimelineItem implements TimelineItem & Authored {
-    """The hash of the source operation"""
-    hash: Hash!
+    """The identifier of the source operation"""
+    id: String!
     author: Identity!
     date: Time!
     status: Status!
@@ -2368,8 +2368,8 @@ type SetStatusTimelineItem implements TimelineItem & Authored {
 
 """LabelChangeTimelineItem is a TimelineItem that represent a change in the title of a bug"""
 type SetTitleTimelineItem implements TimelineItem & Authored {
-    """The hash of the source operation"""
-    hash: Hash!
+    """The identifier of the source operation"""
+    id: String!
     author: Identity!
     date: Time!
     title: String!
@@ -2899,7 +2899,7 @@ func (ec *executionContext) field___Type_fields_args(ctx context.Context, rawArg
 
 // region    **************************** field.gotpl *****************************
 
-func (ec *executionContext) _AddCommentOperation_hash(ctx context.Context, field graphql.CollectedField, obj *bug.AddCommentOperation) (ret graphql.Marshaler) {
+func (ec *executionContext) _AddCommentOperation_id(ctx context.Context, field graphql.CollectedField, obj *bug.AddCommentOperation) (ret graphql.Marshaler) {
 	ctx = ec.Tracer.StartFieldExecution(ctx, field)
 	defer func() {
 		if r := recover(); r != nil {
@@ -2918,7 +2918,7 @@ func (ec *executionContext) _AddCommentOperation_hash(ctx context.Context, field
 	ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
 	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
 		ctx = rctx // use context from middleware stack in children
-		return obj.Hash()
+		return obj.ID(), nil
 	})
 	if err != nil {
 		ec.Error(ctx, err)
@@ -2930,10 +2930,10 @@ func (ec *executionContext) _AddCommentOperation_hash(ctx context.Context, field
 		}
 		return graphql.Null
 	}
-	res := resTmp.(git.Hash)
+	res := resTmp.(string)
 	rctx.Result = res
 	ctx = ec.Tracer.StartFieldChildExecution(ctx)
-	return ec.marshalNHash2githubᚗcomᚋMichaelMureᚋgitᚑbugᚋutilᚋgitᚐHash(ctx, field.Selections, res)
+	return ec.marshalNString2string(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _AddCommentOperation_author(ctx context.Context, field graphql.CollectedField, obj *bug.AddCommentOperation) (ret graphql.Marshaler) {
@@ -3192,7 +3192,7 @@ func (ec *executionContext) _AddCommentPayload_operation(ctx context.Context, fi
 	return ec.marshalNAddCommentOperation2ᚖgithubᚗcomᚋMichaelMureᚋgitᚑbugᚋbugᚐAddCommentOperation(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) _AddCommentTimelineItem_hash(ctx context.Context, field graphql.CollectedField, obj *bug.AddCommentTimelineItem) (ret graphql.Marshaler) {
+func (ec *executionContext) _AddCommentTimelineItem_id(ctx context.Context, field graphql.CollectedField, obj *bug.AddCommentTimelineItem) (ret graphql.Marshaler) {
 	ctx = ec.Tracer.StartFieldExecution(ctx, field)
 	defer func() {
 		if r := recover(); r != nil {
@@ -3211,7 +3211,7 @@ func (ec *executionContext) _AddCommentTimelineItem_hash(ctx context.Context, fi
 	ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
 	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
 		ctx = rctx // use context from middleware stack in children
-		return obj.Hash(), nil
+		return obj.ID(), nil
 	})
 	if err != nil {
 		ec.Error(ctx, err)
@@ -3223,10 +3223,10 @@ func (ec *executionContext) _AddCommentTimelineItem_hash(ctx context.Context, fi
 		}
 		return graphql.Null
 	}
-	res := resTmp.(git.Hash)
+	res := resTmp.(string)
 	rctx.Result = res
 	ctx = ec.Tracer.StartFieldChildExecution(ctx)
-	return ec.marshalNHash2githubᚗcomᚋMichaelMureᚋgitᚑbugᚋutilᚋgitᚐHash(ctx, field.Selections, res)
+	return ec.marshalNString2string(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _AddCommentTimelineItem_author(ctx context.Context, field graphql.CollectedField, obj *bug.AddCommentTimelineItem) (ret graphql.Marshaler) {
@@ -5176,7 +5176,7 @@ func (ec *executionContext) _CommitPayload_bug(ctx context.Context, field graphq
 	return ec.marshalNBug2ᚖgithubᚗcomᚋMichaelMureᚋgitᚑbugᚋbugᚐSnapshot(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) _CreateOperation_hash(ctx context.Context, field graphql.CollectedField, obj *bug.CreateOperation) (ret graphql.Marshaler) {
+func (ec *executionContext) _CreateOperation_id(ctx context.Context, field graphql.CollectedField, obj *bug.CreateOperation) (ret graphql.Marshaler) {
 	ctx = ec.Tracer.StartFieldExecution(ctx, field)
 	defer func() {
 		if r := recover(); r != nil {
@@ -5195,7 +5195,7 @@ func (ec *executionContext) _CreateOperation_hash(ctx context.Context, field gra
 	ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
 	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
 		ctx = rctx // use context from middleware stack in children
-		return obj.Hash()
+		return obj.ID(), nil
 	})
 	if err != nil {
 		ec.Error(ctx, err)
@@ -5207,10 +5207,10 @@ func (ec *executionContext) _CreateOperation_hash(ctx context.Context, field gra
 		}
 		return graphql.Null
 	}
-	res := resTmp.(git.Hash)
+	res := resTmp.(string)
 	rctx.Result = res
 	ctx = ec.Tracer.StartFieldChildExecution(ctx)
-	return ec.marshalNHash2githubᚗcomᚋMichaelMureᚋgitᚑbugᚋutilᚋgitᚐHash(ctx, field.Selections, res)
+	return ec.marshalNString2string(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _CreateOperation_author(ctx context.Context, field graphql.CollectedField, obj *bug.CreateOperation) (ret graphql.Marshaler) {
@@ -5398,7 +5398,7 @@ func (ec *executionContext) _CreateOperation_files(ctx context.Context, field gr
 	return ec.marshalNHash2ᚕgithubᚗcomᚋMichaelMureᚋgitᚑbugᚋutilᚋgitᚐHash(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) _CreateTimelineItem_hash(ctx context.Context, field graphql.CollectedField, obj *bug.CreateTimelineItem) (ret graphql.Marshaler) {
+func (ec *executionContext) _CreateTimelineItem_id(ctx context.Context, field graphql.CollectedField, obj *bug.CreateTimelineItem) (ret graphql.Marshaler) {
 	ctx = ec.Tracer.StartFieldExecution(ctx, field)
 	defer func() {
 		if r := recover(); r != nil {
@@ -5417,7 +5417,7 @@ func (ec *executionContext) _CreateTimelineItem_hash(ctx context.Context, field
 	ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
 	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
 		ctx = rctx // use context from middleware stack in children
-		return obj.Hash(), nil
+		return obj.ID(), nil
 	})
 	if err != nil {
 		ec.Error(ctx, err)
@@ -5429,10 +5429,10 @@ func (ec *executionContext) _CreateTimelineItem_hash(ctx context.Context, field
 		}
 		return graphql.Null
 	}
-	res := resTmp.(git.Hash)
+	res := resTmp.(string)
 	rctx.Result = res
 	ctx = ec.Tracer.StartFieldChildExecution(ctx)
-	return ec.marshalNHash2githubᚗcomᚋMichaelMureᚋgitᚑbugᚋutilᚋgitᚐHash(ctx, field.Selections, res)
+	return ec.marshalNString2string(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _CreateTimelineItem_author(ctx context.Context, field graphql.CollectedField, obj *bug.CreateTimelineItem) (ret graphql.Marshaler) {
@@ -5731,7 +5731,7 @@ func (ec *executionContext) _CreateTimelineItem_history(ctx context.Context, fie
 	return ec.marshalNCommentHistoryStep2ᚕgithubᚗcomᚋMichaelMureᚋgitᚑbugᚋbugᚐCommentHistoryStep(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) _EditCommentOperation_hash(ctx context.Context, field graphql.CollectedField, obj *bug.EditCommentOperation) (ret graphql.Marshaler) {
+func (ec *executionContext) _EditCommentOperation_id(ctx context.Context, field graphql.CollectedField, obj *bug.EditCommentOperation) (ret graphql.Marshaler) {
 	ctx = ec.Tracer.StartFieldExecution(ctx, field)
 	defer func() {
 		if r := recover(); r != nil {
@@ -5750,7 +5750,7 @@ func (ec *executionContext) _EditCommentOperation_hash(ctx context.Context, fiel
 	ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
 	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
 		ctx = rctx // use context from middleware stack in children
-		return obj.Hash()
+		return obj.ID(), nil
 	})
 	if err != nil {
 		ec.Error(ctx, err)
@@ -5762,10 +5762,10 @@ func (ec *executionContext) _EditCommentOperation_hash(ctx context.Context, fiel
 		}
 		return graphql.Null
 	}
-	res := resTmp.(git.Hash)
+	res := resTmp.(string)
 	rctx.Result = res
 	ctx = ec.Tracer.StartFieldChildExecution(ctx)
-	return ec.marshalNHash2githubᚗcomᚋMichaelMureᚋgitᚑbugᚋutilᚋgitᚐHash(ctx, field.Selections, res)
+	return ec.marshalNString2string(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _EditCommentOperation_author(ctx context.Context, field graphql.CollectedField, obj *bug.EditCommentOperation) (ret graphql.Marshaler) {
@@ -5873,10 +5873,10 @@ func (ec *executionContext) _EditCommentOperation_target(ctx context.Context, fi
 		}
 		return graphql.Null
 	}
-	res := resTmp.(git.Hash)
+	res := resTmp.(string)
 	rctx.Result = res
 	ctx = ec.Tracer.StartFieldChildExecution(ctx)
-	return ec.marshalNHash2githubᚗcomᚋMichaelMureᚋgitᚑbugᚋutilᚋgitᚐHash(ctx, field.Selections, res)
+	return ec.marshalNString2string(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _EditCommentOperation_message(ctx context.Context, field graphql.CollectedField, obj *bug.EditCommentOperation) (ret graphql.Marshaler) {
@@ -6533,7 +6533,7 @@ func (ec *executionContext) _Label_color(ctx context.Context, field graphql.Coll
 	return ec.marshalNColor2ᚖimageᚋcolorᚐRGBA(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) _LabelChangeOperation_hash(ctx context.Context, field graphql.CollectedField, obj *bug.LabelChangeOperation) (ret graphql.Marshaler) {
+func (ec *executionContext) _LabelChangeOperation_id(ctx context.Context, field graphql.CollectedField, obj *bug.LabelChangeOperation) (ret graphql.Marshaler) {
 	ctx = ec.Tracer.StartFieldExecution(ctx, field)
 	defer func() {
 		if r := recover(); r != nil {
@@ -6552,7 +6552,7 @@ func (ec *executionContext) _LabelChangeOperation_hash(ctx context.Context, fiel
 	ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
 	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
 		ctx = rctx // use context from middleware stack in children
-		return obj.Hash()
+		return obj.ID(), nil
 	})
 	if err != nil {
 		ec.Error(ctx, err)
@@ -6564,10 +6564,10 @@ func (ec *executionContext) _LabelChangeOperation_hash(ctx context.Context, fiel
 		}
 		return graphql.Null
 	}
-	res := resTmp.(git.Hash)
+	res := resTmp.(string)
 	rctx.Result = res
 	ctx = ec.Tracer.StartFieldChildExecution(ctx)
-	return ec.marshalNHash2githubᚗcomᚋMichaelMureᚋgitᚑbugᚋutilᚋgitᚐHash(ctx, field.Selections, res)
+	return ec.marshalNString2string(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _LabelChangeOperation_author(ctx context.Context, field graphql.CollectedField, obj *bug.LabelChangeOperation) (ret graphql.Marshaler) {
@@ -6792,7 +6792,7 @@ func (ec *executionContext) _LabelChangeResult_status(ctx context.Context, field
 	return ec.marshalNLabelChangeStatus2githubᚗcomᚋMichaelMureᚋgitᚑbugᚋgraphqlᚋmodelsᚐLabelChangeStatus(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) _LabelChangeTimelineItem_hash(ctx context.Context, field graphql.CollectedField, obj *bug.LabelChangeTimelineItem) (ret graphql.Marshaler) {
+func (ec *executionContext) _LabelChangeTimelineItem_id(ctx context.Context, field graphql.CollectedField, obj *bug.LabelChangeTimelineItem) (ret graphql.Marshaler) {
 	ctx = ec.Tracer.StartFieldExecution(ctx, field)
 	defer func() {
 		if r := recover(); r != nil {
@@ -6811,7 +6811,7 @@ func (ec *executionContext) _LabelChangeTimelineItem_hash(ctx context.Context, f
 	ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
 	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
 		ctx = rctx // use context from middleware stack in children
-		return obj.Hash(), nil
+		return obj.ID(), nil
 	})
 	if err != nil {
 		ec.Error(ctx, err)
@@ -6823,10 +6823,10 @@ func (ec *executionContext) _LabelChangeTimelineItem_hash(ctx context.Context, f
 		}
 		return graphql.Null
 	}
-	res := resTmp.(git.Hash)
+	res := resTmp.(string)
 	rctx.Result = res
 	ctx = ec.Tracer.StartFieldChildExecution(ctx)
-	return ec.marshalNHash2githubᚗcomᚋMichaelMureᚋgitᚑbugᚋutilᚋgitᚐHash(ctx, field.Selections, res)
+	return ec.marshalNString2string(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _LabelChangeTimelineItem_author(ctx context.Context, field graphql.CollectedField, obj *bug.LabelChangeTimelineItem) (ret graphql.Marshaler) {
@@ -8306,7 +8306,7 @@ func (ec *executionContext) _Repository_validLabels(ctx context.Context, field g
 	return ec.marshalNLabel2ᚕgithubᚗcomᚋMichaelMureᚋgitᚑbugᚋbugᚐLabel(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) _SetStatusOperation_hash(ctx context.Context, field graphql.CollectedField, obj *bug.SetStatusOperation) (ret graphql.Marshaler) {
+func (ec *executionContext) _SetStatusOperation_id(ctx context.Context, field graphql.CollectedField, obj *bug.SetStatusOperation) (ret graphql.Marshaler) {
 	ctx = ec.Tracer.StartFieldExecution(ctx, field)
 	defer func() {
 		if r := recover(); r != nil {
@@ -8325,7 +8325,7 @@ func (ec *executionContext) _SetStatusOperation_hash(ctx context.Context, field
 	ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
 	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
 		ctx = rctx // use context from middleware stack in children
-		return obj.Hash()
+		return obj.ID(), nil
 	})
 	if err != nil {
 		ec.Error(ctx, err)
@@ -8337,10 +8337,10 @@ func (ec *executionContext) _SetStatusOperation_hash(ctx context.Context, field
 		}
 		return graphql.Null
 	}
-	res := resTmp.(git.Hash)
+	res := resTmp.(string)
 	rctx.Result = res
 	ctx = ec.Tracer.StartFieldChildExecution(ctx)
-	return ec.marshalNHash2githubᚗcomᚋMichaelMureᚋgitᚑbugᚋutilᚋgitᚐHash(ctx, field.Selections, res)
+	return ec.marshalNString2string(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _SetStatusOperation_author(ctx context.Context, field graphql.CollectedField, obj *bug.SetStatusOperation) (ret graphql.Marshaler) {
@@ -8454,7 +8454,7 @@ func (ec *executionContext) _SetStatusOperation_status(ctx context.Context, fiel
 	return ec.marshalNStatus2githubᚗcomᚋMichaelMureᚋgitᚑbugᚋgraphqlᚋmodelsᚐStatus(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) _SetStatusTimelineItem_hash(ctx context.Context, field graphql.CollectedField, obj *bug.SetStatusTimelineItem) (ret graphql.Marshaler) {
+func (ec *executionContext) _SetStatusTimelineItem_id(ctx context.Context, field graphql.CollectedField, obj *bug.SetStatusTimelineItem) (ret graphql.Marshaler) {
 	ctx = ec.Tracer.StartFieldExecution(ctx, field)
 	defer func() {
 		if r := recover(); r != nil {
@@ -8473,7 +8473,7 @@ func (ec *executionContext) _SetStatusTimelineItem_hash(ctx context.Context, fie
 	ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
 	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
 		ctx = rctx // use context from middleware stack in children
-		return obj.Hash(), nil
+		return obj.ID(), nil
 	})
 	if err != nil {
 		ec.Error(ctx, err)
@@ -8485,10 +8485,10 @@ func (ec *executionContext) _SetStatusTimelineItem_hash(ctx context.Context, fie
 		}
 		return graphql.Null
 	}
-	res := resTmp.(git.Hash)
+	res := resTmp.(string)
 	rctx.Result = res
 	ctx = ec.Tracer.StartFieldChildExecution(ctx)
-	return ec.marshalNHash2githubᚗcomᚋMichaelMureᚋgitᚑbugᚋutilᚋgitᚐHash(ctx, field.Selections, res)
+	return ec.marshalNString2string(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _SetStatusTimelineItem_author(ctx context.Context, field graphql.CollectedField, obj *bug.SetStatusTimelineItem) (ret graphql.Marshaler) {
@@ -8602,7 +8602,7 @@ func (ec *executionContext) _SetStatusTimelineItem_status(ctx context.Context, f
 	return ec.marshalNStatus2githubᚗcomᚋMichaelMureᚋgitᚑbugᚋgraphqlᚋmodelsᚐStatus(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) _SetTitleOperation_hash(ctx context.Context, field graphql.CollectedField, obj *bug.SetTitleOperation) (ret graphql.Marshaler) {
+func (ec *executionContext) _SetTitleOperation_id(ctx context.Context, field graphql.CollectedField, obj *bug.SetTitleOperation) (ret graphql.Marshaler) {
 	ctx = ec.Tracer.StartFieldExecution(ctx, field)
 	defer func() {
 		if r := recover(); r != nil {
@@ -8621,7 +8621,7 @@ func (ec *executionContext) _SetTitleOperation_hash(ctx context.Context, field g
 	ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
 	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
 		ctx = rctx // use context from middleware stack in children
-		return obj.Hash()
+		return obj.ID(), nil
 	})
 	if err != nil {
 		ec.Error(ctx, err)
@@ -8633,10 +8633,10 @@ func (ec *executionContext) _SetTitleOperation_hash(ctx context.Context, field g
 		}
 		return graphql.Null
 	}
-	res := resTmp.(git.Hash)
+	res := resTmp.(string)
 	rctx.Result = res
 	ctx = ec.Tracer.StartFieldChildExecution(ctx)
-	return ec.marshalNHash2githubᚗcomᚋMichaelMureᚋgitᚑbugᚋutilᚋgitᚐHash(ctx, field.Selections, res)
+	return ec.marshalNString2string(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _SetTitleOperation_author(ctx context.Context, field graphql.CollectedField, obj *bug.SetTitleOperation) (ret graphql.Marshaler) {
@@ -8895,7 +8895,7 @@ func (ec *executionContext) _SetTitlePayload_operation(ctx context.Context, fiel
 	return ec.marshalNSetTitleOperation2ᚖgithubᚗcomᚋMichaelMureᚋgitᚑbugᚋbugᚐSetTitleOperation(ctx, field.Selections, res)
 }
 
-func (ec *executionContext) _SetTitleTimelineItem_hash(ctx context.Context, field graphql.CollectedField, obj *bug.SetTitleTimelineItem) (ret graphql.Marshaler) {
+func (ec *executionContext) _SetTitleTimelineItem_id(ctx context.Context, field graphql.CollectedField, obj *bug.SetTitleTimelineItem) (ret graphql.Marshaler) {
 	ctx = ec.Tracer.StartFieldExecution(ctx, field)
 	defer func() {
 		if r := recover(); r != nil {
@@ -8914,7 +8914,7 @@ func (ec *executionContext) _SetTitleTimelineItem_hash(ctx context.Context, fiel
 	ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
 	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
 		ctx = rctx // use context from middleware stack in children
-		return obj.Hash(), nil
+		return obj.ID(), nil
 	})
 	if err != nil {
 		ec.Error(ctx, err)
@@ -8926,10 +8926,10 @@ func (ec *executionContext) _SetTitleTimelineItem_hash(ctx context.Context, fiel
 		}
 		return graphql.Null
 	}
-	res := resTmp.(git.Hash)
+	res := resTmp.(string)
 	rctx.Result = res
 	ctx = ec.Tracer.StartFieldChildExecution(ctx)
-	return ec.marshalNHash2githubᚗcomᚋMichaelMureᚋgitᚑbugᚋutilᚋgitᚐHash(ctx, field.Selections, res)
+	return ec.marshalNString2string(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _SetTitleTimelineItem_author(ctx context.Context, field graphql.CollectedField, obj *bug.SetTitleTimelineItem) (ret graphql.Marshaler) {
@@ -10837,8 +10837,8 @@ func (ec *executionContext) _AddCommentOperation(ctx context.Context, sel ast.Se
 		switch field.Name {
 		case "__typename":
 			out.Values[i] = graphql.MarshalString("AddCommentOperation")
-		case "hash":
-			out.Values[i] = ec._AddCommentOperation_hash(ctx, field, obj)
+		case "id":
+			out.Values[i] = ec._AddCommentOperation_id(ctx, field, obj)
 			if out.Values[i] == graphql.Null {
 				atomic.AddUint32(&invalids, 1)
 			}
@@ -10927,8 +10927,8 @@ func (ec *executionContext) _AddCommentTimelineItem(ctx context.Context, sel ast
 		switch field.Name {
 		case "__typename":
 			out.Values[i] = graphql.MarshalString("AddCommentTimelineItem")
-		case "hash":
-			out.Values[i] = ec._AddCommentTimelineItem_hash(ctx, field, obj)
+		case "id":
+			out.Values[i] = ec._AddCommentTimelineItem_id(ctx, field, obj)
 			if out.Values[i] == graphql.Null {
 				atomic.AddUint32(&invalids, 1)
 			}
@@ -11583,8 +11583,8 @@ func (ec *executionContext) _CreateOperation(ctx context.Context, sel ast.Select
 		switch field.Name {
 		case "__typename":
 			out.Values[i] = graphql.MarshalString("CreateOperation")
-		case "hash":
-			out.Values[i] = ec._CreateOperation_hash(ctx, field, obj)
+		case "id":
+			out.Values[i] = ec._CreateOperation_id(ctx, field, obj)
 			if out.Values[i] == graphql.Null {
 				atomic.AddUint32(&invalids, 1)
 			}
@@ -11644,8 +11644,8 @@ func (ec *executionContext) _CreateTimelineItem(ctx context.Context, sel ast.Sel
 		switch field.Name {
 		case "__typename":
 			out.Values[i] = graphql.MarshalString("CreateTimelineItem")
-		case "hash":
-			out.Values[i] = ec._CreateTimelineItem_hash(ctx, field, obj)
+		case "id":
+			out.Values[i] = ec._CreateTimelineItem_id(ctx, field, obj)
 			if out.Values[i] == graphql.Null {
 				atomic.AddUint32(&invalids, 1)
 			}
@@ -11729,8 +11729,8 @@ func (ec *executionContext) _EditCommentOperation(ctx context.Context, sel ast.S
 		switch field.Name {
 		case "__typename":
 			out.Values[i] = graphql.MarshalString("EditCommentOperation")
-		case "hash":
-			out.Values[i] = ec._EditCommentOperation_hash(ctx, field, obj)
+		case "id":
+			out.Values[i] = ec._EditCommentOperation_id(ctx, field, obj)
 			if out.Values[i] == graphql.Null {
 				atomic.AddUint32(&invalids, 1)
 			}
@@ -12036,8 +12036,8 @@ func (ec *executionContext) _LabelChangeOperation(ctx context.Context, sel ast.S
 		switch field.Name {
 		case "__typename":
 			out.Values[i] = graphql.MarshalString("LabelChangeOperation")
-		case "hash":
-			out.Values[i] = ec._LabelChangeOperation_hash(ctx, field, obj)
+		case "id":
+			out.Values[i] = ec._LabelChangeOperation_id(ctx, field, obj)
 			if out.Values[i] == graphql.Null {
 				atomic.AddUint32(&invalids, 1)
 			}
@@ -12133,8 +12133,8 @@ func (ec *executionContext) _LabelChangeTimelineItem(ctx context.Context, sel as
 		switch field.Name {
 		case "__typename":
 			out.Values[i] = graphql.MarshalString("LabelChangeTimelineItem")
-		case "hash":
-			out.Values[i] = ec._LabelChangeTimelineItem_hash(ctx, field, obj)
+		case "id":
+			out.Values[i] = ec._LabelChangeTimelineItem_id(ctx, field, obj)
 			if out.Values[i] == graphql.Null {
 				atomic.AddUint32(&invalids, 1)
 			}
@@ -12588,8 +12588,8 @@ func (ec *executionContext) _SetStatusOperation(ctx context.Context, sel ast.Sel
 		switch field.Name {
 		case "__typename":
 			out.Values[i] = graphql.MarshalString("SetStatusOperation")
-		case "hash":
-			out.Values[i] = ec._SetStatusOperation_hash(ctx, field, obj)
+		case "id":
+			out.Values[i] = ec._SetStatusOperation_id(ctx, field, obj)
 			if out.Values[i] == graphql.Null {
 				atomic.AddUint32(&invalids, 1)
 			}
@@ -12648,8 +12648,8 @@ func (ec *executionContext) _SetStatusTimelineItem(ctx context.Context, sel ast.
 		switch field.Name {
 		case "__typename":
 			out.Values[i] = graphql.MarshalString("SetStatusTimelineItem")
-		case "hash":
-			out.Values[i] = ec._SetStatusTimelineItem_hash(ctx, field, obj)
+		case "id":
+			out.Values[i] = ec._SetStatusTimelineItem_id(ctx, field, obj)
 			if out.Values[i] == graphql.Null {
 				atomic.AddUint32(&invalids, 1)
 			}
@@ -12708,8 +12708,8 @@ func (ec *executionContext) _SetTitleOperation(ctx context.Context, sel ast.Sele
 		switch field.Name {
 		case "__typename":
 			out.Values[i] = graphql.MarshalString("SetTitleOperation")
-		case "hash":
-			out.Values[i] = ec._SetTitleOperation_hash(ctx, field, obj)
+		case "id":
+			out.Values[i] = ec._SetTitleOperation_id(ctx, field, obj)
 			if out.Values[i] == graphql.Null {
 				atomic.AddUint32(&invalids, 1)
 			}
@@ -12798,8 +12798,8 @@ func (ec *executionContext) _SetTitleTimelineItem(ctx context.Context, sel ast.S
 		switch field.Name {
 		case "__typename":
 			out.Values[i] = graphql.MarshalString("SetTitleTimelineItem")
-		case "hash":
-			out.Values[i] = ec._SetTitleTimelineItem_hash(ctx, field, obj)
+		case "id":
+			out.Values[i] = ec._SetTitleTimelineItem_id(ctx, field, obj)
 			if out.Values[i] == graphql.Null {
 				atomic.AddUint32(&invalids, 1)
 			}

graphql/schema/operations.graphql 🔗

@@ -1,7 +1,7 @@
 """An operation applied to a bug."""
 interface Operation {
-    """The hash of the operation"""
-    hash: Hash!
+    """The identifier of the operation"""
+    id: String!
     """The operations author."""
     author: Identity!
     """The datetime when this operation was issued."""
@@ -27,8 +27,8 @@ type OperationEdge {
 # Operations
 
 type CreateOperation implements Operation & Authored {
-    """The hash of the operation"""
-    hash: Hash!
+    """The identifier of the operation"""
+    id: String!
     """The author of this object."""
     author: Identity!
     """The datetime when this operation was issued."""
@@ -40,8 +40,8 @@ type CreateOperation implements Operation & Authored {
 }
 
 type SetTitleOperation implements Operation & Authored {
-    """The hash of the operation"""
-    hash: Hash!
+    """The identifier of the operation"""
+    id: String!
     """The author of this object."""
     author: Identity!
     """The datetime when this operation was issued."""
@@ -52,8 +52,8 @@ type SetTitleOperation implements Operation & Authored {
 }
 
 type AddCommentOperation implements Operation & Authored {
-    """The hash of the operation"""
-    hash: Hash!
+    """The identifier of the operation"""
+    id: String!
     """The author of this object."""
     author: Identity!
     """The datetime when this operation was issued."""
@@ -64,21 +64,21 @@ type AddCommentOperation implements Operation & Authored {
 }
 
 type EditCommentOperation implements Operation & Authored {
-    """The hash of the operation"""
-    hash: Hash!
+    """The identifier of the operation"""
+    id: String!
     """The author of this object."""
     author: Identity!
     """The datetime when this operation was issued."""
     date: Time!
 
-    target: Hash!
+    target: String!
     message: String!
     files: [Hash!]!
 }
 
 type SetStatusOperation implements Operation & Authored {
-    """The hash of the operation"""
-    hash: Hash!
+    """The identifier of the operation"""
+    id: String!
     """The author of this object."""
     author: Identity!
     """The datetime when this operation was issued."""
@@ -88,8 +88,8 @@ type SetStatusOperation implements Operation & Authored {
 }
 
 type LabelChangeOperation implements Operation & Authored {
-    """The hash of the operation"""
-    hash: Hash!
+    """The identifier of the operation"""
+    id: String!
     """The author of this object."""
     author: Identity!
     """The datetime when this operation was issued."""

graphql/schema/timeline.graphql 🔗

@@ -1,7 +1,7 @@
 """An item in the timeline of events"""
 interface TimelineItem {
-    """The hash of the source operation"""
-    hash: Hash!
+    """The identifier of the source operation"""
+    id: String!
 }
 
 """CommentHistoryStep hold one version of a message in the history"""
@@ -30,8 +30,8 @@ type TimelineItemEdge {
 
 """CreateTimelineItem is a TimelineItem that represent the creation of a bug and its message edition history"""
 type CreateTimelineItem implements TimelineItem & Authored {
-    """The hash of the source operation"""
-    hash: Hash!
+    """The identifier of the source operation"""
+    id: String!
     author: Identity!
     message: String!
     messageIsEmpty: Boolean!
@@ -44,8 +44,8 @@ type CreateTimelineItem implements TimelineItem & Authored {
 
 """AddCommentTimelineItem is a TimelineItem that represent a Comment and its edition history"""
 type AddCommentTimelineItem implements TimelineItem & Authored {
-    """The hash of the source operation"""
-    hash: Hash!
+    """The identifier of the source operation"""
+    id: String!
     author: Identity!
     message: String!
     messageIsEmpty: Boolean!
@@ -58,8 +58,8 @@ type AddCommentTimelineItem implements TimelineItem & Authored {
 
 """LabelChangeTimelineItem is a TimelineItem that represent a change in the labels of a bug"""
 type LabelChangeTimelineItem implements TimelineItem & Authored {
-    """The hash of the source operation"""
-    hash: Hash!
+    """The identifier of the source operation"""
+    id: String!
     author: Identity!
     date: Time!
     added: [Label!]!
@@ -68,8 +68,8 @@ type LabelChangeTimelineItem implements TimelineItem & Authored {
 
 """SetStatusTimelineItem is a TimelineItem that represent a change in the status of a bug"""
 type SetStatusTimelineItem implements TimelineItem & Authored {
-    """The hash of the source operation"""
-    hash: Hash!
+    """The identifier of the source operation"""
+    id: String!
     author: Identity!
     date: Time!
     status: Status!
@@ -77,8 +77,8 @@ type SetStatusTimelineItem implements TimelineItem & Authored {
 
 """LabelChangeTimelineItem is a TimelineItem that represent a change in the title of a bug"""
 type SetTitleTimelineItem implements TimelineItem & Authored {
-    """The hash of the source operation"""
-    hash: Hash!
+    """The identifier of the source operation"""
+    id: String!
     author: Identity!
     date: Time!
     title: String!

termui/show_bug.go 🔗

@@ -8,7 +8,6 @@ import (
 	"github.com/MichaelMure/git-bug/bug"
 	"github.com/MichaelMure/git-bug/cache"
 	"github.com/MichaelMure/git-bug/util/colors"
-	"github.com/MichaelMure/git-bug/util/git"
 	"github.com/MichaelMure/git-bug/util/text"
 	"github.com/MichaelMure/gocui"
 )
@@ -232,7 +231,7 @@ func (sb *showBug) renderMain(g *gocui.Gui, mainView *gocui.View) error {
 	y0 += lines + 1
 
 	for _, op := range snap.Timeline {
-		viewName := op.Hash().String()
+		viewName := op.ID()
 
 		// TODO: me might skip the rendering of blocks that are outside of the view
 		// but to do that we need to rework how sb.mainSelectableView is maintained
@@ -643,7 +642,7 @@ func (sb *showBug) edit(g *gocui.Gui, v *gocui.View) error {
 		return nil
 	}
 
-	op, err := snap.SearchTimelineItem(git.Hash(sb.selected))
+	op, err := snap.SearchTimelineItem(sb.selected)
 	if err != nil {
 		return err
 	}
@@ -651,10 +650,10 @@ func (sb *showBug) edit(g *gocui.Gui, v *gocui.View) error {
 	switch op.(type) {
 	case *bug.AddCommentTimelineItem:
 		message := op.(*bug.AddCommentTimelineItem).Message
-		return editCommentWithEditor(sb.bug, op.Hash(), message)
+		return editCommentWithEditor(sb.bug, op.ID(), message)
 	case *bug.CreateTimelineItem:
 		preMessage := op.(*bug.CreateTimelineItem).Message
-		return editCommentWithEditor(sb.bug, op.Hash(), preMessage)
+		return editCommentWithEditor(sb.bug, op.ID(), preMessage)
 	case *bug.LabelChangeTimelineItem:
 		return sb.editLabels(g, snap)
 	}

termui/termui.go 🔗

@@ -2,11 +2,11 @@
 package termui
 
 import (
-	"github.com/MichaelMure/git-bug/cache"
-	"github.com/MichaelMure/git-bug/input"
-	"github.com/MichaelMure/git-bug/util/git"
 	"github.com/MichaelMure/gocui"
 	"github.com/pkg/errors"
+
+	"github.com/MichaelMure/git-bug/cache"
+	"github.com/MichaelMure/git-bug/input"
 )
 
 var errTerminateMainloop = errors.New("terminate gocui mainloop")
@@ -237,7 +237,7 @@ func addCommentWithEditor(bug *cache.BugCache) error {
 	return errTerminateMainloop
 }
 
-func editCommentWithEditor(bug *cache.BugCache, target git.Hash, preMessage string) error {
+func editCommentWithEditor(bug *cache.BugCache, target string, preMessage string) error {
 	// This is somewhat hacky.
 	// As there is no way to pause gocui, run the editor and restart gocui,
 	// we have to stop it entirely and start a new one later.