From 4c431045378c538f61ea94b55c41451948979abb Mon Sep 17 00:00:00 2001 From: GDS K S Date: Sat, 11 Apr 2026 22:46:44 -0500 Subject: [PATCH 1/2] Fix empty tree hash for SHA-256 repos --- pkg/commands/models/commit.go | 14 ++++++++++++-- pkg/gui/presentation/graph/graph.go | 6 +++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/pkg/commands/models/commit.go b/pkg/commands/models/commit.go index 137528ee6..77ad21b4a 100644 --- a/pkg/commands/models/commit.go +++ b/pkg/commands/models/commit.go @@ -8,8 +8,9 @@ import ( "github.com/stefanhaller/git-todo-parser/todo" ) -// Special commit hash for empty tree object +// Empty tree object hashes for SHA-1 and SHA-256 repos. const EmptyTreeCommitHash = "4b825dc642cb6eb9a060e54bf8d69288fbee4904" +const EmptyTreeCommitHashSHA256 = "6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321" type CommitStatus uint8 @@ -122,11 +123,20 @@ func (c *Commit) ShortRefName() string { func (c *Commit) ParentRefName() string { if c.IsFirstCommit() { - return EmptyTreeCommitHash + return c.emptyTreeHash() } return c.RefName() + "^" } +// emptyTreeHash returns the empty tree object hash matching this repo's +// object format. SHA-256 repos produce 64-char hashes; SHA-1 repos 40-char. +func (c *Commit) emptyTreeHash() string { + if len(c.Hash()) > 40 { + return EmptyTreeCommitHashSHA256 + } + return EmptyTreeCommitHash +} + func (c *Commit) Parents() []string { return lo.Map(c.parents, func(s *string, _ int) string { return *s }) } diff --git a/pkg/gui/presentation/graph/graph.go b/pkg/gui/presentation/graph/graph.go index 1639a62e6..8c6a96b5e 100644 --- a/pkg/gui/presentation/graph/graph.go +++ b/pkg/gui/presentation/graph/graph.go @@ -142,7 +142,11 @@ func getNextPipes(prevPipes []Pipe, commit *models.Commit, getStyle func(c *mode var toHash *string if commit.IsFirstCommit() { - toHash = &EmptyTreeCommitHash + emptyHash := EmptyTreeCommitHash + if len(commit.Hash()) > 40 { + emptyHash = models.EmptyTreeCommitHashSHA256 + } + toHash = &emptyHash } else { toHash = commit.ParentPtrs()[0] } From f32c86a7f824ed6651b093eeee575f1314da8edc Mon Sep 17 00:00:00 2001 From: GDS K S Date: Sat, 11 Apr 2026 22:56:57 -0500 Subject: [PATCH 2/2] Use exact length matching, add centralized helper, add SHA-256 test --- pkg/commands/models/commit.go | 15 +++++++++++++-- pkg/gui/presentation/graph/graph.go | 15 ++++++++------- pkg/gui/presentation/graph/graph_test.go | 13 +++++++++++++ 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/pkg/commands/models/commit.go b/pkg/commands/models/commit.go index 77ad21b4a..41d19bf37 100644 --- a/pkg/commands/models/commit.go +++ b/pkg/commands/models/commit.go @@ -12,6 +12,15 @@ import ( const EmptyTreeCommitHash = "4b825dc642cb6eb9a060e54bf8d69288fbee4904" const EmptyTreeCommitHashSHA256 = "6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321" +// EmptyTreeHashForFormat returns the empty tree hash for the given object +// format ("sha1" or "sha256"). Falls back to SHA-1 for unknown formats. +func EmptyTreeHashForFormat(objectFormat string) string { + if objectFormat == "sha256" { + return EmptyTreeCommitHashSHA256 + } + return EmptyTreeCommitHash +} + type CommitStatus uint8 const ( @@ -129,9 +138,11 @@ func (c *Commit) ParentRefName() string { } // emptyTreeHash returns the empty tree object hash matching this repo's -// object format. SHA-256 repos produce 64-char hashes; SHA-1 repos 40-char. +// object format. This is only called when IsFirstCommit() is true, so the +// commit comes from git log with a full-length hash (40 for SHA-1, 64 for +// SHA-256). func (c *Commit) emptyTreeHash() string { - if len(c.Hash()) > 40 { + if len(c.Hash()) == len(EmptyTreeCommitHashSHA256) { return EmptyTreeCommitHashSHA256 } return EmptyTreeCommitHash diff --git a/pkg/gui/presentation/graph/graph.go b/pkg/gui/presentation/graph/graph.go index 8c6a96b5e..30695c97f 100644 --- a/pkg/gui/presentation/graph/graph.go +++ b/pkg/gui/presentation/graph/graph.go @@ -32,9 +32,10 @@ type Pipe struct { } var ( - highlightStyle = style.FgLightWhite.SetBold() - EmptyTreeCommitHash = models.EmptyTreeCommitHash - StartCommitHash = "START" + highlightStyle = style.FgLightWhite.SetBold() + EmptyTreeCommitHash = models.EmptyTreeCommitHash + EmptyTreeCommitHashSHA256 = models.EmptyTreeCommitHashSHA256 + StartCommitHash = "START" ) func (self Pipe) left() int16 { @@ -142,11 +143,11 @@ func getNextPipes(prevPipes []Pipe, commit *models.Commit, getStyle func(c *mode var toHash *string if commit.IsFirstCommit() { - emptyHash := EmptyTreeCommitHash - if len(commit.Hash()) > 40 { - emptyHash = models.EmptyTreeCommitHashSHA256 + if len(commit.Hash()) == len(EmptyTreeCommitHashSHA256) { + toHash = &EmptyTreeCommitHashSHA256 + } else { + toHash = &EmptyTreeCommitHash } - toHash = &emptyHash } else { toHash = commit.ParentPtrs()[0] } diff --git a/pkg/gui/presentation/graph/graph_test.go b/pkg/gui/presentation/graph/graph_test.go index a756f8aa4..0dad25ab0 100644 --- a/pkg/gui/presentation/graph/graph_test.go +++ b/pkg/gui/presentation/graph/graph_test.go @@ -531,6 +531,19 @@ func TestGetNextPipes(t *testing.T) { {fromPos: 1, toPos: 1, fromHash: pool("root"), toHash: pool(models.EmptyTreeCommitHash), kind: STARTS, style: &style.FgDefault}, }, }, + // SHA-256 repo: first commit with a 64-char hash should use the SHA-256 empty tree hash + { + prevPipes: []Pipe{ + {fromPos: 0, toPos: 0, fromHash: pool("a"), toHash: pool("ba741fcd02b3cd42187ee46d4bdbfed10bf8fdbb15ccf739cb9ce583aefe5cae"), kind: TERMINATES, style: &style.FgDefault}, + }, + commit: models.NewCommit(hashPool, models.NewCommitOpts{ + Hash: "ba741fcd02b3cd42187ee46d4bdbfed10bf8fdbb15ccf739cb9ce583aefe5cae", + Parents: []string{}, + }), + expected: []Pipe{ + {fromPos: 1, toPos: 1, fromHash: pool("ba741fcd02b3cd42187ee46d4bdbfed10bf8fdbb15ccf739cb9ce583aefe5cae"), toHash: pool(models.EmptyTreeCommitHashSHA256), kind: STARTS, style: &style.FgDefault}, + }, + }, } oldColorLevel := color.ForceSetColorLevel(terminfo.ColorLevelMillions)