Files
Gitea/services/repository/gitgraph/graph.go
T
wxiaoguang fe31237fd8 fix: handle git branch name with special chars correctly (#39483)
Fix the bugs:
* Commit graph page doesn't show
* PR command line instructions are wrong

---------

Co-authored-by: silverwind <me@silverwind.io>
2026-10-01 04:01:16 +00:00

112 lines
2.9 KiB
Go

// Copyright 2016 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package gitgraph
import (
"bufio"
"bytes"
"context"
"strings"
"gitea.dev/modules/git"
"gitea.dev/modules/git/gitcmd"
"gitea.dev/modules/setting"
)
const gitLogGraphFormatSep = "^" // disallowed char in git ref names
// GetCommitGraph return a list of commit (GraphItems) from all branches
func GetCommitGraph(ctx context.Context, gitRepo *git.Repository, page, maxAllowedColors int, hidePRRefs bool, refs, files []string) (*Graph, error) {
format := "DATA:" + strings.Join([]string{
"%D", // ref names without the " (", ")" wrapping.
"%H", // commit hash
"%ad", // author date (format respects --date= option)
"%h", // abbreviated commit hash
"%s", // subject
}, gitLogGraphFormatSep)
page = max(page, 1)
graphCmd := gitcmd.NewCommand("log", "--graph", "--date-order", "--decorate=full")
if hidePRRefs {
graphCmd.AddArguments("--exclude=" + git.PullPrefix + "*")
}
if len(refs) == 0 {
graphCmd.AddArguments("--tags", "--branches")
}
graphCmd.AddArguments("--find-copies", "--find-renames", "--date=iso-strict").
AddOptionFormat("-n %d", setting.UI.GraphMaxCommitNum*page).
AddOptionFormat("--pretty=format:%s", format)
if len(refs) > 0 {
graphCmd.AddDynamicArguments(refs...)
}
if len(files) > 0 {
graphCmd.AddDashesAndList(files...)
}
graph := NewGraph()
commitsToSkip := setting.UI.GraphMaxCommitNum * (page - 1)
stdoutReader, stdoutReaderClose := graphCmd.MakeStdoutPipe()
defer stdoutReaderClose()
if err := graphCmd.
WithRepo(gitRepo).
WithPipelineFunc(func(ctx gitcmd.Context) error {
scanner := bufio.NewScanner(stdoutReader)
parser := &Parser{}
parser.firstInUse = -1
parser.maxAllowedColors = maxAllowedColors
if maxAllowedColors > 0 {
parser.availableColors = make([]int, maxAllowedColors)
for i := range parser.availableColors {
parser.availableColors[i] = i + 1
}
} else {
parser.availableColors = []int{1, 2}
}
for commitsToSkip > 0 && scanner.Scan() {
line := scanner.Bytes()
dataIdx := bytes.Index(line, []byte("DATA:"))
if dataIdx < 0 {
dataIdx = len(line)
}
starIdx := bytes.IndexByte(line, '*')
if starIdx >= 0 && starIdx < dataIdx {
commitsToSkip--
}
parser.ParseGlyphs(line[:dataIdx])
}
row := 0
// Skip initial non-commit lines
for scanner.Scan() {
line := scanner.Bytes()
if bytes.IndexByte(line, '*') >= 0 {
if err := parser.AddLineToGraph(graph, row, line); err != nil {
return ctx.CancelPipeline(err)
}
break
}
parser.ParseGlyphs(line)
}
for scanner.Scan() {
row++
line := scanner.Bytes()
if err := parser.AddLineToGraph(graph, row, line); err != nil {
return ctx.CancelPipeline(err)
}
}
return scanner.Err()
}).
RunWithStderr(ctx); err != nil {
return graph, err
}
return graph, nil
}