chore: fix git diff render (#38746)

Fix a regression from #38517 (the tail section index is not correctly
assigned).

And add a test to cover GetDiffForRender.
This commit is contained in:
wxiaoguang
2026-08-02 19:34:26 +02:00
committed by GitHub
parent 4e4ea75fb9
commit 7f7dc2d16c
3 changed files with 126 additions and 6 deletions
+5 -2
View File
@@ -9,6 +9,7 @@ import (
"fmt"
"gitea.dev/modules/git/gitcmd"
"gitea.dev/modules/util"
)
type FastImportFile struct {
@@ -27,11 +28,13 @@ type FastImportCommit struct {
func ForceFastImport(ctx context.Context, repo RepositoryFacade, commits []FastImportCommit) error {
var buf bytes.Buffer
for i, c := range commits {
msg := util.IfZero(c.Message, fmt.Sprintf("commit %d", i+1))
_, _ = fmt.Fprintf(&buf, "reset %s\n", c.Ref)
_, _ = fmt.Fprintf(&buf, "commit %s\nmark :%d\ncommitter Gitea <gitea@example.com> 1500000000 +0000\n", c.Ref, i+1)
_, _ = fmt.Fprintf(&buf, "data %d\n%s\n", len(c.Message), c.Message)
_, _ = fmt.Fprintf(&buf, "data %d\n%s\n", len(msg), msg)
for _, f := range c.Files {
_, _ = fmt.Fprintf(&buf, "M %s inline %s\ndata %d\n%s\n", f.Mode.String(), f.Path, len(f.Content), f.Content)
mode := util.IfZero(f.Mode, EntryModeBlob)
_, _ = fmt.Fprintf(&buf, "M %s inline %s\ndata %d\n%s\n", mode.String(), f.Path, len(f.Content), f.Content)
}
}
buf.WriteString("done\n")
+3 -4
View File
@@ -503,16 +503,15 @@ func (diffFile *DiffFile) prepareDiffRenderDetail(ctx context.Context, gitRepo *
// * for "bin" type: need the pre-fetched buffer to detect content type (e.g.: help to render image diff)
// * for "text" type: need to read up to "highlight limit size" to do full-file-highlighting
contentLimit := util.Iif(diffFile.IsBin, typesniffer.SniffContentSize, MaxFullFileHighlightSizeLimit)
var leftLineCount, rightLineCount int
var leftBlobType, rightBlobType typesniffer.SniffedType
if (diffFile.Type == DiffFileDel || diffFile.Type == DiffFileChange) && leftCommit != nil {
c := getCommitFileBlobAndLimitedContent(ctx, gitRepo, leftCommit, diffFile.OldName, contentLimit)
diffFile.LeftBlob, diffFile.LeftBlobSize, leftLineCount, ret.leftContent = c.gitBlob, c.blobSize, c.lineCount, c.limitedContent
diffFile.LeftBlob, diffFile.LeftBlobSize, ret.leftLineCount, ret.leftContent = c.gitBlob, c.blobSize, c.lineCount, c.limitedContent
leftBlobType = typesniffer.DetectContentType(ret.leftContent.buf.Bytes())
}
if (diffFile.Type == DiffFileAdd || diffFile.Type == DiffFileChange) && rightCommit != nil {
c := getCommitFileBlobAndLimitedContent(ctx, gitRepo, rightCommit, diffFile.OldName, contentLimit)
diffFile.RightBlob, diffFile.RightBlobSize, rightLineCount, ret.rightContent = c.gitBlob, c.blobSize, c.lineCount, c.limitedContent
diffFile.RightBlob, diffFile.RightBlobSize, ret.rightLineCount, ret.rightContent = c.gitBlob, c.blobSize, c.lineCount, c.limitedContent
rightBlobType = typesniffer.DetectContentType(ret.rightContent.buf.Bytes())
}
@@ -534,7 +533,7 @@ func (diffFile *DiffFile) prepareDiffRenderDetail(ctx context.Context, gitRepo *
// check whether the text file diff needs a tail section
lastSection := diffFile.Sections[len(diffFile.Sections)-1]
lastLine := lastSection.Lines[len(lastSection.Lines)-1]
if leftLineCount <= lastLine.LeftIdx || rightLineCount <= lastLine.RightIdx {
if ret.leftLineCount <= lastLine.LeftIdx || ret.rightLineCount <= lastLine.RightIdx {
return ret
}
ret.needTailSection = true
+118
View File
@@ -0,0 +1,118 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package gitdiff
import (
"path/filepath"
"strings"
"testing"
"gitea.dev/modules/git"
"gitea.dev/modules/setting"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestGetDiffForRender(t *testing.T) {
repoDir := filepath.Join(t.TempDir(), "temp-repo")
require.NoError(t, git.InitRepositoryLocal(t.Context(), repoDir, false, git.Sha1ObjectFormat.Name()))
contentLeft := strings.Repeat("a\n", 20) +
"mark1\n" +
strings.Repeat("b\n", 10) +
"mark2\n" +
strings.Repeat("c\n", 40) +
"mark3\n" +
strings.Repeat("a\n", 30)
contentRight := strings.Repeat("a\n", 20-1) +
"mark1-x\n" +
strings.Repeat("b\n", 10+3) +
"mark2-x\n" +
strings.Repeat("c\n", 40-5) +
"mark3-x\n" +
strings.Repeat("a\n", 30)
gitRepo, err := git.OpenRepositoryLocal(t.Context(), repoDir)
require.NoError(t, err)
defer gitRepo.Close()
require.NoError(t, git.ForceFastImport(t.Context(), gitRepo, []git.FastImportCommit{
{Ref: "refs/heads/b1", Files: []git.FastImportFile{{Path: "foo.txt", Content: contentLeft}}},
{Ref: "refs/heads/b2", Files: []git.FastImportFile{{Path: "foo.txt", Content: contentRight}}},
}))
beforeCommit, err := gitRepo.GetBranchCommit(t.Context(), "b1")
require.NoError(t, err)
afterCommit, err := gitRepo.GetBranchCommit(t.Context(), "b2")
require.NoError(t, err)
diff, err := GetDiffForRender(t.Context(), "/any/repo-link", gitRepo, &DiffOptions{
BeforeCommitID: beforeCommit.ID.String(),
AfterCommitID: afterCommit.ID.String(),
MaxLines: setting.Git.MaxGitDiffLines,
MaxLineCharacters: setting.Git.MaxGitDiffLineCharacters,
MaxFiles: setting.Git.MaxGitDiffFiles,
})
require.NoError(t, err)
require.Len(t, diff.Files, 1)
type section struct {
ExpandDirection string
LastLeftIdx int
LastRightIdx int
LeftIdx int
RightIdx int
LeftHunkSize int
RightHunkSize int
}
expectedSections := []section{
{
ExpandDirection: "up",
LeftIdx: 17,
RightIdx: 17,
LeftHunkSize: 8,
RightHunkSize: 7,
},
{
ExpandDirection: "single",
LastLeftIdx: 24,
LastRightIdx: 23,
LeftIdx: 29,
RightIdx: 28,
LeftHunkSize: 7,
RightHunkSize: 10,
},
{
ExpandDirection: "updown",
LastLeftIdx: 35,
LastRightIdx: 37,
LeftIdx: 65,
RightIdx: 67,
LeftHunkSize: 12,
RightHunkSize: 7,
},
{
ExpandDirection: "down",
LastLeftIdx: 76,
LastRightIdx: 73,
LeftIdx: 104,
RightIdx: 101,
},
}
for idx, exp := range expectedSections {
secLine := diff.Files[0].Sections[idx].Lines[0] // line 0 should be the "section info"
actual := section{
ExpandDirection: secLine.GetExpandDirection(),
LastLeftIdx: secLine.SectionInfo.LastLeftIdx,
LastRightIdx: secLine.SectionInfo.LastRightIdx,
LeftIdx: secLine.SectionInfo.LeftIdx,
RightIdx: secLine.SectionInfo.RightIdx,
LeftHunkSize: secLine.SectionInfo.LeftHunkSize,
RightHunkSize: secLine.SectionInfo.RightHunkSize,
}
assert.Equal(t, exp, actual, "idx=%d", idx)
}
}