This commit is contained in:
Lunny Xiao 2025-10-27 00:06:57 +08:00 committed by GitHub
commit c9940ab157
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
117 changed files with 715 additions and 704 deletions

View File

@ -44,12 +44,12 @@ func IsWorkflow(path string) bool {
return strings.HasPrefix(path, ".gitea/workflows") || strings.HasPrefix(path, ".github/workflows")
}
func ListWorkflows(commit *git.Commit) (string, git.Entries, error) {
func ListWorkflows(rootTree *git.Tree) (string, git.Entries, error) {
rpath := ".gitea/workflows"
tree, err := commit.SubTree(rpath)
tree, err := rootTree.SubTree(rpath)
if _, ok := err.(git.ErrNotExist); ok {
rpath = ".github/workflows"
tree, err = commit.SubTree(rpath)
tree, err = rootTree.SubTree(rpath)
}
if _, ok := err.(git.ErrNotExist); ok {
return "", nil, nil
@ -105,7 +105,7 @@ func DetectWorkflows(
payload api.Payloader,
detectSchedule bool,
) ([]*DetectedWorkflow, []*DetectedWorkflow, error) {
_, entries, err := ListWorkflows(commit)
_, entries, err := ListWorkflows(git.NewTree(gitRepo, commit.TreeID))
if err != nil {
return nil, nil, err
}
@ -150,7 +150,7 @@ func DetectWorkflows(
}
func DetectScheduledWorkflows(gitRepo *git.Repository, commit *git.Commit) ([]*DetectedWorkflow, error) {
_, entries, err := ListWorkflows(commit)
_, entries, err := ListWorkflows(git.NewTree(gitRepo, commit.TreeID))
if err != nil {
return nil, err
}
@ -204,7 +204,7 @@ func detectMatched(gitRepo *git.Repository, commit *git.Commit, triggedEvent web
case // push
webhook_module.HookEventPush:
return matchPushEvent(commit, payload.(*api.PushPayload), evt)
return matchPushEvent(gitRepo, commit, payload.(*api.PushPayload), evt)
case // issues
webhook_module.HookEventIssues,
@ -256,7 +256,7 @@ func detectMatched(gitRepo *git.Repository, commit *git.Commit, triggedEvent web
}
}
func matchPushEvent(commit *git.Commit, pushPayload *api.PushPayload, evt *jobparser.Event) bool {
func matchPushEvent(gitRepo *git.Repository, commit *git.Commit, pushPayload *api.PushPayload, evt *jobparser.Event) bool {
// with no special filter parameters
if len(evt.Acts()) == 0 {
return true
@ -322,7 +322,7 @@ func matchPushEvent(commit *git.Commit, pushPayload *api.PushPayload, evt *jobpa
matchTimes++
break
}
filesChanged, err := commit.GetFilesChangedSinceCommit(pushPayload.Before)
filesChanged, err := gitRepo.GetFilesChangedBetween(pushPayload.Before, commit.ID.String())
if err != nil {
log.Error("GetFilesChangedSinceCommit [commit_sha1: %s]: %v", commit.ID.String(), err)
} else {
@ -339,7 +339,7 @@ func matchPushEvent(commit *git.Commit, pushPayload *api.PushPayload, evt *jobpa
matchTimes++
break
}
filesChanged, err := commit.GetFilesChangedSinceCommit(pushPayload.Before)
filesChanged, err := gitRepo.GetFilesChangedBetween(pushPayload.Before, commit.ID.String())
if err != nil {
log.Error("GetFilesChangedSinceCommit [commit_sha1: %s]: %v", commit.ID.String(), err)
} else {
@ -486,7 +486,7 @@ func matchPullRequestEvent(gitRepo *git.Repository, commit *git.Commit, prPayloa
matchTimes++
}
case "paths":
filesChanged, err := headCommit.GetFilesChangedSinceCommit(prPayload.PullRequest.MergeBase)
filesChanged, err := gitRepo.GetFilesChangedBetween(prPayload.PullRequest.MergeBase, headCommit.ID.String())
if err != nil {
log.Error("GetFilesChangedSinceCommit [commit_sha1: %s]: %v", headCommit.ID.String(), err)
} else {
@ -499,7 +499,7 @@ func matchPullRequestEvent(gitRepo *git.Repository, commit *git.Commit, prPayloa
}
}
case "paths-ignore":
filesChanged, err := headCommit.GetFilesChangedSinceCommit(prPayload.PullRequest.MergeBase)
filesChanged, err := gitRepo.GetFilesChangedBetween(prPayload.PullRequest.MergeBase, headCommit.ID.String())
if err != nil {
log.Error("GetFilesChangedSinceCommit [commit_sha1: %s]: %v", headCommit.ID.String(), err)
} else {

View File

@ -12,10 +12,10 @@ type EntryInfo struct {
IsOpen bool
}
func EntryInfoFromGitTreeEntry(commit *git.Commit, fullPath string, gitEntry *git.TreeEntry) *EntryInfo {
func EntryInfoFromGitTreeEntry(tree *git.Tree, fullPath string, gitEntry *git.TreeEntry) *EntryInfo {
ret := &EntryInfo{BaseName: gitEntry.Name(), EntryMode: gitEntry.Mode()}
if gitEntry.IsLink() {
if res, err := git.EntryFollowLink(commit, fullPath, gitEntry); err == nil && res.TargetEntry.IsDir() {
if res, err := git.EntryFollowLink(tree, fullPath, gitEntry); err == nil && res.TargetEntry.IsDir() {
ret.SymlinkToMode = res.TargetEntry.Mode()
}
}

View File

@ -133,7 +133,7 @@ func (r *BlameReader) Close() error {
}
// CreateBlameReader creates reader for given repository, commit and file
func CreateBlameReader(ctx context.Context, objectFormat ObjectFormat, repoPath string, commit *Commit, file string, bypassBlameIgnore bool) (rd *BlameReader, err error) {
func CreateBlameReader(ctx context.Context, repo *Repository, objectFormat ObjectFormat, repoPath string, commit *Commit, file string, bypassBlameIgnore bool) (rd *BlameReader, err error) {
var ignoreRevsFileName string
var ignoreRevsFileCleanup func()
defer func() {
@ -145,7 +145,8 @@ func CreateBlameReader(ctx context.Context, objectFormat ObjectFormat, repoPath
cmd := gitcmd.NewCommand("blame", "--porcelain")
if DefaultFeatures().CheckVersionAtLeast("2.23") && !bypassBlameIgnore {
ignoreRevsFileName, ignoreRevsFileCleanup, err = tryCreateBlameIgnoreRevsFile(commit)
tree := NewTree(repo, commit.TreeID)
ignoreRevsFileName, ignoreRevsFileCleanup, err = tryCreateBlameIgnoreRevsFile(tree)
if err != nil && !IsErrNotExist(err) {
return nil, err
}
@ -190,8 +191,8 @@ func CreateBlameReader(ctx context.Context, objectFormat ObjectFormat, repoPath
}, nil
}
func tryCreateBlameIgnoreRevsFile(commit *Commit) (string, func(), error) {
entry, err := commit.GetTreeEntryByPath(".git-blame-ignore-revs")
func tryCreateBlameIgnoreRevsFile(tree *Tree) (string, func(), error) {
entry, err := tree.GetTreeEntryByPath(".git-blame-ignore-revs")
if err != nil {
return "", nil, err
}

View File

@ -47,7 +47,7 @@ func TestReadingBlameOutputSha256(t *testing.T) {
}
for _, bypass := range []bool{false, true} {
blameReader, err := CreateBlameReader(ctx, Sha256ObjectFormat, "./tests/repos/repo5_pulls_sha256", commit, "README.md", bypass)
blameReader, err := CreateBlameReader(ctx, repo, Sha256ObjectFormat, "./tests/repos/repo5_pulls_sha256", commit, "README.md", bypass)
assert.NoError(t, err)
assert.NotNil(t, blameReader)
defer blameReader.Close()
@ -131,7 +131,7 @@ func TestReadingBlameOutputSha256(t *testing.T) {
for _, c := range cases {
commit, err := repo.GetCommit(c.CommitID)
assert.NoError(t, err)
blameReader, err := CreateBlameReader(ctx, objectFormat, "./tests/repos/repo6_blame_sha256", commit, "blame.txt", c.Bypass)
blameReader, err := CreateBlameReader(ctx, repo, objectFormat, "./tests/repos/repo6_blame_sha256", commit, "blame.txt", c.Bypass)
assert.NoError(t, err)
assert.NotNil(t, blameReader)
defer blameReader.Close()

View File

@ -42,7 +42,7 @@ func TestReadingBlameOutput(t *testing.T) {
}
for _, bypass := range []bool{false, true} {
blameReader, err := CreateBlameReader(ctx, Sha1ObjectFormat, "./tests/repos/repo5_pulls", commit, "README.md", bypass)
blameReader, err := CreateBlameReader(ctx, repo, Sha1ObjectFormat, "./tests/repos/repo5_pulls", commit, "README.md", bypass)
assert.NoError(t, err)
assert.NotNil(t, blameReader)
defer blameReader.Close()
@ -127,7 +127,7 @@ func TestReadingBlameOutput(t *testing.T) {
commit, err := repo.GetCommit(c.CommitID)
assert.NoError(t, err)
blameReader, err := CreateBlameReader(ctx, objectFormat, "./tests/repos/repo6_blame", commit, "blame.txt", c.Bypass)
blameReader, err := CreateBlameReader(ctx, repo, objectFormat, "./tests/repos/repo6_blame", commit, "blame.txt", c.Bypass)
assert.NoError(t, err)
assert.NotNil(t, blameReader)
defer blameReader.Close()

View File

@ -8,9 +8,7 @@ import (
"bufio"
"bytes"
"context"
"errors"
"io"
"os/exec"
"strconv"
"strings"
@ -21,16 +19,13 @@ import (
// Commit represents a git commit.
type Commit struct {
Tree // FIXME: bad design, this field can be nil if the commit is from "last commit cache"
ID ObjectID
TreeID ObjectID
Parents []ObjectID // ID strings
Author *Signature // never nil
Committer *Signature // never nil
CommitMessage string
Signature *CommitSignature
Parents []ObjectID // ID strings
submoduleCache *ObjectCache[*SubModule]
}
// CommitSignature represents a git commit signature part.
@ -59,33 +54,12 @@ func (c *Commit) ParentID(n int) (ObjectID, error) {
return c.Parents[n], nil
}
// Parent returns n-th parent (0-based index) of the commit.
func (c *Commit) Parent(n int) (*Commit, error) {
id, err := c.ParentID(n)
if err != nil {
return nil, err
}
parent, err := c.repo.getCommit(id)
if err != nil {
return nil, err
}
return parent, nil
}
// ParentCount returns number of parents of the commit.
// 0 if this is the root commit, otherwise 1,2, etc.
func (c *Commit) ParentCount() int {
return len(c.Parents)
}
// GetCommitByPath return the commit of relative path object.
func (c *Commit) GetCommitByPath(relpath string) (*Commit, error) {
if c.repo.LastCommitCache != nil {
return c.repo.LastCommitCache.GetCommitByPath(c.ID.String(), relpath)
}
return c.repo.getCommitByPathWithID(c.ID, relpath)
}
// AddChanges marks local changes to be ready for commit.
func AddChanges(ctx context.Context, repoPath string, all bool, files ...string) error {
cmd := gitcmd.NewCommand().AddArguments("add")
@ -181,81 +155,6 @@ func CommitsCount(ctx context.Context, opts CommitsCountOptions) (int64, error)
return strconv.ParseInt(strings.TrimSpace(stdout), 10, 64)
}
// CommitsCount returns number of total commits of until current revision.
func (c *Commit) CommitsCount() (int64, error) {
return CommitsCount(c.repo.Ctx, CommitsCountOptions{
RepoPath: c.repo.Path,
Revision: []string{c.ID.String()},
})
}
// CommitsByRange returns the specific page commits before current revision, every page's number default by CommitsRangeSize
func (c *Commit) CommitsByRange(page, pageSize int, not, since, until string) ([]*Commit, error) {
return c.repo.commitsByRangeWithTime(c.ID, page, pageSize, not, since, until)
}
// CommitsBefore returns all the commits before current revision
func (c *Commit) CommitsBefore() ([]*Commit, error) {
return c.repo.getCommitsBefore(c.ID)
}
// HasPreviousCommit returns true if a given commitHash is contained in commit's parents
func (c *Commit) HasPreviousCommit(objectID ObjectID) (bool, error) {
this := c.ID.String()
that := objectID.String()
if this == that {
return false, nil
}
_, _, err := gitcmd.NewCommand("merge-base", "--is-ancestor").
AddDynamicArguments(that, this).
WithDir(c.repo.Path).
RunStdString(c.repo.Ctx)
if err == nil {
return true, nil
}
var exitError *exec.ExitError
if errors.As(err, &exitError) {
if exitError.ProcessState.ExitCode() == 1 && len(exitError.Stderr) == 0 {
return false, nil
}
}
return false, err
}
// IsForcePush returns true if a push from oldCommitHash to this is a force push
func (c *Commit) IsForcePush(oldCommitID string) (bool, error) {
objectFormat, err := c.repo.GetObjectFormat()
if err != nil {
return false, err
}
if oldCommitID == objectFormat.EmptyObjectID().String() {
return false, nil
}
oldCommit, err := c.repo.GetCommit(oldCommitID)
if err != nil {
return false, err
}
hasPreviousCommit, err := c.HasPreviousCommit(oldCommit.ID)
return !hasPreviousCommit, err
}
// CommitsBeforeLimit returns num commits before current revision
func (c *Commit) CommitsBeforeLimit(num int) ([]*Commit, error) {
return c.repo.getCommitsBeforeLimit(c.ID, num)
}
// CommitsBeforeUntil returns the commits between commitID to current revision
func (c *Commit) CommitsBeforeUntil(commitID string) ([]*Commit, error) {
endCommit, err := c.repo.GetCommit(commitID)
if err != nil {
return nil, err
}
return c.repo.CommitsBetween(c, endCommit)
}
// SearchCommitsOptions specify the parameters for SearchCommits
type SearchCommitsOptions struct {
Keywords []string
@ -295,82 +194,6 @@ func NewSearchCommitsOptions(searchString string, forAllRefs bool) SearchCommits
}
}
// SearchCommits returns the commits match the keyword before current revision
func (c *Commit) SearchCommits(opts SearchCommitsOptions) ([]*Commit, error) {
return c.repo.searchCommits(c.ID, opts)
}
// GetFilesChangedSinceCommit get all changed file names between pastCommit to current revision
func (c *Commit) GetFilesChangedSinceCommit(pastCommit string) ([]string, error) {
return c.repo.GetFilesChangedBetween(pastCommit, c.ID.String())
}
// FileChangedSinceCommit Returns true if the file given has changed since the past commit
// YOU MUST ENSURE THAT pastCommit is a valid commit ID.
func (c *Commit) FileChangedSinceCommit(filename, pastCommit string) (bool, error) {
return c.repo.FileChangedBetweenCommits(filename, pastCommit, c.ID.String())
}
// HasFile returns true if the file given exists on this commit
// This does only mean it's there - it does not mean the file was changed during the commit.
func (c *Commit) HasFile(filename string) (bool, error) {
_, err := c.GetBlobByPath(filename)
if err != nil {
return false, err
}
return true, nil
}
// GetFileContent reads a file content as a string or returns false if this was not possible
func (c *Commit) GetFileContent(filename string, limit int) (string, error) {
entry, err := c.GetTreeEntryByPath(filename)
if err != nil {
return "", err
}
r, err := entry.Blob().DataAsync()
if err != nil {
return "", err
}
defer r.Close()
if limit > 0 {
bs := make([]byte, limit)
n, err := util.ReadAtMost(r, bs)
if err != nil {
return "", err
}
return string(bs[:n]), nil
}
bytes, err := io.ReadAll(r)
if err != nil {
return "", err
}
return string(bytes), nil
}
// GetBranchName gets the closest branch name (as returned by 'git name-rev --name-only')
func (c *Commit) GetBranchName() (string, error) {
cmd := gitcmd.NewCommand("name-rev")
if DefaultFeatures().CheckVersionAtLeast("2.13.0") {
cmd.AddArguments("--exclude", "refs/tags/*")
}
cmd.AddArguments("--name-only", "--no-undefined").AddDynamicArguments(c.ID.String())
data, _, err := cmd.WithDir(c.repo.Path).RunStdString(c.repo.Ctx)
if err != nil {
// handle special case where git can not describe commit
if strings.Contains(err.Error(), "cannot describe") {
return "", nil
}
return "", err
}
// name-rev commitID output will be "master" or "master~12"
return strings.SplitN(strings.TrimSpace(data), "~", 2)[0], nil
}
// CommitFileStatus represents status of files in a commit.
type CommitFileStatus struct {
Added []string
@ -465,14 +288,6 @@ func GetFullCommitID(ctx context.Context, repoPath, shortID string) (string, err
return strings.TrimSpace(commitID), nil
}
// GetRepositoryDefaultPublicGPGKey returns the default public key for this commit
func (c *Commit) GetRepositoryDefaultPublicGPGKey(forceUpdate bool) (*GPGSettings, error) {
if c.repo == nil {
return nil, nil
}
return c.repo.GetDefaultPublicGPGKey(forceUpdate)
}
func IsStringLikelyCommitID(objFmt ObjectFormat, s string, minLength ...int) bool {
maxLen := 64 // sha256
if objFmt != nil {

View File

@ -66,6 +66,7 @@ func convertPGPSignature(c *object.Commit) *CommitSignature {
func convertCommit(c *object.Commit) *Commit {
return &Commit{
ID: ParseGogitHash(c.Hash),
TreeID: ParseGogitHash(c.TreeHash),
CommitMessage: c.Message,
Committer: &c.Committer,
Author: &c.Author,

View File

@ -7,17 +7,17 @@ package git
type CommitInfo struct {
Entry *TreeEntry
Commit *Commit
SubmoduleFile *CommitSubmoduleFile
SubmoduleFile *SubmoduleFile
}
func GetCommitInfoSubmoduleFile(repoLink, fullPath string, commit *Commit, refCommitID ObjectID) (*CommitSubmoduleFile, error) {
submodule, err := commit.GetSubModule(fullPath)
func GetCommitInfoSubmoduleFile(gitRepo *Repository, repoLink, fullPath string, treeID, refCommitID ObjectID) (*SubmoduleFile, error) {
submodule, err := NewTree(gitRepo, treeID).GetSubModule(fullPath)
if err != nil {
return nil, err
}
if submodule == nil {
// unable to find submodule from ".gitmodules" file
return NewCommitSubmoduleFile(repoLink, fullPath, "", refCommitID.String()), nil
return NewSubmoduleFile(repoLink, fullPath, "", refCommitID.String()), nil
}
return NewCommitSubmoduleFile(repoLink, fullPath, submodule.URL, refCommitID.String()), nil
return NewSubmoduleFile(repoLink, fullPath, submodule.URL, refCommitID.String()), nil
}

View File

@ -16,7 +16,7 @@ import (
)
// GetCommitsInfo gets information of all commits that are corresponding to these entries
func (tes Entries) GetCommitsInfo(ctx context.Context, repoLink string, commit *Commit, treePath string) ([]CommitInfo, *Commit, error) {
func (tes Entries) GetCommitsInfo(ctx context.Context, gitRepo *Repository, repoLink string, commit *Commit, treePath string) ([]CommitInfo, *Commit, error) {
entryPaths := make([]string, len(tes)+1)
// Get the commit for the treePath itself
entryPaths[0] = ""
@ -24,7 +24,7 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, repoLink string, commit *
entryPaths[i+1] = entry.Name()
}
commitNodeIndex, commitGraphFile := commit.repo.CommitNodeIndex()
commitNodeIndex, commitGraphFile := gitRepo.CommitNodeIndex()
if commitGraphFile != nil {
defer commitGraphFile.Close()
}
@ -35,14 +35,14 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, repoLink string, commit *
}
var revs map[string]*Commit
if commit.repo.LastCommitCache != nil {
if gitRepo.LastCommitCache != nil {
var unHitPaths []string
revs, unHitPaths, err = getLastCommitForPathsByCache(commit.ID.String(), treePath, entryPaths, commit.repo.LastCommitCache)
revs, unHitPaths, err = getLastCommitForPathsByCache(commit.ID.String(), treePath, entryPaths, gitRepo.LastCommitCache)
if err != nil {
return nil, nil, err
}
if len(unHitPaths) > 0 {
revs2, err := GetLastCommitForPaths(ctx, commit.repo.LastCommitCache, c, treePath, unHitPaths)
revs2, err := GetLastCommitForPaths(ctx, gitRepo.LastCommitCache, c, treePath, unHitPaths)
if err != nil {
return nil, nil, err
}
@ -58,7 +58,7 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, repoLink string, commit *
return nil, nil, err
}
commit.repo.gogitStorage.Close()
gitRepo.gogitStorage.Close()
commitsInfo := make([]CommitInfo, len(tes))
for i, entry := range tes {
@ -73,7 +73,7 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, repoLink string, commit *
// If the entry is a submodule, add a submodule file for this
if entry.IsSubModule() {
commitsInfo[i].SubmoduleFile, err = GetCommitInfoSubmoduleFile(repoLink, path.Join(treePath, entry.Name()), commit, entry.ID)
commitsInfo[i].SubmoduleFile, err = GetCommitInfoSubmoduleFile(gitRepo, repoLink, path.Join(treePath, entry.Name()), commit.TreeID, entry.ID)
if err != nil {
return nil, nil, err
}
@ -84,11 +84,10 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, repoLink string, commit *
// get it for free during the tree traversal and it's used for listing
// pages to display information about newest commit for a given path.
var treeCommit *Commit
var ok bool
if treePath == "" {
treeCommit = commit
} else if treeCommit, ok = revs[""]; ok {
treeCommit.repo = commit.repo
} else {
treeCommit = revs[""]
}
return commitsInfo, treeCommit, nil
}

View File

@ -15,7 +15,7 @@ import (
)
// GetCommitsInfo gets information of all commits that are corresponding to these entries
func (tes Entries) GetCommitsInfo(ctx context.Context, repoLink string, commit *Commit, treePath string) ([]CommitInfo, *Commit, error) {
func (tes Entries) GetCommitsInfo(ctx context.Context, gitRepo *Repository, repoLink string, commit *Commit, treePath string) ([]CommitInfo, *Commit, error) {
entryPaths := make([]string, len(tes)+1)
// Get the commit for the treePath itself
entryPaths[0] = ""
@ -26,15 +26,15 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, repoLink string, commit *
var err error
var revs map[string]*Commit
if commit.repo.LastCommitCache != nil {
if gitRepo.LastCommitCache != nil {
var unHitPaths []string
revs, unHitPaths, err = getLastCommitForPathsByCache(commit.ID.String(), treePath, entryPaths, commit.repo.LastCommitCache)
revs, unHitPaths, err = getLastCommitForPathsByCache(commit.ID.String(), treePath, entryPaths, gitRepo.LastCommitCache)
if err != nil {
return nil, nil, err
}
if len(unHitPaths) > 0 {
sort.Strings(unHitPaths)
commits, err := GetLastCommitForPaths(ctx, commit, treePath, unHitPaths)
commits, err := GetLastCommitForPaths(ctx, gitRepo, commit, treePath, unHitPaths)
if err != nil {
return nil, nil, err
}
@ -43,7 +43,7 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, repoLink string, commit *
}
} else {
sort.Strings(entryPaths)
revs, err = GetLastCommitForPaths(ctx, commit, treePath, entryPaths)
revs, err = GetLastCommitForPaths(ctx, gitRepo, commit, treePath, entryPaths)
}
if err != nil {
return nil, nil, err
@ -64,7 +64,7 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, repoLink string, commit *
// If the entry is a submodule, add a submodule file for this
if entry.IsSubModule() {
commitsInfo[i].SubmoduleFile, err = GetCommitInfoSubmoduleFile(repoLink, path.Join(treePath, entry.Name()), commit, entry.ID)
commitsInfo[i].SubmoduleFile, err = GetCommitInfoSubmoduleFile(gitRepo, repoLink, path.Join(treePath, entry.Name()), commit.TreeID, entry.ID)
if err != nil {
return nil, nil, err
}
@ -75,11 +75,10 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, repoLink string, commit *
// get it for free during the tree traversal, and it's used for listing
// pages to display information about the newest commit for a given path.
var treeCommit *Commit
var ok bool
if treePath == "" {
treeCommit = commit
} else if treeCommit, ok = revs[""]; ok {
treeCommit.repo = commit.repo
} else {
treeCommit = revs[""]
}
return commitsInfo, treeCommit, nil
}
@ -104,9 +103,9 @@ func getLastCommitForPathsByCache(commitID, treePath string, paths []string, cac
}
// GetLastCommitForPaths returns last commit information
func GetLastCommitForPaths(ctx context.Context, commit *Commit, treePath string, paths []string) (map[string]*Commit, error) {
func GetLastCommitForPaths(ctx context.Context, gitRepo *Repository, commit *Commit, treePath string, paths []string) (map[string]*Commit, error) {
// We read backwards from the commit to obtain all of the commits
revs, err := WalkGitLog(ctx, commit.repo, commit, treePath, paths...)
revs, err := WalkGitLog(ctx, gitRepo, commit, treePath, paths...)
if err != nil {
return nil, err
}
@ -126,7 +125,7 @@ func GetLastCommitForPaths(ctx context.Context, commit *Commit, treePath string,
continue
}
c, err := commit.repo.GetCommit(commitID) // Ensure the commit exists in the repository
c, err := gitRepo.GetCommit(commitID) // Ensure the commit exists in the repository
if err != nil {
return nil, err
}

View File

@ -62,10 +62,9 @@ func testGetCommitsInfo(t *testing.T, repo1 *Repository) {
continue
}
assert.NotNil(t, commit)
assert.NotNil(t, commit.Tree)
assert.NotNil(t, commit.Tree.repo)
assert.NotNil(t, commit.TreeID)
tree, err := commit.Tree.SubTree(testCase.Path)
tree, err := NewTree(repo1, commit.TreeID).SubTree(testCase.Path)
if err != nil {
assert.NoError(t, err, "Unable to get subtree: %s of commit: %s from testcase due to error: %v", testCase.Path, testCase.CommitID, err)
// no point trying to do anything else for this test.
@ -83,7 +82,7 @@ func testGetCommitsInfo(t *testing.T, repo1 *Repository) {
}
// FIXME: Context.TODO() - if graceful has started we should use its Shutdown context otherwise use install signals in TestMain.
commitsInfo, treeCommit, err := entries.GetCommitsInfo(t.Context(), "/any/repo-link", commit, testCase.Path)
commitsInfo, treeCommit, err := entries.GetCommitsInfo(t.Context(), repo1, "/any/repo-link", commit, testCase.Path)
assert.NoError(t, err, "Unable to get commit information for entries of subtree: %s in commit: %s from testcase due to error: %v", testCase.Path, testCase.CommitID, err)
if err != nil {
t.FailNow()
@ -125,11 +124,12 @@ func TestEntries_GetCommitsInfo(t *testing.T) {
t.Run("NonExistingSubmoduleAsNil", func(t *testing.T) {
commit, err := bareRepo1.GetCommit("HEAD")
require.NoError(t, err)
treeEntry, err := commit.GetTreeEntryByPath("file1.txt")
tree := NewTree(bareRepo1, commit.TreeID)
treeEntry, err := tree.GetTreeEntryByPath("file1.txt")
require.NoError(t, err)
cisf, err := GetCommitInfoSubmoduleFile("/any/repo-link", "file1.txt", commit, treeEntry.ID)
cisf, err := GetCommitInfoSubmoduleFile(bareRepo1, "/any/repo-link", "file1.txt", commit.TreeID, treeEntry.ID)
require.NoError(t, err)
assert.Equal(t, &CommitSubmoduleFile{
assert.Equal(t, &SubmoduleFile{
repoLink: "/any/repo-link",
fullPath: "file1.txt",
refURL: "",
@ -170,14 +170,14 @@ func BenchmarkEntries_GetCommitsInfo(b *testing.B) {
if commit, err = repo.GetBranchCommit("master"); err != nil {
b.Fatal(err)
} else if entries, err = commit.Tree.ListEntries(); err != nil {
} else if entries, err = NewTree(repo, commit.TreeID).ListEntries(); err != nil {
b.Fatal(err)
}
entries.Sort()
b.ResetTimer()
b.Run(benchmark.name, func(b *testing.B) {
for b.Loop() {
_, _, err := entries.GetCommitsInfo(b.Context(), "/any/repo-link", commit, "")
_, _, err := entries.GetCommitsInfo(b.Context(), repo, "/any/repo-link", commit, "")
if err != nil {
b.Fatal(err)
}

View File

@ -15,7 +15,7 @@ const (
commitHeaderGpgsigSha256 = "gpgsig-sha256"
)
func assignCommitFields(gitRepo *Repository, commit *Commit, headerKey string, headerValue []byte) error {
func assignCommitFields(commit *Commit, headerKey string, headerValue []byte) error {
if len(headerValue) > 0 && headerValue[len(headerValue)-1] == '\n' {
headerValue = headerValue[:len(headerValue)-1] // remove trailing newline
}
@ -25,7 +25,7 @@ func assignCommitFields(gitRepo *Repository, commit *Commit, headerKey string, h
if err != nil {
return fmt.Errorf("invalid tree ID %q: %w", string(headerValue), err)
}
commit.Tree = *NewTree(gitRepo, objID)
commit.TreeID = objID
case "parent":
objID, err := NewIDFromString(string(headerValue))
if err != nil {
@ -48,7 +48,7 @@ func assignCommitFields(gitRepo *Repository, commit *Commit, headerKey string, h
// We need this to interpret commits from cat-file or cat-file --batch
//
// If used as part of a cat-file --batch stream you need to limit the reader to the correct size
func CommitFromReader(gitRepo *Repository, objectID ObjectID, reader io.Reader) (*Commit, error) {
func CommitFromReader(objectID ObjectID, reader io.Reader) (*Commit, error) {
commit := &Commit{
ID: objectID,
Author: &Signature{},
@ -74,7 +74,7 @@ func CommitFromReader(gitRepo *Repository, objectID ObjectID, reader io.Reader)
k, v, _ := bytes.Cut(line, []byte{' '})
if len(k) != 0 || !inHeader {
if headerKey != "" {
if err = assignCommitFields(gitRepo, commit, headerKey, headerValue); err != nil {
if err = assignCommitFields(commit, headerKey, headerValue); err != nil {
return nil, fmt.Errorf("unable to parse commit %q: %w", objectID.String(), err)
}
}

View File

@ -92,7 +92,7 @@ signed commit`
assert.NotNil(t, gitRepo)
defer gitRepo.Close()
commitFromReader, err := CommitFromReader(gitRepo, sha, strings.NewReader(commitString))
commitFromReader, err := CommitFromReader(sha, strings.NewReader(commitString))
assert.NoError(t, err)
require.NotNil(t, commitFromReader)
assert.EqualValues(t, sha, commitFromReader.ID)
@ -120,7 +120,7 @@ committer Adam Majer <amajer@suse.de> 1698676906 +0100
signed commit`, commitFromReader.Signature.Payload)
assert.Equal(t, "Adam Majer <amajer@suse.de>", commitFromReader.Author.String())
commitFromReader2, err := CommitFromReader(gitRepo, sha, strings.NewReader(commitString+"\n\n"))
commitFromReader2, err := CommitFromReader(sha, strings.NewReader(commitString+"\n\n"))
assert.NoError(t, err)
commitFromReader.CommitMessage += "\n\n"
commitFromReader.Signature.Payload += "\n\n"
@ -145,15 +145,15 @@ func TestHasPreviousCommitSha256(t *testing.T) {
assert.Equal(t, objectFormat, parentSHA.Type())
assert.Equal(t, "sha256", objectFormat.Name())
haz, err := commit.HasPreviousCommit(parentSHA)
haz, err := repo.HasPreviousCommit(commit, parentSHA)
assert.NoError(t, err)
assert.True(t, haz)
hazNot, err := commit.HasPreviousCommit(notParentSHA)
hazNot, err := repo.HasPreviousCommit(commit, notParentSHA)
assert.NoError(t, err)
assert.False(t, hazNot)
selfNot, err := commit.HasPreviousCommit(commit.ID)
selfNot, err := repo.HasPreviousCommit(commit, commit.ID)
assert.NoError(t, err)
assert.False(t, selfNot)
}

View File

@ -1,52 +0,0 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package git
type SubmoduleWebLink struct {
RepoWebLink, CommitWebLink string
}
// GetSubModules get all the submodules of current revision git tree
func (c *Commit) GetSubModules() (*ObjectCache[*SubModule], error) {
if c.submoduleCache != nil {
return c.submoduleCache, nil
}
entry, err := c.GetTreeEntryByPath(".gitmodules")
if err != nil {
if _, ok := err.(ErrNotExist); ok {
return nil, nil
}
return nil, err
}
rd, err := entry.Blob().DataAsync()
if err != nil {
return nil, err
}
defer rd.Close()
// at the moment we do not strictly limit the size of the .gitmodules file because some users would have huge .gitmodules files (>1MB)
c.submoduleCache, err = configParseSubModules(rd)
if err != nil {
return nil, err
}
return c.submoduleCache, nil
}
// GetSubModule gets the submodule by the entry name.
// It returns "nil, nil" if the submodule does not exist, caller should always remember to check the "nil"
func (c *Commit) GetSubModule(entryName string) (*SubModule, error) {
modules, err := c.GetSubModules()
if err != nil {
return nil, err
}
if modules != nil {
if module, has := modules.Get(entryName); has {
return module, nil
}
}
return nil, nil
}

View File

@ -88,7 +88,7 @@ empty commit`
assert.NotNil(t, gitRepo)
defer gitRepo.Close()
commitFromReader, err := CommitFromReader(gitRepo, sha, strings.NewReader(commitString))
commitFromReader, err := CommitFromReader(sha, strings.NewReader(commitString))
assert.NoError(t, err)
require.NotNil(t, commitFromReader)
assert.EqualValues(t, sha, commitFromReader.ID)
@ -116,7 +116,7 @@ committer silverwind <me@silverwind.io> 1563741793 +0200
empty commit`, commitFromReader.Signature.Payload)
assert.Equal(t, "silverwind <me@silverwind.io>", commitFromReader.Author.String())
commitFromReader2, err := CommitFromReader(gitRepo, sha, strings.NewReader(commitString+"\n\n"))
commitFromReader2, err := CommitFromReader(sha, strings.NewReader(commitString+"\n\n"))
assert.NoError(t, err)
commitFromReader.CommitMessage += "\n\n"
commitFromReader.Signature.Payload += "\n\n"
@ -152,7 +152,7 @@ ISO-8859-1`
assert.NotNil(t, gitRepo)
defer gitRepo.Close()
commitFromReader, err := CommitFromReader(gitRepo, sha, strings.NewReader(commitString))
commitFromReader, err := CommitFromReader(sha, strings.NewReader(commitString))
assert.NoError(t, err)
require.NotNil(t, commitFromReader)
assert.EqualValues(t, sha, commitFromReader.ID)
@ -179,7 +179,7 @@ encoding ISO-8859-1
ISO-8859-1`, commitFromReader.Signature.Payload)
assert.Equal(t, "KN4CK3R <admin@oldschoolhack.me>", commitFromReader.Author.String())
commitFromReader2, err := CommitFromReader(gitRepo, sha, strings.NewReader(commitString+"\n\n"))
commitFromReader2, err := CommitFromReader(sha, strings.NewReader(commitString+"\n\n"))
assert.NoError(t, err)
commitFromReader.CommitMessage += "\n\n"
commitFromReader.Signature.Payload += "\n\n"
@ -199,15 +199,15 @@ func TestHasPreviousCommit(t *testing.T) {
parentSHA := MustIDFromString("8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2")
notParentSHA := MustIDFromString("2839944139e0de9737a044f78b0e4b40d989a9e3")
haz, err := commit.HasPreviousCommit(parentSHA)
haz, err := repo.HasPreviousCommit(commit, parentSHA)
assert.NoError(t, err)
assert.True(t, haz)
hazNot, err := commit.HasPreviousCommit(notParentSHA)
hazNot, err := repo.HasPreviousCommit(commit, notParentSHA)
assert.NoError(t, err)
assert.False(t, hazNot)
selfNot, err := commit.HasPreviousCommit(commit.ID)
selfNot, err := repo.HasPreviousCommit(commit, commit.ID)
assert.NoError(t, err)
assert.False(t, selfNot)
}

View File

@ -65,7 +65,7 @@ func GetRepoRawDiffForFile(repo *Repository, startCommit, endCommit string, diff
} else if commit.ParentCount() == 0 {
cmd.AddArguments("show").AddDynamicArguments(endCommit).AddDashesAndList(files...)
} else {
c, err := commit.Parent(0)
c, err := repo.ParentCommit(commit, 0)
if err != nil {
return err
}
@ -78,7 +78,7 @@ func GetRepoRawDiffForFile(repo *Repository, startCommit, endCommit string, diff
} else if commit.ParentCount() == 0 {
cmd.AddArguments("format-patch", "--no-signature", "--stdout", "--root").AddDynamicArguments(endCommit).AddDashesAndList(files...)
} else {
c, err := commit.Parent(0)
c, err := repo.ParentCommit(commit, 0)
if err != nil {
return err
}

View File

@ -48,7 +48,7 @@ func GetLanguageStats(repo *git.Repository, commitID string) (map[string]int64,
return nil, git.ErrNotExist{ID: commitID}
}
commit, err := git.CommitFromReader(repo, sha, io.LimitReader(batchReader, size))
commit, err := git.CommitFromReader(sha, io.LimitReader(batchReader, size))
if err != nil {
log.Debug("Unable to get commit for: %s. Err: %v", commitID, err)
return nil, err
@ -57,7 +57,7 @@ func GetLanguageStats(repo *git.Repository, commitID string) (map[string]int64,
return nil, err
}
tree := commit.Tree
tree := git.NewTree(repo, commit.TreeID)
entries, err := tree.ListEntriesRecursiveWithSize()
if err != nil {

View File

@ -13,21 +13,21 @@ import (
)
// CacheCommit will cache the commit from the gitRepository
func (c *Commit) CacheCommit(ctx context.Context) error {
if c.repo.LastCommitCache == nil {
func (repo *Repository) CacheCommit(ctx context.Context, c *Commit) error {
if repo.LastCommitCache == nil {
return nil
}
commitNodeIndex, _ := c.repo.CommitNodeIndex()
commitNodeIndex, _ := repo.CommitNodeIndex()
index, err := commitNodeIndex.Get(plumbing.Hash(c.ID.RawValue()))
if err != nil {
return err
}
return c.recursiveCache(ctx, index, &c.Tree, "", 1)
return repo.recursiveCache(ctx, c, index, NewTree(repo, c.TreeID), "", 1)
}
func (c *Commit) recursiveCache(ctx context.Context, index cgobject.CommitNode, tree *Tree, treePath string, level int) error {
func (repo *Repository) recursiveCache(ctx context.Context, c *Commit, index cgobject.CommitNode, tree *Tree, treePath string, level int) error {
if level == 0 {
return nil
}
@ -44,7 +44,7 @@ func (c *Commit) recursiveCache(ctx context.Context, index cgobject.CommitNode,
entryMap[entry.Name()] = entry
}
commits, err := GetLastCommitForPaths(ctx, c.repo.LastCommitCache, index, treePath, entryPaths)
commits, err := GetLastCommitForPaths(ctx, repo.LastCommitCache, index, treePath, entryPaths)
if err != nil {
return err
}
@ -55,7 +55,7 @@ func (c *Commit) recursiveCache(ctx context.Context, index cgobject.CommitNode,
if err != nil {
return err
}
if err := c.recursiveCache(ctx, index, subTree, entry, level-1); err != nil {
if err := repo.recursiveCache(ctx, c, index, subTree, entry, level-1); err != nil {
return err
}
}

View File

@ -10,14 +10,14 @@ import (
)
// CacheCommit will cache the commit from the gitRepository
func (c *Commit) CacheCommit(ctx context.Context) error {
if c.repo.LastCommitCache == nil {
func (repo *Repository) CacheCommit(ctx context.Context, c *Commit) error {
if repo.LastCommitCache == nil {
return nil
}
return c.recursiveCache(ctx, &c.Tree, "", 1)
return repo.recursiveCache(ctx, c, NewTree(repo, c.TreeID), "", 1)
}
func (c *Commit) recursiveCache(ctx context.Context, tree *Tree, treePath string, level int) error {
func (repo *Repository) recursiveCache(ctx context.Context, c *Commit, tree *Tree, treePath string, level int) error {
if level == 0 {
return nil
}
@ -32,7 +32,7 @@ func (c *Commit) recursiveCache(ctx context.Context, tree *Tree, treePath string
entryPaths[i] = entry.Name()
}
_, err = WalkGitLog(ctx, c.repo, c, treePath, entryPaths...)
_, err = WalkGitLog(ctx, repo, c, treePath, entryPaths...)
if err != nil {
return err
}
@ -44,7 +44,7 @@ func (c *Commit) recursiveCache(ctx context.Context, tree *Tree, treePath string
if err != nil {
return err
}
if err := c.recursiveCache(ctx, subTree, treeEntry.Name(), level-1); err != nil {
if err := repo.recursiveCache(ctx, c, subTree, treeEntry.Name(), level-1); err != nil {
return err
}
}

View File

@ -298,7 +298,7 @@ func (g *LogNameStatusRepoParser) Close() {
func WalkGitLog(ctx context.Context, repo *Repository, head *Commit, treepath string, paths ...string) (map[string]string, error) {
headRef := head.ID.String()
tree, err := head.SubTree(treepath)
tree, err := NewTree(repo, head.TreeID).SubTree(treepath)
if err != nil {
return nil, err
}

View File

@ -30,7 +30,13 @@ func GetNote(ctx context.Context, repo *Repository, commitID string, note *Note)
remainingCommitID := commitID
path := ""
currentTree := notes.Tree.gogitTree
tree := NewTree(repo, notes.TreeID)
if err := tree.loadTreeObject(); err != nil {
log.Error("Unable to get git tree for notes commit %q. Error: %v", notes.ID, err)
return err
}
currentTree := tree.gogitTree
log.Trace("Found tree with ID %q while searching for git note corresponding to the commit %q", currentTree.Entries[0].Name, commitID)
var file *object.File
for len(remainingCommitID) > 2 {

View File

@ -28,7 +28,7 @@ func GetNote(ctx context.Context, repo *Repository, commitID string, note *Note)
path := ""
tree := &notes.Tree
tree := NewTree(repo, notes.TreeID)
log.Trace("Found tree with ID %q while searching for git note corresponding to the commit %q", tree.ID, commitID)
var entry *TreeEntry
@ -80,7 +80,7 @@ func GetNote(ctx context.Context, repo *Repository, commitID string, note *Note)
path = path[idx+1:]
}
lastCommits, err := GetLastCommitForPaths(ctx, notes, treePath, []string{path})
lastCommits, err := GetLastCommitForPaths(ctx, repo, notes, treePath, []string{path})
if err != nil {
log.Error("Unable to get the commit for the path %q. Error: %v", treePath, err)
return err

View File

@ -100,7 +100,7 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err
continue
case "commit":
// Read in the commit to get its tree and in case this is one of the last used commits
curCommit, err = git.CommitFromReader(repo, git.MustIDFromString(string(commitID)), io.LimitReader(batchReader, size))
curCommit, err = git.CommitFromReader(git.MustIDFromString(string(commitID)), io.LimitReader(batchReader, size))
if err != nil {
return nil, err
}
@ -108,7 +108,7 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err
return nil, err
}
if _, err := batchStdinWriter.Write([]byte(curCommit.Tree.ID.String() + "\n")); err != nil {
if _, err := batchStdinWriter.Write([]byte(curCommit.TreeID.String() + "\n")); err != nil {
return nil, err
}
curPath = ""

View File

@ -6,8 +6,10 @@ package git
import (
"bytes"
"errors"
"io"
"os"
"os/exec"
"strconv"
"strings"
@ -77,8 +79,8 @@ func (repo *Repository) getCommitByPathWithID(id ObjectID, relpath string) (*Com
return repo.getCommit(id)
}
// GetCommitByPath returns the last commit of relative path.
func (repo *Repository) GetCommitByPath(relpath string) (*Commit, error) {
// GetCommitByPathDefaultBranch returns the last commit of relative path.
func (repo *Repository) GetCommitByPathDefaultBranch(relpath string) (*Commit, error) {
stdout, _, runErr := gitcmd.NewCommand("log", "-1", prettyLogFormat).
AddDashesAndList(relpath).
WithDir(repo.Path).
@ -97,8 +99,8 @@ func (repo *Repository) GetCommitByPath(relpath string) (*Commit, error) {
return commits[0], nil
}
// commitsByRangeWithTime returns the specific page commits before current revision, with not, since, until support
func (repo *Repository) commitsByRangeWithTime(id ObjectID, page, pageSize int, not, since, until string) ([]*Commit, error) {
// CommitsByRangeWithTime returns the specific page commits before current revision, with not, since, until support
func (repo *Repository) CommitsByRangeWithTime(id ObjectID, page, pageSize int, not, since, until string) ([]*Commit, error) {
cmd := gitcmd.NewCommand("log").
AddOptionFormat("--skip=%d", (page-1)*pageSize).
AddOptionFormat("--max-count=%d", pageSize).
@ -123,7 +125,8 @@ func (repo *Repository) commitsByRangeWithTime(id ObjectID, page, pageSize int,
return repo.parsePrettyFormatLogToList(stdout)
}
func (repo *Repository) searchCommits(id ObjectID, opts SearchCommitsOptions) ([]*Commit, error) {
// SearchCommits returns the commits match the keyword before current revision
func (repo *Repository) SearchCommits(id ObjectID, opts SearchCommitsOptions) ([]*Commit, error) {
// add common arguments to git command
addCommonSearchArgs := func(c *gitcmd.Command) {
// ignore case
@ -487,11 +490,13 @@ func (repo *Repository) commitsBefore(id ObjectID, limit int) ([]*Commit, error)
return commits, nil
}
func (repo *Repository) getCommitsBefore(id ObjectID) ([]*Commit, error) {
// CommitsBefore returns all the commits before current revision
func (repo *Repository) CommitsBefore(id ObjectID) ([]*Commit, error) {
return repo.commitsBefore(id, 0)
}
func (repo *Repository) getCommitsBeforeLimit(id ObjectID, num int) ([]*Commit, error) {
// CommitsBeforeLimit returns num commits before current revision
func (repo *Repository) CommitsBeforeLimit(id ObjectID, num int) ([]*Commit, error) {
return repo.commitsBefore(id, num)
}
@ -567,11 +572,7 @@ func (repo *Repository) IsCommitInBranch(commitID, branch string) (r bool, err e
func (repo *Repository) AddLastCommitCache(cacheKey, fullName, sha string) error {
if repo.LastCommitCache == nil {
commitsCount, err := cache.GetInt64(cacheKey, func() (int64, error) {
commit, err := repo.GetCommit(sha)
if err != nil {
return 0, err
}
return commit.CommitsCount()
return repo.CommitsCount(sha)
})
if err != nil {
return err
@ -611,3 +612,104 @@ func (repo *Repository) GetCommitBranchStart(env []string, branch, endCommitID s
return "", nil
}
// Parent returns n-th parent (0-based index) of the commit.
func (repo *Repository) ParentCommit(c *Commit, n int) (*Commit, error) {
id, err := c.ParentID(n)
if err != nil {
return nil, err
}
parent, err := repo.getCommit(id)
if err != nil {
return nil, err
}
return parent, nil
}
// GetCommitByPath return the commit of relative path object.
func (repo *Repository) GetCommitByPath(commitID ObjectID, relpath string) (*Commit, error) {
if repo.LastCommitCache != nil {
return repo.LastCommitCache.GetCommitByPath(commitID.String(), relpath)
}
return repo.getCommitByPathWithID(commitID, relpath)
}
// CommitsCount returns number of total commits of until current revision.
func (repo *Repository) CommitsCount(commitID string) (int64, error) {
return CommitsCount(repo.Ctx, CommitsCountOptions{
RepoPath: repo.Path,
Revision: []string{commitID},
})
}
// HasPreviousCommit returns true if a given commitHash is contained in commit's parents
func (repo *Repository) HasPreviousCommit(c *Commit, objectID ObjectID) (bool, error) {
this := c.ID.String()
that := objectID.String()
if this == that {
return false, nil
}
_, _, err := gitcmd.NewCommand("merge-base", "--is-ancestor").AddDynamicArguments(that, this).
WithDir(repo.Path).
RunStdString(repo.Ctx)
if err == nil {
return true, nil
}
var exitError *exec.ExitError
if errors.As(err, &exitError) {
if exitError.ProcessState.ExitCode() == 1 && len(exitError.Stderr) == 0 {
return false, nil
}
}
return false, err
}
// IsForcePush returns true if a push from oldCommitHash to this is a force push
func (repo *Repository) IsForcePush(c *Commit, oldCommitID string) (bool, error) {
objectFormat, err := repo.GetObjectFormat()
if err != nil {
return false, err
}
if oldCommitID == objectFormat.EmptyObjectID().String() {
return false, nil
}
oldCommit, err := repo.GetCommit(oldCommitID)
if err != nil {
return false, err
}
hasPreviousCommit, err := repo.HasPreviousCommit(c, oldCommit.ID)
return !hasPreviousCommit, err
}
// CommitsBeforeUntil returns the commits between commitID to current revision
func (repo *Repository) CommitsBeforeUntil(c *Commit, commitID string) ([]*Commit, error) {
endCommit, err := repo.GetCommit(commitID)
if err != nil {
return nil, err
}
return repo.CommitsBetween(c, endCommit)
}
// GetClosestBranchName gets the closest branch name (as returned by 'git name-rev --name-only')
func (repo *Repository) GetClosestBranchName(c *Commit) (string, error) {
cmd := gitcmd.NewCommand("name-rev")
if DefaultFeatures().CheckVersionAtLeast("2.13.0") {
cmd.AddArguments("--exclude", "refs/tags/*")
}
cmd.AddArguments("--name-only", "--no-undefined").AddDynamicArguments(c.ID.String())
data, _, err := cmd.WithDir(repo.Path).RunStdString(repo.Ctx)
if err != nil {
// handle special case where git can not describe commit
if strings.Contains(err.Error(), "cannot describe") {
return "", nil
}
return "", err
}
// name-rev commitID output will be "master" or "master~12"
return strings.SplitN(strings.TrimSpace(data), "~", 2)[0], nil
}

View File

@ -98,16 +98,5 @@ func (repo *Repository) getCommit(id ObjectID) (*Commit, error) {
return nil, err
}
commit := convertCommit(gogitCommit)
commit.repo = repo
tree, err := gogitCommit.Tree()
if err != nil {
return nil, err
}
commit.Tree.ID = ParseGogitHash(tree.Hash)
commit.Tree.gogitTree = tree
return commit, nil
return convertCommit(gogitCommit), nil
}

View File

@ -118,7 +118,7 @@ func (repo *Repository) getCommitFromBatchReader(wr WriteCloserError, rd *bufio.
return commit, nil
case "commit":
commit, err := CommitFromReader(repo, id, io.LimitReader(rd, size))
commit, err := CommitFromReader(id, io.LimitReader(rd, size))
if err != nil {
return nil, err
}

View File

@ -43,18 +43,20 @@ func (repo *Repository) getTree(id ObjectID) (*Tree, error) {
if err != nil {
return nil, err
}
commit.Tree.ResolvedID = resolvedID
return &commit.Tree, nil
tree := NewTree(repo, commit.TreeID)
tree.ResolvedID = resolvedID
return tree, nil
case "commit":
commit, err := CommitFromReader(repo, id, io.LimitReader(rd, size))
commit, err := CommitFromReader(id, io.LimitReader(rd, size))
if err != nil {
return nil, err
}
if _, err := rd.Discard(1); err != nil {
return nil, err
}
commit.Tree.ResolvedID = commit.ID
return &commit.Tree, nil
tree := NewTree(repo, commit.TreeID)
tree.ResolvedID = commit.ID
return tree, nil
case "tree":
tree := NewTree(repo, id)
tree.ResolvedID = id

View File

@ -3,65 +3,50 @@
package git
import (
"bufio"
"context"
"fmt"
"os"
"code.gitea.io/gitea/modules/git/gitcmd"
"code.gitea.io/gitea/modules/log"
)
type TemplateSubmoduleCommit struct {
Path string
Commit string
type SubmoduleWebLink struct {
RepoWebLink, CommitWebLink string
}
// GetTemplateSubmoduleCommits returns a list of submodules paths and their commits from a repository
// This function is only for generating new repos based on existing template, the template couldn't be too large.
func GetTemplateSubmoduleCommits(ctx context.Context, repoPath string) (submoduleCommits []TemplateSubmoduleCommit, _ error) {
stdoutReader, stdoutWriter, err := os.Pipe()
// GetSubModules get all the submodules of current revision git tree
func (t *Tree) GetSubModules() (*ObjectCache[*SubModule], error) {
if t.submoduleCache != nil {
return t.submoduleCache, nil
}
entry, err := t.GetTreeEntryByPath(".gitmodules")
if err != nil {
if _, ok := err.(ErrNotExist); ok {
return nil, nil
}
return nil, err
}
rd, err := entry.Blob().DataAsync()
if err != nil {
return nil, err
}
defer rd.Close()
// at the moment we do not strictly limit the size of the .gitmodules file because some users would have huge .gitmodules files (>1MB)
t.submoduleCache, err = configParseSubModules(rd)
if err != nil {
return nil, err
}
return t.submoduleCache, nil
}
// GetSubModule gets the submodule by the entry name.
// It returns "nil, nil" if the submodule does not exist, caller should always remember to check the "nil"
func (t *Tree) GetSubModule(entryName string) (*SubModule, error) {
modules, err := t.GetSubModules()
if err != nil {
return nil, err
}
err = gitcmd.NewCommand("ls-tree", "-r", "--", "HEAD").
WithDir(repoPath).
WithStdout(stdoutWriter).
WithPipelineFunc(func(ctx context.Context, cancel context.CancelFunc) error {
_ = stdoutWriter.Close()
defer stdoutReader.Close()
scanner := bufio.NewScanner(stdoutReader)
for scanner.Scan() {
entry, err := parseLsTreeLine(scanner.Bytes())
if err != nil {
cancel()
return err
}
if entry.EntryMode == EntryModeCommit {
submoduleCommits = append(submoduleCommits, TemplateSubmoduleCommit{Path: entry.Name, Commit: entry.ID.String()})
}
}
return scanner.Err()
}).
Run(ctx)
if err != nil {
return nil, fmt.Errorf("GetTemplateSubmoduleCommits: error running git ls-tree: %v", err)
}
return submoduleCommits, nil
}
// AddTemplateSubmoduleIndexes Adds the given submodules to the git index.
// It is only for generating new repos based on existing template, requires the .gitmodules file to be already present in the work dir.
func AddTemplateSubmoduleIndexes(ctx context.Context, repoPath string, submodules []TemplateSubmoduleCommit) error {
for _, submodule := range submodules {
cmd := gitcmd.NewCommand("update-index", "--add", "--cacheinfo", "160000").AddDynamicArguments(submodule.Commit, submodule.Path)
if stdout, _, err := cmd.WithDir(repoPath).RunStdString(ctx); err != nil {
log.Error("Unable to add %s as submodule to repo %s: stdout %s\nError: %v", submodule.Path, repoPath, stdout, err)
return err
if modules != nil {
if module, has := modules.Get(entryName); has {
return module, nil
}
}
return nil
return nil, nil
}

View File

@ -13,8 +13,8 @@ import (
"code.gitea.io/gitea/modules/util"
)
// CommitSubmoduleFile represents a file with submodule type.
type CommitSubmoduleFile struct {
// SubmoduleFile represents a file with submodule type.
type SubmoduleFile struct {
repoLink string
fullPath string
refURL string
@ -24,20 +24,20 @@ type CommitSubmoduleFile struct {
parsedTargetLink string
}
// NewCommitSubmoduleFile create a new submodule file
func NewCommitSubmoduleFile(repoLink, fullPath, refURL, refID string) *CommitSubmoduleFile {
return &CommitSubmoduleFile{repoLink: repoLink, fullPath: fullPath, refURL: refURL, refID: refID}
// NewSubmoduleFile create a new submodule file
func NewSubmoduleFile(repoLink, fullPath, refURL, refID string) *SubmoduleFile {
return &SubmoduleFile{repoLink: repoLink, fullPath: fullPath, refURL: refURL, refID: refID}
}
// RefID returns the commit ID of the submodule, it returns empty string for nil receiver
func (sf *CommitSubmoduleFile) RefID() string {
func (sf *SubmoduleFile) RefID() string {
if sf == nil {
return ""
}
return sf.refID
}
func (sf *CommitSubmoduleFile) getWebLinkInTargetRepo(ctx context.Context, moreLinkPath string) *SubmoduleWebLink {
func (sf *SubmoduleFile) getWebLinkInTargetRepo(ctx context.Context, moreLinkPath string) *SubmoduleWebLink {
if sf == nil || sf.refURL == "" {
return nil
}
@ -58,12 +58,12 @@ func (sf *CommitSubmoduleFile) getWebLinkInTargetRepo(ctx context.Context, moreL
// SubmoduleWebLinkTree tries to make the submodule's tree link in its own repo, it also works on "nil" receiver
// It returns nil if the submodule does not have a valid URL or is nil
func (sf *CommitSubmoduleFile) SubmoduleWebLinkTree(ctx context.Context, optCommitID ...string) *SubmoduleWebLink {
func (sf *SubmoduleFile) SubmoduleWebLinkTree(ctx context.Context, optCommitID ...string) *SubmoduleWebLink {
return sf.getWebLinkInTargetRepo(ctx, "/tree/"+util.OptionalArg(optCommitID, sf.RefID()))
}
// SubmoduleWebLinkCompare tries to make the submodule's compare link in its own repo, it also works on "nil" receiver
// It returns nil if the submodule does not have a valid URL or is nil
func (sf *CommitSubmoduleFile) SubmoduleWebLinkCompare(ctx context.Context, commitID1, commitID2 string) *SubmoduleWebLink {
func (sf *SubmoduleFile) SubmoduleWebLinkCompare(ctx context.Context, commitID1, commitID2 string) *SubmoduleWebLink {
return sf.getWebLinkInTargetRepo(ctx, "/compare/"+commitID1+"..."+commitID2)
}

View File

@ -9,14 +9,14 @@ import (
"github.com/stretchr/testify/assert"
)
func TestCommitSubmoduleLink(t *testing.T) {
assert.Nil(t, (*CommitSubmoduleFile)(nil).SubmoduleWebLinkTree(t.Context()))
assert.Nil(t, (*CommitSubmoduleFile)(nil).SubmoduleWebLinkCompare(t.Context(), "", ""))
assert.Nil(t, (&CommitSubmoduleFile{}).SubmoduleWebLinkTree(t.Context()))
assert.Nil(t, (&CommitSubmoduleFile{}).SubmoduleWebLinkCompare(t.Context(), "", ""))
func TestSubmoduleLink(t *testing.T) {
assert.Nil(t, (*SubmoduleFile)(nil).SubmoduleWebLinkTree(t.Context()))
assert.Nil(t, (*SubmoduleFile)(nil).SubmoduleWebLinkCompare(t.Context(), "", ""))
assert.Nil(t, (&SubmoduleFile{}).SubmoduleWebLinkTree(t.Context()))
assert.Nil(t, (&SubmoduleFile{}).SubmoduleWebLinkCompare(t.Context(), "", ""))
t.Run("GitHubRepo", func(t *testing.T) {
sf := NewCommitSubmoduleFile("/any/repo-link", "full-path", "git@github.com:user/repo.git", "aaaa")
sf := NewSubmoduleFile("/any/repo-link", "full-path", "git@github.com:user/repo.git", "aaaa")
wl := sf.SubmoduleWebLinkTree(t.Context())
assert.Equal(t, "https://github.com/user/repo", wl.RepoWebLink)
assert.Equal(t, "https://github.com/user/repo/tree/aaaa", wl.CommitWebLink)
@ -27,12 +27,12 @@ func TestCommitSubmoduleLink(t *testing.T) {
})
t.Run("RelativePath", func(t *testing.T) {
sf := NewCommitSubmoduleFile("/subpath/any/repo-home-link", "full-path", "../../user/repo", "aaaa")
sf := NewSubmoduleFile("/subpath/any/repo-home-link", "full-path", "../../user/repo", "aaaa")
wl := sf.SubmoduleWebLinkTree(t.Context())
assert.Equal(t, "/subpath/user/repo", wl.RepoWebLink)
assert.Equal(t, "/subpath/user/repo/tree/aaaa", wl.CommitWebLink)
sf = NewCommitSubmoduleFile("/subpath/any/repo-home-link", "dir/submodule", "../../user/repo", "aaaa")
sf = NewSubmoduleFile("/subpath/any/repo-home-link", "dir/submodule", "../../user/repo", "aaaa")
wl = sf.SubmoduleWebLinkCompare(t.Context(), "1111", "2222")
assert.Equal(t, "/subpath/user/repo", wl.RepoWebLink)
assert.Equal(t, "/subpath/user/repo/compare/1111...2222", wl.CommitWebLink)

View File

@ -0,0 +1,67 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package git
import (
"bufio"
"context"
"fmt"
"os"
"code.gitea.io/gitea/modules/git/gitcmd"
"code.gitea.io/gitea/modules/log"
)
type TemplateSubmoduleCommit struct {
Path string
Commit string
}
// GetTemplateSubmoduleCommits returns a list of submodules paths and their commits from a repository
// This function is only for generating new repos based on existing template, the template couldn't be too large.
func GetTemplateSubmoduleCommits(ctx context.Context, repoPath string) (submoduleCommits []TemplateSubmoduleCommit, _ error) {
stdoutReader, stdoutWriter, err := os.Pipe()
if err != nil {
return nil, err
}
err = gitcmd.NewCommand("ls-tree", "-r", "--", "HEAD").
WithDir(repoPath).
WithStdout(stdoutWriter).
WithPipelineFunc(func(ctx context.Context, cancel context.CancelFunc) error {
_ = stdoutWriter.Close()
defer stdoutReader.Close()
scanner := bufio.NewScanner(stdoutReader)
for scanner.Scan() {
entry, err := parseLsTreeLine(scanner.Bytes())
if err != nil {
cancel()
return err
}
if entry.EntryMode == EntryModeCommit {
submoduleCommits = append(submoduleCommits, TemplateSubmoduleCommit{Path: entry.Name, Commit: entry.ID.String()})
}
}
return scanner.Err()
}).
Run(ctx)
if err != nil {
return nil, fmt.Errorf("GetTemplateSubmoduleCommits: error running git ls-tree: %v", err)
}
return submoduleCommits, nil
}
// AddTemplateSubmoduleIndexes Adds the given submodules to the git index.
// It is only for generating new repos based on existing template, requires the .gitmodules file to be already present in the work dir.
func AddTemplateSubmoduleIndexes(ctx context.Context, repoPath string, submodules []TemplateSubmoduleCommit) error {
for _, submodule := range submodules {
cmd := gitcmd.NewCommand("update-index", "--add", "--cacheinfo", "160000").AddDynamicArguments(submodule.Commit, submodule.Path)
if stdout, _, err := cmd.WithDir(repoPath).RunStdString(ctx); err != nil {
log.Error("Unable to add %s as submodule to repo %s: stdout %s\nError: %v", submodule.Path, repoPath, stdout, err)
return err
}
}
return nil
}

View File

@ -6,9 +6,11 @@ package git
import (
"bytes"
"io"
"strings"
"code.gitea.io/gitea/modules/git/gitcmd"
"code.gitea.io/gitea/modules/util"
)
// NewTree create a new tree according the repository and tree id
@ -76,3 +78,32 @@ func (repo *Repository) GetTreePathLatestCommit(refName, treePath string) (*Comm
}
return repo.GetCommit(strings.TrimSpace(stdout))
}
// GetFileContent reads a file content as a string or returns false if this was not possible
func (t *Tree) GetFileContent(filename string, limit int) (string, error) {
entry, err := t.GetTreeEntryByPath(filename)
if err != nil {
return "", err
}
r, err := entry.Blob().DataAsync()
if err != nil {
return "", err
}
defer r.Close()
if limit > 0 {
bs := make([]byte, limit)
n, err := util.ReadAtMost(r, bs)
if err != nil {
return "", err
}
return string(bs[:n]), nil
}
bytes, err := io.ReadAll(r)
if err != nil {
return "", err
}
return string(bytes), nil
}

View File

@ -30,7 +30,7 @@ type EntryFollowResult struct {
TargetEntry *TreeEntry
}
func EntryFollowLink(commit *Commit, fullPath string, te *TreeEntry) (*EntryFollowResult, error) {
func EntryFollowLink(tree *Tree, fullPath string, te *TreeEntry) (*EntryFollowResult, error) {
if !te.IsLink() {
return nil, util.ErrorWrap(util.ErrUnprocessableContent, "%q is not a symlink", fullPath)
}
@ -51,18 +51,18 @@ func EntryFollowLink(commit *Commit, fullPath string, te *TreeEntry) (*EntryFoll
}
targetFullPath := path.Join(path.Dir(fullPath), link)
targetEntry, err := commit.GetTreeEntryByPath(targetFullPath)
targetEntry, err := tree.GetTreeEntryByPath(targetFullPath)
if err != nil {
return &EntryFollowResult{SymlinkContent: link}, err
}
return &EntryFollowResult{SymlinkContent: link, TargetFullPath: targetFullPath, TargetEntry: targetEntry}, nil
}
func EntryFollowLinks(commit *Commit, firstFullPath string, firstTreeEntry *TreeEntry, optLimit ...int) (res *EntryFollowResult, err error) {
func EntryFollowLinks(tree *Tree, firstFullPath string, firstTreeEntry *TreeEntry, optLimit ...int) (res *EntryFollowResult, err error) {
limit := util.OptionalArg(optLimit, 10)
treeEntry, fullPath := firstTreeEntry, firstFullPath
for range limit {
res, err = EntryFollowLink(commit, fullPath, treeEntry)
res, err = EntryFollowLink(tree, fullPath, treeEntry)
if err != nil {
return res, err
}

View File

@ -20,15 +20,17 @@ func TestFollowLink(t *testing.T) {
commit, err := r.GetCommit("37991dec2c8e592043f47155ce4808d4580f9123")
require.NoError(t, err)
tree := NewTree(r, commit.TreeID)
// get the symlink
{
lnkFullPath := "foo/bar/link_to_hello"
lnk, err := commit.Tree.GetTreeEntryByPath("foo/bar/link_to_hello")
lnk, err := tree.GetTreeEntryByPath("foo/bar/link_to_hello")
require.NoError(t, err)
assert.True(t, lnk.IsLink())
// should be able to dereference to target
res, err := EntryFollowLink(commit, lnkFullPath, lnk)
res, err := EntryFollowLink(tree, lnkFullPath, lnk)
require.NoError(t, err)
assert.Equal(t, "hello", res.TargetEntry.Name())
assert.Equal(t, "foo/nar/hello", res.TargetFullPath)
@ -38,38 +40,38 @@ func TestFollowLink(t *testing.T) {
{
// should error when called on a normal file
entry, err := commit.Tree.GetTreeEntryByPath("file1.txt")
entry, err := tree.GetTreeEntryByPath("file1.txt")
require.NoError(t, err)
res, err := EntryFollowLink(commit, "file1.txt", entry)
res, err := EntryFollowLink(tree, "file1.txt", entry)
assert.ErrorIs(t, err, util.ErrUnprocessableContent)
assert.Nil(t, res)
}
{
// should error for broken links
entry, err := commit.Tree.GetTreeEntryByPath("foo/broken_link")
entry, err := tree.GetTreeEntryByPath("foo/broken_link")
require.NoError(t, err)
assert.True(t, entry.IsLink())
res, err := EntryFollowLink(commit, "foo/broken_link", entry)
res, err := EntryFollowLink(tree, "foo/broken_link", entry)
assert.ErrorIs(t, err, util.ErrNotExist)
assert.Equal(t, "nar/broken_link", res.SymlinkContent)
}
{
// should error for external links
entry, err := commit.Tree.GetTreeEntryByPath("foo/outside_repo")
entry, err := tree.GetTreeEntryByPath("foo/outside_repo")
require.NoError(t, err)
assert.True(t, entry.IsLink())
res, err := EntryFollowLink(commit, "foo/outside_repo", entry)
res, err := EntryFollowLink(tree, "foo/outside_repo", entry)
assert.ErrorIs(t, err, util.ErrNotExist)
assert.Equal(t, "../../outside_repo", res.SymlinkContent)
}
{
// testing fix for short link bug
entry, err := commit.Tree.GetTreeEntryByPath("foo/link_short")
entry, err := tree.GetTreeEntryByPath("foo/link_short")
require.NoError(t, err)
res, err := EntryFollowLink(commit, "foo/link_short", entry)
res, err := EntryFollowLink(tree, "foo/link_short", entry)
assert.ErrorIs(t, err, util.ErrNotExist)
assert.Equal(t, "a", res.SymlinkContent)
}

View File

@ -7,6 +7,8 @@
package git
import (
"code.gitea.io/gitea/modules/log"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/filemode"
"github.com/go-git/go-git/v5/plumbing/object"
@ -41,6 +43,11 @@ func (te *TreeEntry) Size() int64 {
return te.size
}
if err := te.ptree.loadTreeObject(); err != nil {
log.Error("Unable to load tree object: %v", err)
return 0
}
file, err := te.ptree.gogitTree.TreeEntryFile(te.gogitTreeEntry)
if err != nil {
return 0

View File

@ -23,9 +23,14 @@ type Tree struct {
// parent tree
ptree *Tree
submoduleCache *ObjectCache[*SubModule]
}
func (t *Tree) loadTreeObject() error {
if t.gogitTree != nil {
return nil
}
gogitTree, err := t.repo.gogitRepo.TreeObject(plumbing.Hash(t.ID.RawValue()))
if err != nil {
return err
@ -37,11 +42,8 @@ func (t *Tree) loadTreeObject() error {
// ListEntries returns all entries of current tree.
func (t *Tree) ListEntries() (Entries, error) {
if t.gogitTree == nil {
err := t.loadTreeObject()
if err != nil {
return nil, err
}
if err := t.loadTreeObject(); err != nil {
return nil, err
}
entries := make([]*TreeEntry, len(t.gogitTree.Entries))
@ -58,11 +60,9 @@ func (t *Tree) ListEntries() (Entries, error) {
// ListEntriesRecursiveWithSize returns all entries of current tree recursively including all subtrees
func (t *Tree) ListEntriesRecursiveWithSize() (Entries, error) {
if t.gogitTree == nil {
err := t.loadTreeObject()
if err != nil {
return nil, err
}
err := t.loadTreeObject()
if err != nil {
return nil, err
}
var entries []*TreeEntry

View File

@ -26,6 +26,8 @@ type Tree struct {
entriesRecursive Entries
entriesRecursiveParsed bool
submoduleCache *ObjectCache[*SubModule]
}
// ListEntries returns all entries of current tree.

View File

@ -18,9 +18,11 @@ func TestSubTree_Issue29101(t *testing.T) {
commit, err := repo.GetCommit("ce064814f4a0d337b333e646ece456cd39fab612")
assert.NoError(t, err)
tree := NewTree(repo, commit.TreeID)
// old code could produce a different error if called multiple times
for range 10 {
_, err = commit.SubTree("file1.txt")
_, err = tree.SubTree("file1.txt")
assert.Error(t, err)
assert.True(t, IsErrNotExist(err))
}

View File

@ -47,8 +47,8 @@ func UnmarshalFromEntry(entry *git.TreeEntry, dir string) (*api.IssueTemplate, e
}
// UnmarshalFromCommit parses out a valid template from the commit
func UnmarshalFromCommit(commit *git.Commit, filename string) (*api.IssueTemplate, error) {
entry, err := commit.GetTreeEntryByPath(filename)
func UnmarshalFromCommit(tree *git.Tree, filename string) (*api.IssueTemplate, error) {
entry, err := tree.GetTreeEntryByPath(filename)
if err != nil {
return nil, fmt.Errorf("get entry for %q: %w", filename, err)
}
@ -62,7 +62,7 @@ func UnmarshalFromRepo(repo *git.Repository, branch, filename string) (*api.Issu
return nil, fmt.Errorf("get commit on branch %q: %w", branch, err)
}
return UnmarshalFromCommit(commit, filename)
return UnmarshalFromCommit(git.NewTree(repo, commit.TreeID), filename)
}
func unmarshalFromEntry(entry *git.TreeEntry, filename string) (*api.IssueTemplate, error) {

View File

@ -80,7 +80,7 @@ func GetBranch(ctx *context.APIContext) {
return
}
br, err := convert.ToBranch(ctx, ctx.Repo.Repository, branchName, c, branchProtection, ctx.Doer, ctx.Repo.IsAdmin())
br, err := convert.ToBranch(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, branchName, c, branchProtection, ctx.Doer, ctx.Repo.IsAdmin())
if err != nil {
ctx.APIErrorInternal(err)
return
@ -271,7 +271,7 @@ func CreateBranch(ctx *context.APIContext) {
return
}
br, err := convert.ToBranch(ctx, ctx.Repo.Repository, opt.BranchName, commit, branchProtection, ctx.Doer, ctx.Repo.IsAdmin())
br, err := convert.ToBranch(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, opt.BranchName, commit, branchProtection, ctx.Doer, ctx.Repo.IsAdmin())
if err != nil {
ctx.APIErrorInternal(err)
return
@ -366,7 +366,7 @@ func ListBranches(ctx *context.APIContext) {
}
branchProtection := rules.GetFirstMatched(branches[i].Name)
apiBranch, err := convert.ToBranch(ctx, ctx.Repo.Repository, branches[i].Name, c, branchProtection, ctx.Doer, ctx.Repo.IsAdmin())
apiBranch, err := convert.ToBranch(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, branches[i].Name, c, branchProtection, ctx.Doer, ctx.Repo.IsAdmin())
if err != nil {
ctx.APIErrorInternal(err)
return

View File

@ -235,7 +235,7 @@ func GetAllCommits(ctx *context.APIContext) {
}
// Query commits
commits, err = baseCommit.CommitsByRange(listOptions.Page, listOptions.PageSize, not, since, until)
commits, err = ctx.Repo.GitRepo.CommitsByRangeWithTime(baseCommit.ID, listOptions.Page, listOptions.PageSize, not, since, until)
if err != nil {
ctx.APIErrorInternal(err)
return

View File

@ -225,7 +225,8 @@ func GetRawFileOrLFS(ctx *context.APIContext) {
}
func getBlobForEntry(ctx *context.APIContext) (blob *git.Blob, entry *git.TreeEntry, lastModified *time.Time) {
entry, err := ctx.Repo.Commit.GetTreeEntryByPath(ctx.Repo.TreePath)
tree := git.NewTree(ctx.Repo.GitRepo, ctx.Repo.Commit.TreeID)
entry, err := tree.GetTreeEntryByPath(ctx.Repo.TreePath)
if err != nil {
if git.IsErrNotExist(err) {
ctx.APIErrorNotFound()

View File

@ -174,7 +174,7 @@ func TestHook(ctx *context.APIContext) {
return
}
commit := convert.ToPayloadCommit(ctx, ctx.Repo.Repository, ctx.Repo.Commit)
commit := convert.ToPayloadCommit(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, ctx.Repo.Commit)
commitID := ctx.Repo.Commit.ID.String()
if err := webhook_service.PrepareWebhook(ctx, hook, webhook_module.HookEventPush, &api.PushPayload{

View File

@ -57,7 +57,7 @@ func ApplyDiffPatch(ctx *context.APIContext) {
Signoff: changeRepoFileOpts.Signoff,
}
fileResponse, err := files.ApplyDiffPatch(ctx, ctx.Repo.Repository, ctx.Doer, opts)
fileResponse, err := files.ApplyDiffPatch(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, ctx.Doer, opts)
if err != nil {
handleChangeRepoFilesError(ctx, err)
} else {

View File

@ -114,7 +114,7 @@ func GetAnnotatedTag(ctx *context.APIContext) {
if err != nil {
ctx.APIError(http.StatusBadRequest, err)
}
ctx.JSON(http.StatusOK, convert.ToAnnotatedTag(ctx, ctx.Repo.Repository, tag, commit))
ctx.JSON(http.StatusOK, convert.ToAnnotatedTag(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, tag, commit))
}
}

View File

@ -177,17 +177,17 @@ func getWikiPage(ctx *context.APIContext, wikiName wiki_service.WebPath) *api.Wi
}
// lookup filename in wiki - get filecontent, real filename
content, pageFilename := wikiContentsByName(ctx, commit, wikiName, false)
content, pageFilename := wikiContentsByName(ctx, wikiRepo, commit, wikiName, false)
if ctx.Written() {
return nil
}
sidebarContent, _ := wikiContentsByName(ctx, commit, "_Sidebar", true)
sidebarContent, _ := wikiContentsByName(ctx, wikiRepo, commit, "_Sidebar", true)
if ctx.Written() {
return nil
}
footerContent, _ := wikiContentsByName(ctx, commit, "_Footer", true)
footerContent, _ := wikiContentsByName(ctx, wikiRepo, commit, "_Footer", true)
if ctx.Written() {
return nil
}
@ -196,7 +196,7 @@ func getWikiPage(ctx *context.APIContext, wikiName wiki_service.WebPath) *api.Wi
commitsCount, _ := wikiRepo.FileCommitsCount(ctx.Repo.Repository.DefaultWikiBranch, pageFilename)
// Get last change information.
lastCommit, err := wikiRepo.GetCommitByPath(pageFilename)
lastCommit, err := wikiRepo.GetCommitByPathDefaultBranch(pageFilename)
if err != nil {
ctx.APIErrorInternal(err)
return nil
@ -307,7 +307,7 @@ func ListWikiPages(ctx *context.APIContext) {
skip := (page - 1) * limit
maxNum := page * limit
entries, err := commit.ListEntries()
entries, err := git.NewTree(wikiRepo, commit.TreeID).ListEntries()
if err != nil {
ctx.APIErrorInternal(err)
return
@ -317,7 +317,7 @@ func ListWikiPages(ctx *context.APIContext) {
if i < skip || i >= maxNum || !entry.IsRegular() {
continue
}
c, err := wikiRepo.GetCommitByPath(entry.Name())
c, err := wikiRepo.GetCommitByPathDefaultBranch(entry.Name())
if err != nil {
ctx.APIErrorInternal(err)
return
@ -423,7 +423,7 @@ func ListPageRevisions(ctx *context.APIContext) {
}
// lookup filename in wiki - get filecontent, gitTree entry , real filename
_, pageFilename := wikiContentsByName(ctx, commit, pageName, false)
_, pageFilename := wikiContentsByName(ctx, wikiRepo, commit, pageName, false)
if ctx.Written() {
return
}
@ -450,8 +450,8 @@ func ListPageRevisions(ctx *context.APIContext) {
}
// findEntryForFile finds the tree entry for a target filepath.
func findEntryForFile(commit *git.Commit, target string) (*git.TreeEntry, error) {
entry, err := commit.GetTreeEntryByPath(target)
func findEntryForFile(tree *git.Tree, target string) (*git.TreeEntry, error) {
entry, err := tree.GetTreeEntryByPath(target)
if err != nil {
return nil, err
}
@ -464,7 +464,7 @@ func findEntryForFile(commit *git.Commit, target string) (*git.TreeEntry, error)
if unescapedTarget, err = url.QueryUnescape(target); err != nil {
return nil, err
}
return commit.GetTreeEntryByPath(unescapedTarget)
return tree.GetTreeEntryByPath(unescapedTarget)
}
// findWikiRepoCommit opens the wiki repo and returns the latest commit, writing to context on error.
@ -509,9 +509,9 @@ func wikiContentsByEntry(ctx *context.APIContext, entry *git.TreeEntry) string {
// wikiContentsByName returns the contents of a wiki page, along with a boolean
// indicating whether the page exists. Writes to ctx if an error occurs.
func wikiContentsByName(ctx *context.APIContext, commit *git.Commit, wikiName wiki_service.WebPath, isSidebarOrFooter bool) (string, string) {
func wikiContentsByName(ctx *context.APIContext, wikiRepo *git.Repository, commit *git.Commit, wikiName wiki_service.WebPath, isSidebarOrFooter bool) (string, string) {
gitFilename := wiki_service.WebPathToGitPath(wikiName)
entry, err := findEntryForFile(commit, gitFilename)
entry, err := findEntryForFile(git.NewTree(wikiRepo, commit.TreeID), gitFilename)
if err != nil {
if git.IsErrNotExist(err) {
if !isSidebarOrFooter {

View File

@ -90,11 +90,11 @@ func readAndVerifyCommit(sha string, repo *git.Repository, env []string) error {
WithStdout(stdoutWriter).
WithPipelineFunc(func(ctx context.Context, cancel context.CancelFunc) error {
_ = stdoutWriter.Close()
commit, err := git.CommitFromReader(repo, commitID, stdoutReader)
commit, err := git.CommitFromReader(commitID, stdoutReader)
if err != nil {
return err
}
verification := asymkey_service.ParseCommitWithSignature(ctx, commit)
verification := asymkey_service.ParseCommitWithSignature(ctx, repo, commit)
if !verification.Verified {
cancel()
return &errUnverifiedCommit{

View File

@ -19,7 +19,7 @@ func ShowBranchFeed(ctx *context.Context, repo *repo.Repository, formatType stri
var commits []*git.Commit
var err error
if ctx.Repo.Commit != nil {
commits, err = ctx.Repo.Commit.CommitsByRange(0, 10, "", "", "")
commits, err = ctx.Repo.GitRepo.CommitsByRangeWithTime(ctx.Repo.Commit.ID, 0, 10, "", "", "")
if err != nil {
ctx.ServerError("ShowBranchFeed", err)
return

View File

@ -131,7 +131,7 @@ func WorkflowDispatchInputs(ctx *context.Context) {
func prepareWorkflowTemplate(ctx *context.Context, commit *git.Commit) (workflows []WorkflowInfo, curWorkflowID string) {
curWorkflowID = ctx.FormString("workflow")
_, entries, err := actions.ListWorkflows(commit)
_, entries, err := actions.ListWorkflows(git.NewTree(ctx.Repo.GitRepo, commit.TreeID))
if err != nil {
ctx.ServerError("ListWorkflows", err)
return nil, ""

View File

@ -80,7 +80,7 @@ func ViewWorkflowFile(ctx *context_module.Context) {
}, err)
return
}
rpath, entries, err := actions.ListWorkflows(commit)
rpath, entries, err := actions.ListWorkflows(git.NewTree(ctx.Repo.GitRepo, commit.TreeID))
if err != nil {
ctx.ServerError("ListWorkflows", err)
return

View File

@ -50,7 +50,8 @@ func RefBlame(ctx *context.Context) {
ctx.NotFound(nil)
return
}
entry, err := ctx.Repo.Commit.GetTreeEntryByPath(ctx.Repo.TreePath)
tree := git.NewTree(ctx.Repo.GitRepo, ctx.Repo.Commit.TreeID)
entry, err := tree.GetTreeEntryByPath(ctx.Repo.TreePath)
if err != nil {
HandleGitError(ctx, "Repo.Commit.GetTreeEntryByPath", err)
return
@ -91,7 +92,7 @@ func RefBlame(ctx *context.Context) {
}
bypassBlameIgnore, _ := strconv.ParseBool(ctx.FormString("bypass-blame-ignore"))
result, err := performBlame(ctx, ctx.Repo.Repository, ctx.Repo.Commit, ctx.Repo.TreePath, bypassBlameIgnore)
result, err := performBlame(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, ctx.Repo.Commit, ctx.Repo.TreePath, bypassBlameIgnore)
if err != nil {
ctx.NotFound(err)
return
@ -116,10 +117,10 @@ type blameResult struct {
FaultyIgnoreRevsFile bool
}
func performBlame(ctx *context.Context, repo *repo_model.Repository, commit *git.Commit, file string, bypassBlameIgnore bool) (*blameResult, error) {
func performBlame(ctx *context.Context, repo *repo_model.Repository, gitRepo *git.Repository, commit *git.Commit, file string, bypassBlameIgnore bool) (*blameResult, error) {
objectFormat := ctx.Repo.GetObjectFormat()
blameReader, err := git.CreateBlameReader(ctx, objectFormat, repo.RepoPath(), commit, file, bypassBlameIgnore)
blameReader, err := git.CreateBlameReader(ctx, gitRepo, objectFormat, repo.RepoPath(), commit, file, bypassBlameIgnore)
if err != nil {
return nil, err
}
@ -135,7 +136,7 @@ func performBlame(ctx *context.Context, repo *repo_model.Repository, commit *git
if len(r.Parts) == 0 && r.UsesIgnoreRevs {
// try again without ignored revs
blameReader, err = git.CreateBlameReader(ctx, objectFormat, repo.RepoPath(), commit, file, true)
blameReader, err = git.CreateBlameReader(ctx, gitRepo, objectFormat, repo.RepoPath(), commit, file, true)
if err != nil {
return nil, err
}

View File

@ -76,7 +76,7 @@ func Commits(ctx *context.Context) {
}
// Both `git log branchName` and `git log commitId` work.
commits, err := ctx.Repo.Commit.CommitsByRange(page, pageSize, "", "", "")
commits, err := ctx.Repo.GitRepo.CommitsByRangeWithTime(ctx.Repo.Commit.ID, page, pageSize, "", "", "")
if err != nil {
ctx.ServerError("CommitsByRange", err)
return
@ -194,7 +194,7 @@ func SearchCommits(ctx *context.Context) {
all := ctx.FormBool("all")
opts := git.NewSearchCommitsOptions(query, all)
commits, err := ctx.Repo.Commit.SearchCommits(opts)
commits, err := ctx.Repo.GitRepo.SearchCommits(ctx.Repo.Commit.ID, opts)
if err != nil {
ctx.ServerError("SearchCommits", err)
return
@ -391,7 +391,7 @@ func Diff(ctx *context.Context) {
ctx.Data["CommitStatus"] = git_model.CalcCommitStatus(statuses)
ctx.Data["CommitStatuses"] = statuses
verification := asymkey_service.ParseCommitWithSignature(ctx, commit)
verification := asymkey_service.ParseCommitWithSignature(ctx, ctx.Repo.GitRepo, commit)
ctx.Data["Verification"] = verification
ctx.Data["Author"] = user_model.ValidateCommitWithEmail(ctx, commit)
ctx.Data["Parents"] = parents
@ -459,7 +459,7 @@ func RawDiff(ctx *context.Context) {
}
func processGitCommits(ctx *context.Context, gitCommits []*git.Commit) ([]*git_model.SignCommitWithStatuses, error) {
commits, err := git_service.ConvertFromGitCommit(ctx, gitCommits, ctx.Repo.Repository)
commits, err := git_service.ConvertFromGitCommit(ctx, gitCommits, ctx.Repo.Repository, ctx.Repo.GitRepo)
if err != nil {
return nil, err
}

View File

@ -63,7 +63,7 @@ func setCompareContext(ctx *context.Context, before, head *git.Commit, headOwner
return nil
}
blob, err := commit.GetBlobByPath(path)
blob, err := git.NewTree(ctx.Repo.GitRepo, commit.TreeID).GetBlobByPath(path)
if err != nil {
return nil
}
@ -937,9 +937,9 @@ func ExcerptBlob(ctx *context.Context) {
idxRight -= chunkSize
leftHunkSize += chunkSize
rightHunkSize += chunkSize
section.Lines, err = getExcerptLines(commit, filePath, idxLeft-1, idxRight-1, chunkSize)
section.Lines, err = getExcerptLines(gitRepo, commit, filePath, idxLeft-1, idxRight-1, chunkSize)
} else if direction == "down" && (idxLeft-lastLeft) > chunkSize {
section.Lines, err = getExcerptLines(commit, filePath, lastLeft, lastRight, chunkSize)
section.Lines, err = getExcerptLines(gitRepo, commit, filePath, lastLeft, lastRight, chunkSize)
lastLeft += chunkSize
lastRight += chunkSize
} else {
@ -947,7 +947,7 @@ func ExcerptBlob(ctx *context.Context) {
if direction == "down" {
offset = 0
}
section.Lines, err = getExcerptLines(commit, filePath, lastLeft, lastRight, idxRight-lastRight+offset)
section.Lines, err = getExcerptLines(gitRepo, commit, filePath, lastLeft, lastRight, idxRight-lastRight+offset)
leftHunkSize = 0
rightHunkSize = 0
idxLeft = lastLeft
@ -1023,8 +1023,8 @@ func ExcerptBlob(ctx *context.Context) {
ctx.HTML(http.StatusOK, tplBlobExcerpt)
}
func getExcerptLines(commit *git.Commit, filePath string, idxLeft, idxRight, chunkSize int) ([]*gitdiff.DiffLine, error) {
blob, err := commit.Tree.GetBlobByPath(filePath)
func getExcerptLines(gitRepo *git.Repository, commit *git.Commit, filePath string, idxLeft, idxRight, chunkSize int) ([]*gitdiff.DiffLine, error) {
blob, err := git.NewTree(gitRepo, commit.TreeID).GetBlobByPath(filePath)
if err != nil {
return nil, err
}

View File

@ -82,7 +82,8 @@ func ServeBlobOrLFS(ctx *context.Context, blob *git.Blob, lastModified *time.Tim
}
func getBlobForEntry(ctx *context.Context) (*git.Blob, *time.Time) {
entry, err := ctx.Repo.Commit.GetTreeEntryByPath(ctx.Repo.TreePath)
tree := git.NewTree(ctx.Repo.GitRepo, ctx.Repo.Commit.TreeID)
entry, err := tree.GetTreeEntryByPath(ctx.Repo.TreePath)
if err != nil {
if git.IsErrNotExist(err) {
ctx.NotFound(err)

View File

@ -221,7 +221,8 @@ func redirectForCommitChoice[T any](ctx *context.Context, parsed *preparedEditor
}
func editFileOpenExisting(ctx *context.Context) (prefetch []byte, dataRc io.ReadCloser, fInfo *fileInfo) {
entry, err := ctx.Repo.Commit.GetTreeEntryByPath(ctx.Repo.TreePath)
tree := git.NewTree(ctx.Repo.GitRepo, ctx.Repo.Commit.TreeID)
entry, err := tree.GetTreeEntryByPath(ctx.Repo.TreePath)
if err != nil {
HandleGitError(ctx, "GetTreeEntryByPath", err)
return nil, nil, nil

View File

@ -31,7 +31,7 @@ func NewDiffPatchPost(ctx *context.Context) {
}
defaultCommitMessage := ctx.Locale.TrString("repo.editor.patch")
_, err := files.ApplyDiffPatch(ctx, ctx.Repo.Repository, ctx.Doer, &files.ApplyDiffPatchOptions{
_, err := files.ApplyDiffPatch(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, ctx.Doer, &files.ApplyDiffPatchOptions{
LastCommitID: parsed.form.LastCommit,
OldBranch: parsed.OldBranchName,
NewBranch: parsed.NewBranchName,

View File

@ -72,7 +72,7 @@ func CherryPickPost(ctx *context.Context) {
}
if err == nil {
opts.Content = buf.String()
_, err = files.ApplyDiffPatch(ctx, ctx.Repo.Repository, ctx.Doer, opts)
_, err = files.ApplyDiffPatch(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, ctx.Doer, opts)
if err != nil {
err = util.ErrorWrapTranslatable(err, "repo.editor.fail_to_apply_patch")
}

View File

@ -6,6 +6,7 @@ package repo
import (
"net/http"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/services/context"
files_service "code.gitea.io/gitea/services/repository/files"
)
@ -18,7 +19,9 @@ func DiffPreviewPost(ctx *context.Context) {
return
}
entry, err := ctx.Repo.Commit.GetTreeEntryByPath(treePath)
tree := git.NewTree(ctx.Repo.GitRepo, ctx.Repo.Commit.TreeID)
entry, err := tree.GetTreeEntryByPath(treePath)
if err != nil {
ctx.ServerError("GetTreeEntryByPath", err)
return

View File

@ -46,7 +46,8 @@ func getClosestParentWithFiles(gitRepo *git.Repository, branchName, originTreePa
return ""
}
// see if the tree has entries
if tree, err := commit.SubTree(treePath); err != nil {
tree := git.NewTree(gitRepo, commit.TreeID)
if tree, err := tree.SubTree(treePath); err != nil {
return f(path.Dir(treePath), commit) // failed to get the tree, going up a dir
} else if entries, err := tree.ListEntries(); err != nil || len(entries) == 0 {
return f(path.Dir(treePath), commit) // no files in this dir, going up a dir

View File

@ -50,11 +50,12 @@ func setTemplateIfExists(ctx *context.Context, ctxDataKey string, possibleFiles
templateCandidates = append(templateCandidates, possibleFiles...) // Append files to the end because they should be fallback
templateErrs := map[string]error{}
tree := git.NewTree(ctx.Repo.GitRepo, commit.TreeID)
for _, filename := range templateCandidates {
if ok, _ := commit.HasFile(filename); !ok {
if entry, _ := tree.GetTreeEntryByPath(filename); entry == nil {
continue
}
template, err := issue_template.UnmarshalFromCommit(commit, filename)
template, err := issue_template.UnmarshalFromCommit(tree, filename)
if err != nil {
templateErrs[filename] = err
continue

View File

@ -740,7 +740,7 @@ func viewPullFiles(ctx *context.Context, beforeCommitID, afterCommitID string) {
}
}
} else {
beforeCommit, err = afterCommit.Parent(0)
beforeCommit, err = gitRepo.ParentCommit(afterCommit, 0)
if err != nil {
ctx.ServerError("Parent", err)
return

View File

@ -59,7 +59,7 @@ func calReleaseNumCommitsBehind(repoCtx *context.Repository, release *repo_model
return fmt.Errorf("GetBranchCommit(DefaultBranch): %w", err)
}
}
countCache[target], err = commit.CommitsCount()
countCache[target], err = repoCtx.GitRepo.CommitsCount(commit.ID.String())
if err != nil {
return fmt.Errorf("CommitsCount: %w", err)
}

View File

@ -19,7 +19,7 @@ func RenderFile(ctx *context.Context) {
var blob *git.Blob
var err error
if ctx.Repo.TreePath != "" {
blob, err = ctx.Repo.Commit.GetBlobByPath(ctx.Repo.TreePath)
blob, err = git.NewTree(ctx.Repo.GitRepo, ctx.Repo.Commit.TreeID).GetBlobByPath(ctx.Repo.TreePath)
} else {
blob, err = ctx.Repo.GitRepo.GetBlob(ctx.PathParam("sha"))
}

View File

@ -22,7 +22,7 @@ import (
// TreeList get all files' entries of a repository
func TreeList(ctx *context.Context) {
tree, err := ctx.Repo.Commit.SubTree("/")
tree, err := git.NewTree(ctx.Repo.GitRepo, ctx.Repo.Commit.TreeID).SubTree("/")
if err != nil {
ctx.ServerError("Repo.Commit.SubTree", err)
return
@ -144,7 +144,8 @@ func transformDiffTreeForWeb(renderedIconPool *fileicon.RenderedIconPool, diffTr
func TreeViewNodes(ctx *context.Context) {
renderedIconPool := fileicon.NewRenderedIconPool()
results, err := files_service.GetTreeViewNodes(ctx, ctx.Repo.RepoLink, renderedIconPool, ctx.Repo.Commit, ctx.Repo.TreePath, ctx.FormString("sub_path"))
tree := git.NewTree(ctx.Repo.GitRepo, ctx.Repo.Commit.TreeID)
results, err := files_service.GetTreeViewNodes(ctx, ctx.Repo.RepoLink, renderedIconPool, tree, ctx.Repo.TreePath, ctx.FormString("sub_path"))
if err != nil {
ctx.ServerError("GetTreeViewNodes", err)
return

View File

@ -124,7 +124,7 @@ func loadLatestCommitData(ctx *context.Context, latestCommit *git.Commit) bool {
// or of directory if not in root directory.
ctx.Data["LatestCommit"] = latestCommit
if latestCommit != nil {
verification := asymkey_service.ParseCommitWithSignature(ctx, latestCommit)
verification := asymkey_service.ParseCommitWithSignature(ctx, ctx.Repo.GitRepo, latestCommit)
if err := asymkey_model.CalculateTrustStatus(verification, ctx.Repo.Repository.GetTrustModel(), func(user *user_model.User) (bool, error) {
return repo_model.IsOwnerMemberCollaborator(ctx, ctx.Repo.Repository, user.ID)
@ -271,9 +271,10 @@ func LastCommit(ctx *context.Context) {
func prepareDirectoryFileIcons(ctx *context.Context, files []git.CommitInfo) {
renderedIconPool := fileicon.NewRenderedIconPool()
fileIcons := map[string]template.HTML{}
tree := git.NewTree(ctx.Repo.GitRepo, ctx.Repo.Commit.TreeID)
for _, f := range files {
fullPath := path.Join(ctx.Repo.TreePath, f.Entry.Name())
entryInfo := fileicon.EntryInfoFromGitTreeEntry(ctx.Repo.Commit, fullPath, f.Entry)
entryInfo := fileicon.EntryInfoFromGitTreeEntry(tree, fullPath, f.Entry)
fileIcons[f.Entry.Name()] = fileicon.RenderEntryIconHTML(renderedIconPool, entryInfo)
}
fileIcons[".."] = fileicon.RenderEntryIconHTML(renderedIconPool, fileicon.EntryInfoFolder())
@ -282,7 +283,8 @@ func prepareDirectoryFileIcons(ctx *context.Context, files []git.CommitInfo) {
}
func renderDirectoryFiles(ctx *context.Context, timeout time.Duration) git.Entries {
tree, err := ctx.Repo.Commit.SubTree(ctx.Repo.TreePath)
rootTree := git.NewTree(ctx.Repo.GitRepo, ctx.Repo.Commit.TreeID)
tree, err := rootTree.SubTree(ctx.Repo.TreePath)
if err != nil {
HandleGitError(ctx, "Repo.Commit.SubTree", err)
return nil
@ -291,7 +293,7 @@ func renderDirectoryFiles(ctx *context.Context, timeout time.Duration) git.Entri
ctx.Data["LastCommitLoaderURL"] = ctx.Repo.RepoLink + "/lastcommit/" + url.PathEscape(ctx.Repo.CommitID) + "/" + util.PathEscapeSegments(ctx.Repo.TreePath)
// Get current entry user currently looking at.
entry, err := ctx.Repo.Commit.GetTreeEntryByPath(ctx.Repo.TreePath)
entry, err := rootTree.GetTreeEntryByPath(ctx.Repo.TreePath)
if err != nil {
HandleGitError(ctx, "Repo.Commit.GetTreeEntryByPath", err)
return nil
@ -316,7 +318,7 @@ func renderDirectoryFiles(ctx *context.Context, timeout time.Duration) git.Entri
defer cancel()
}
files, latestCommit, err := allEntries.GetCommitsInfo(commitInfoCtx, ctx.Repo.RepoLink, ctx.Repo.Commit, ctx.Repo.TreePath)
files, latestCommit, err := allEntries.GetCommitsInfo(commitInfoCtx, ctx.Repo.GitRepo, ctx.Repo.RepoLink, ctx.Repo.Commit, ctx.Repo.TreePath)
if err != nil {
ctx.ServerError("GetCommitsInfo", err)
return nil

View File

@ -32,7 +32,7 @@ import (
)
func prepareLatestCommitInfo(ctx *context.Context) bool {
commit, err := ctx.Repo.Commit.GetCommitByPath(ctx.Repo.TreePath)
commit, err := ctx.Repo.GitRepo.GetCommitByPath(ctx.Repo.Commit.ID, ctx.Repo.TreePath)
if err != nil {
ctx.ServerError("GetCommitByPath", err)
return false
@ -177,6 +177,7 @@ func prepareFileView(ctx *context.Context, entry *git.TreeEntry) {
ctx.Data["FileTreePath"] = ctx.Repo.TreePath
ctx.Data["RawFileLink"] = ctx.Repo.RepoLink + "/raw/" + ctx.Repo.RefTypeNameSubURL() + "/" + util.PathEscapeSegments(ctx.Repo.TreePath)
tree := git.NewTree(ctx.Repo.GitRepo, ctx.Repo.Commit.TreeID)
if ctx.Repo.TreePath == ".editorconfig" {
_, editorconfigWarning, editorconfigErr := ctx.Repo.GetEditorconfig(ctx.Repo.Commit)
if editorconfigWarning != nil {
@ -186,7 +187,7 @@ func prepareFileView(ctx *context.Context, entry *git.TreeEntry) {
ctx.Data["FileError"] = strings.TrimSpace(editorconfigErr.Error())
}
} else if issue_service.IsTemplateConfig(ctx.Repo.TreePath) {
_, issueConfigErr := issue_service.GetTemplateConfig(ctx.Repo.GitRepo, ctx.Repo.TreePath, ctx.Repo.Commit)
_, issueConfigErr := issue_service.GetTemplateConfig(ctx.Repo.GitRepo, ctx.Repo.TreePath, tree)
if issueConfigErr != nil {
ctx.Data["FileError"] = strings.TrimSpace(issueConfigErr.Error())
}

View File

@ -103,7 +103,7 @@ func prepareHomeSidebarCitationFile(entry *git.TreeEntry) func(ctx *context.Cont
if entry.Name() != "" {
return
}
tree, err := ctx.Repo.Commit.SubTree(ctx.Repo.TreePath)
tree, err := git.NewTree(ctx.Repo.GitRepo, ctx.Repo.Commit.TreeID).SubTree(ctx.Repo.TreePath)
if err != nil {
HandleGitError(ctx, "Repo.Commit.SubTree", err)
return
@ -269,8 +269,8 @@ func isViewHomeOnlyContent(ctx *context.Context) bool {
return ctx.FormBool("only_content")
}
func handleRepoViewSubmodule(ctx *context.Context, commitSubmoduleFile *git.CommitSubmoduleFile) {
submoduleWebLink := commitSubmoduleFile.SubmoduleWebLinkTree(ctx)
func handleRepoViewSubmodule(ctx *context.Context, submoduleFile *git.SubmoduleFile) {
submoduleWebLink := submoduleFile.SubmoduleWebLinkTree(ctx)
if submoduleWebLink == nil {
ctx.Data["NotFoundPrompt"] = ctx.Repo.TreePath
ctx.NotFound(nil)
@ -293,12 +293,12 @@ func handleRepoViewSubmodule(ctx *context.Context, commitSubmoduleFile *git.Comm
func prepareToRenderDirOrFile(entry *git.TreeEntry) func(ctx *context.Context) {
return func(ctx *context.Context) {
if entry.IsSubModule() {
commitSubmoduleFile, err := git.GetCommitInfoSubmoduleFile(ctx.Repo.RepoLink, ctx.Repo.TreePath, ctx.Repo.Commit, entry.ID)
submoduleFile, err := git.GetCommitInfoSubmoduleFile(ctx.Repo.GitRepo, ctx.Repo.RepoLink, ctx.Repo.TreePath, ctx.Repo.Commit.TreeID, entry.ID)
if err != nil {
HandleGitError(ctx, "prepareToRenderDirOrFile: GetCommitInfoSubmoduleFile", err)
return
}
handleRepoViewSubmodule(ctx, commitSubmoduleFile)
handleRepoViewSubmodule(ctx, submoduleFile)
} else if entry.IsDir() {
prepareToRenderDirectory(ctx)
} else {
@ -354,7 +354,7 @@ func redirectFollowSymlink(ctx *context.Context, treePathEntry *git.TreeEntry) b
return false
}
if treePathEntry.IsLink() {
if res, err := git.EntryFollowLinks(ctx.Repo.Commit, ctx.Repo.TreePath, treePathEntry); err == nil {
if res, err := git.EntryFollowLinks(git.NewTree(ctx.Repo.GitRepo, ctx.Repo.Commit.TreeID), ctx.Repo.TreePath, treePathEntry); err == nil {
redirect := ctx.Repo.RepoLink + "/src/" + ctx.Repo.RefTypeNameSubURL() + "/" + util.PathEscapeSegments(res.TargetFullPath) + "?" + ctx.Req.URL.RawQuery
ctx.Redirect(redirect)
return true
@ -396,7 +396,7 @@ func Home(ctx *context.Context) {
prepareHomeTreeSideBarSwitch(ctx)
// get the current git entry which doer user is currently looking at.
entry, err := ctx.Repo.Commit.GetTreeEntryByPath(ctx.Repo.TreePath)
entry, err := git.NewTree(ctx.Repo.GitRepo, ctx.Repo.Commit.TreeID).GetTreeEntryByPath(ctx.Repo.TreePath)
if err != nil {
HandleGitError(ctx, "Repo.Commit.GetTreeEntryByPath", err)
return

View File

@ -18,19 +18,19 @@ func TestViewHomeSubmoduleRedirect(t *testing.T) {
unittest.PrepareTestEnv(t)
ctx, _ := contexttest.MockContext(t, "/user2/repo1/src/branch/master/test-submodule")
submodule := git_module.NewCommitSubmoduleFile("/user2/repo1", "test-submodule", "../repo-other", "any-ref-id")
submodule := git_module.NewSubmoduleFile("/user2/repo1", "test-submodule", "../repo-other", "any-ref-id")
handleRepoViewSubmodule(ctx, submodule)
assert.Equal(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
assert.Equal(t, "/user2/repo-other/tree/any-ref-id", ctx.Resp.Header().Get("Location"))
ctx, _ = contexttest.MockContext(t, "/user2/repo1/src/branch/master/test-submodule")
submodule = git_module.NewCommitSubmoduleFile("/user2/repo1", "test-submodule", "https://other/user2/repo-other.git", "any-ref-id")
submodule = git_module.NewSubmoduleFile("/user2/repo1", "test-submodule", "https://other/user2/repo-other.git", "any-ref-id")
handleRepoViewSubmodule(ctx, submodule)
// do not auto-redirect for external URLs, to avoid open redirect or phishing
assert.Equal(t, http.StatusNotFound, ctx.Resp.WrittenStatus())
ctx, respWriter := contexttest.MockContext(t, "/user2/repo1/src/branch/master/test-submodule?only_content=true")
submodule = git_module.NewCommitSubmoduleFile("/user2/repo1", "test-submodule", "../repo-other", "any-ref-id")
submodule = git_module.NewSubmoduleFile("/user2/repo1", "test-submodule", "../repo-other", "any-ref-id")
handleRepoViewSubmodule(ctx, submodule)
assert.Equal(t, http.StatusOK, ctx.Resp.WrittenStatus())
assert.Equal(t, `<a href="/user2/repo-other/tree/any-ref-id">/user2/repo-other/tree/any-ref-id</a>`, respWriter.Body.String())

View File

@ -64,12 +64,13 @@ func findReadmeFileInEntries(ctx *context.Context, parentDir string, entries []*
exts := append(localizedExtensions(".md", ctx.Locale.Language()), ".txt", "") // sorted by priority
extCount := len(exts)
readmeFiles := make([]*git.TreeEntry, extCount+1)
tree := git.NewTree(ctx.Repo.GitRepo, ctx.Repo.Commit.TreeID)
for _, entry := range entries {
if i, ok := util.IsReadmeFileExtension(entry.Name(), exts...); ok {
fullPath := path.Join(parentDir, entry.Name())
if readmeFiles[i] == nil || base.NaturalSortLess(readmeFiles[i].Name(), entry.Blob().Name()) {
if entry.IsLink() {
res, err := git.EntryFollowLinks(ctx.Repo.Commit, fullPath, entry)
res, err := git.EntryFollowLinks(tree, fullPath, entry)
if err == nil && (res.TargetEntry.IsExecutable() || res.TargetEntry.IsRegular()) {
readmeFiles[i] = entry
}
@ -146,7 +147,7 @@ func prepareToRenderReadmeFile(ctx *context.Context, subfolder string, readmeFil
readmeFullPath := path.Join(ctx.Repo.TreePath, subfolder, readmeFile.Name())
readmeTargetEntry := readmeFile
if readmeFile.IsLink() {
if res, err := git.EntryFollowLinks(ctx.Repo.Commit, readmeFullPath, readmeFile); err == nil {
if res, err := git.EntryFollowLinks(git.NewTree(ctx.Repo.GitRepo, ctx.Repo.Commit.TreeID), readmeFullPath, readmeFile); err == nil {
readmeTargetEntry = res.TargetEntry
} else {
readmeTargetEntry = nil // if we cannot resolve the symlink, we cannot render the readme, ignore the error

View File

@ -78,8 +78,8 @@ type PageMeta struct {
}
// findEntryForFile finds the tree entry for a target filepath.
func findEntryForFile(commit *git.Commit, target string) (*git.TreeEntry, error) {
entry, err := commit.GetTreeEntryByPath(target)
func findEntryForFile(tree *git.Tree, target string) (*git.TreeEntry, error) {
entry, err := tree.GetTreeEntryByPath(target)
if err != nil && !git.IsErrNotExist(err) {
return nil, err
}
@ -92,7 +92,7 @@ func findEntryForFile(commit *git.Commit, target string) (*git.TreeEntry, error)
if unescapedTarget, err = url.QueryUnescape(target); err != nil {
return nil, err
}
return commit.GetTreeEntryByPath(unescapedTarget)
return tree.GetTreeEntryByPath(unescapedTarget)
}
func findWikiRepoCommit(ctx *context.Context) (*git.Repository, *git.Commit, error) {
@ -144,10 +144,10 @@ func wikiContentsByEntry(ctx *context.Context, entry *git.TreeEntry) []byte {
// wikiEntryByName returns the entry of a wiki page, along with a boolean
// indicating whether the entry exists. Writes to ctx if an error occurs.
// The last return value indicates whether the file should be returned as a raw file
func wikiEntryByName(ctx *context.Context, commit *git.Commit, wikiName wiki_service.WebPath) (*git.TreeEntry, string, bool, bool) {
func wikiEntryByName(ctx *context.Context, tree *git.Tree, wikiName wiki_service.WebPath) (*git.TreeEntry, string, bool, bool) {
isRaw := false
gitFilename := wiki_service.WebPathToGitPath(wikiName)
entry, err := findEntryForFile(commit, gitFilename)
entry, err := findEntryForFile(tree, gitFilename)
if err != nil && !git.IsErrNotExist(err) {
ctx.ServerError("findEntryForFile", err)
return nil, "", false, false
@ -155,7 +155,7 @@ func wikiEntryByName(ctx *context.Context, commit *git.Commit, wikiName wiki_ser
if entry == nil {
// check if the file without ".md" suffix exists
gitFilename := strings.TrimSuffix(gitFilename, ".md")
entry, err = findEntryForFile(commit, gitFilename)
entry, err = findEntryForFile(tree, gitFilename)
if err != nil && !git.IsErrNotExist(err) {
ctx.ServerError("findEntryForFile", err)
return nil, "", false, false
@ -170,8 +170,8 @@ func wikiEntryByName(ctx *context.Context, commit *git.Commit, wikiName wiki_ser
// wikiContentsByName returns the contents of a wiki page, along with a boolean
// indicating whether the page exists. Writes to ctx if an error occurs.
func wikiContentsByName(ctx *context.Context, commit *git.Commit, wikiName wiki_service.WebPath) ([]byte, *git.TreeEntry, string, bool) {
entry, gitFilename, noEntry, _ := wikiEntryByName(ctx, commit, wikiName)
func wikiContentsByName(ctx *context.Context, tree *git.Tree, wikiName wiki_service.WebPath) ([]byte, *git.TreeEntry, string, bool) {
entry, gitFilename, noEntry, _ := wikiEntryByName(ctx, tree, wikiName)
if entry == nil {
return nil, nil, "", true
}
@ -187,8 +187,9 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
return nil, nil
}
tree := git.NewTree(wikiGitRepo, commit.TreeID)
// get the wiki pages list.
entries, err := commit.ListEntries()
entries, err := tree.ListEntries()
if err != nil {
ctx.ServerError("ListEntries", err)
return nil, nil
@ -233,7 +234,7 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
isFooter := pageName == "_Footer"
// lookup filename in wiki - get gitTree entry , real filename
entry, pageFilename, noEntry, isRaw := wikiEntryByName(ctx, commit, pageName)
entry, pageFilename, noEntry, isRaw := wikiEntryByName(ctx, tree, pageName)
if noEntry {
ctx.Redirect(ctx.Repo.RepoLink + "/wiki/?action=_pages")
}
@ -286,7 +287,7 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
}
if !isSideBar {
sidebarContent, _, _, _ := wikiContentsByName(ctx, commit, "_Sidebar")
sidebarContent, _, _, _ := wikiContentsByName(ctx, tree, "_Sidebar")
if ctx.Written() {
return nil, nil
}
@ -298,7 +299,7 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
}
if !isFooter {
footerContent, _, _, _ := wikiContentsByName(ctx, commit, "_Footer")
footerContent, _, _, _ := wikiContentsByName(ctx, tree, "_Footer")
if ctx.Written() {
return nil, nil
}
@ -340,8 +341,10 @@ func renderRevisionPage(ctx *context.Context) (*git.Repository, *git.TreeEntry)
ctx.Data["Username"] = ctx.Repo.Owner.Name
ctx.Data["Reponame"] = ctx.Repo.Repository.Name
tree := git.NewTree(wikiGitRepo, commit.TreeID)
// lookup filename in wiki - get page content, gitTree entry , real filename
_, entry, pageFilename, noEntry := wikiContentsByName(ctx, commit, pageName)
_, entry, pageFilename, noEntry := wikiContentsByName(ctx, tree, pageName)
if noEntry {
ctx.Redirect(ctx.Repo.RepoLink + "/wiki/?action=_pages")
}
@ -367,7 +370,7 @@ func renderRevisionPage(ctx *context.Context) (*git.Repository, *git.TreeEntry)
ctx.ServerError("CommitsByFileAndRange", err)
return nil, nil
}
ctx.Data["Commits"], err = git_service.ConvertFromGitCommit(ctx, commitsHistory, ctx.Repo.Repository)
ctx.Data["Commits"], err = git_service.ConvertFromGitCommit(ctx, commitsHistory, ctx.Repo.Repository, wikiGitRepo)
if err != nil {
ctx.ServerError("ConvertFromGitCommit", err)
return nil, nil
@ -381,7 +384,7 @@ func renderRevisionPage(ctx *context.Context) (*git.Repository, *git.TreeEntry)
}
func renderEditPage(ctx *context.Context) {
_, commit, err := findWikiRepoCommit(ctx)
wikiGitRepo, commit, err := findWikiRepoCommit(ctx)
if err != nil {
if !git.IsErrNotExist(err) {
ctx.ServerError("GetBranchCommit", err)
@ -401,8 +404,10 @@ func renderEditPage(ctx *context.Context) {
ctx.Data["Title"] = displayName
ctx.Data["title"] = displayName
tree := git.NewTree(wikiGitRepo, commit.TreeID)
// lookup filename in wiki - gitTree entry , real filename
entry, _, noEntry, isRaw := wikiEntryByName(ctx, commit, pageName)
entry, _, noEntry, isRaw := wikiEntryByName(ctx, tree, pageName)
if noEntry {
ctx.Redirect(ctx.Repo.RepoLink + "/wiki/?action=_pages")
}
@ -497,7 +502,7 @@ func Wiki(ctx *context.Context) {
ctx.Data["FormatWarning"] = ext + " rendering is not supported at the moment. Rendered as Markdown."
}
// Get last change information.
lastCommit, err := wikiGitRepo.GetCommitByPath(wikiPath)
lastCommit, err := wikiGitRepo.GetCommitByPathDefaultBranch(wikiPath)
if err != nil {
ctx.ServerError("GetCommitByPath", err)
return
@ -529,7 +534,7 @@ func WikiRevision(ctx *context.Context) {
// Get last change information.
wikiPath := entry.Name()
lastCommit, err := wikiGitRepo.GetCommitByPath(wikiPath)
lastCommit, err := wikiGitRepo.GetCommitByPathDefaultBranch(wikiPath)
if err != nil {
ctx.ServerError("GetCommitByPath", err)
return
@ -549,14 +554,15 @@ func WikiPages(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("repo.wiki.pages")
ctx.Data["CanWriteWiki"] = ctx.Repo.CanWrite(unit.TypeWiki) && !ctx.Repo.Repository.IsArchived
_, commit, err := findWikiRepoCommit(ctx)
wikiGitRepo, commit, err := findWikiRepoCommit(ctx)
if err != nil {
ctx.Redirect(ctx.Repo.RepoLink + "/wiki")
return
}
rootTree := git.NewTree(wikiGitRepo, commit.TreeID)
treePath := "" // To support list sub folders' pages in the future
tree, err := commit.SubTree(treePath)
tree, err := rootTree.SubTree(treePath)
if err != nil {
ctx.ServerError("SubTree", err)
return
@ -569,7 +575,7 @@ func WikiPages(ctx *context.Context) {
}
allEntries.CustomSort(base.NaturalSortLess)
entries, _, err := allEntries.GetCommitsInfo(ctx, ctx.Repo.RepoLink, commit, treePath)
entries, _, err := allEntries.GetCommitsInfo(ctx, wikiGitRepo, ctx.Repo.RepoLink, commit, treePath)
if err != nil {
ctx.ServerError("GetCommitsInfo", err)
return
@ -603,7 +609,7 @@ func WikiPages(ctx *context.Context) {
// WikiRaw outputs raw blob requested by user (image for example)
func WikiRaw(ctx *context.Context) {
_, commit, err := findWikiRepoCommit(ctx)
wikiGitRepo, commit, err := findWikiRepoCommit(ctx)
if err != nil {
if git.IsErrNotExist(err) {
ctx.NotFound(nil)
@ -617,8 +623,9 @@ func WikiRaw(ctx *context.Context) {
providedGitPath := wiki_service.WebPathToGitPath(providedWebPath)
var entry *git.TreeEntry
if commit != nil {
tree := git.NewTree(wikiGitRepo, commit.TreeID)
// Try to find a file with that name
entry, err = findEntryForFile(commit, providedGitPath)
entry, err = findEntryForFile(tree, providedGitPath)
if err != nil && !git.IsErrNotExist(err) {
ctx.ServerError("findFile", err)
return
@ -627,7 +634,7 @@ func WikiRaw(ctx *context.Context) {
if entry == nil {
// Try to find a wiki page with that name
providedGitPath = strings.TrimSuffix(providedGitPath, ".md")
entry, err = findEntryForFile(commit, providedGitPath)
entry, err = findEntryForFile(tree, providedGitPath)
if err != nil && !git.IsErrNotExist(err) {
ctx.ServerError("findFile", err)
return

View File

@ -34,7 +34,8 @@ func wikiEntry(t *testing.T, repo *repo_model.Repository, wikiName wiki_service.
defer wikiRepo.Close()
commit, err := wikiRepo.GetBranchCommit("master")
assert.NoError(t, err)
entries, err := commit.ListEntries()
tree := git.NewTree(wikiRepo, commit.TreeID)
entries, err := tree.ListEntries()
assert.NoError(t, err)
for _, entry := range entries {
if entry.Name() == wiki_service.WebPathToGitPath(wikiName) {

View File

@ -122,7 +122,7 @@ func FindOwnerProfileReadme(ctx *context.Context, doer *user_model.User, optProf
return nil, nil
}
profileReadmeBlob, _ = commit.GetBlobByPath("README.md") // no need to handle this error
profileReadmeBlob, _ = git.NewTree(profileGitRepo, commit.TreeID).GetBlobByPath("README.md") // no need to handle this error
return profileDbRepo, profileReadmeBlob
}

View File

@ -234,7 +234,7 @@ func notify(ctx context.Context, input *notifyInput) error {
}
if shouldDetectSchedules {
if err := handleSchedules(ctx, schedules, commit, input, ref.String()); err != nil {
if err := handleSchedules(ctx, gitRepo, schedules, commit, input, ref.String()); err != nil {
return err
}
}
@ -439,12 +439,13 @@ func ifNeedApproval(ctx context.Context, run *actions_model.ActionRun, repo *rep
func handleSchedules(
ctx context.Context,
gitRepo *git.Repository,
detectedWorkflows []*actions_module.DetectedWorkflow,
commit *git.Commit,
input *notifyInput,
ref string,
) error {
branch, err := commit.GetBranchName()
branch, err := gitRepo.GetClosestBranchName(commit)
if err != nil {
return err
}
@ -538,5 +539,5 @@ func DetectAndHandleSchedules(ctx context.Context, repo *repo_model.Repository)
// so we use action user as the Doer of the notifyInput
notifyInput := newNotifyInputForSchedules(repo)
return handleSchedules(ctx, scheduleWorkflows, commit, notifyInput, repo.DefaultBranch)
return handleSchedules(ctx, gitRepo, scheduleWorkflows, commit, notifyInput, repo.DefaultBranch)
}

View File

@ -89,7 +89,8 @@ func DispatchActionWorkflow(ctx reqctx.RequestContext, doer *user_model.User, re
}
// get workflow entry from runTargetCommit
_, entries, err := actions.ListWorkflows(runTargetCommit)
tree := git.NewTree(gitRepo, runTargetCommit.TreeID)
_, entries, err := actions.ListWorkflows(tree)
if err != nil {
return err
}

View File

@ -23,7 +23,7 @@ import (
)
// ParseCommitWithSignature check if signature is good against keystore.
func ParseCommitWithSignature(ctx context.Context, c *git.Commit) *asymkey_model.CommitVerification {
func ParseCommitWithSignature(ctx context.Context, gitRepo *git.Repository, c *git.Commit) *asymkey_model.CommitVerification {
committer, err := user_model.GetUserByEmail(ctx, c.Committer.Email)
if err != nil && !user_model.IsErrUserNotExist(err) {
log.Error("GetUserByEmail: %v", err)
@ -32,14 +32,14 @@ func ParseCommitWithSignature(ctx context.Context, c *git.Commit) *asymkey_model
Reason: "gpg.error.no_committer_account", // this error is not right, but such error should seldom happen
}
}
return ParseCommitWithSignatureCommitter(ctx, c, committer)
return ParseCommitWithSignatureCommitter(ctx, gitRepo, c, committer)
}
// ParseCommitWithSignatureCommitter parses a commit's GPG or SSH signature.
// The caller guarantees that the committer user is related to the commit by checking its activated email addresses or no-reply address.
// If the commit is singed by an instance key, then committer can be nil.
// If the signature exists, even if committer is nil, the returned CommittingUser will be a non-nil fake user (e.g.: instance key)
func ParseCommitWithSignatureCommitter(ctx context.Context, c *git.Commit, committer *user_model.User) *asymkey_model.CommitVerification {
func ParseCommitWithSignatureCommitter(ctx context.Context, gitRepo *git.Repository, c *git.Commit, committer *user_model.User) *asymkey_model.CommitVerification {
// If no signature, just report the committer
if c.Signature == nil {
return &asymkey_model.CommitVerification{
@ -58,10 +58,10 @@ func ParseCommitWithSignatureCommitter(ctx context.Context, c *git.Commit, commi
if strings.HasPrefix(c.Signature.Signature, "-----BEGIN SSH SIGNATURE-----") {
return parseCommitWithSSHSignature(ctx, c, committer)
}
return parseCommitWithGPGSignature(ctx, c, committer)
return parseCommitWithGPGSignature(ctx, gitRepo, c, committer)
}
func parseCommitWithGPGSignature(ctx context.Context, c *git.Commit, committer *user_model.User) *asymkey_model.CommitVerification {
func parseCommitWithGPGSignature(ctx context.Context, gitRepo *git.Repository, c *git.Commit, committer *user_model.User) *asymkey_model.CommitVerification {
// Parsing signature
sig, err := asymkey_model.ExtractSignature(c.Signature.Signature)
if err != nil { // Skipping failed to extract sign
@ -162,7 +162,7 @@ func parseCommitWithGPGSignature(ctx context.Context, c *git.Commit, committer *
}
}
defaultGPGSettings, err := c.GetRepositoryDefaultPublicGPGKey(false)
defaultGPGSettings, err := gitRepo.GetDefaultPublicGPGKey(false)
if err != nil {
log.Error("Error getting default public gpg key: %v", err)
} else if defaultGPGSettings == nil {

View File

@ -37,7 +37,7 @@ func TestParseCommitWithSSHSignature(t *testing.T) {
require.NoError(t, err)
t.Run("UserSSHKey", func(t *testing.T) {
commit, err := git.CommitFromReader(nil, git.Sha1ObjectFormat.EmptyObjectID(), strings.NewReader(`tree a3b1fad553e0f9a2b4a58327bebde36c7da75aa2
commit, err := git.CommitFromReader(git.Sha1ObjectFormat.EmptyObjectID(), strings.NewReader(`tree a3b1fad553e0f9a2b4a58327bebde36c7da75aa2
author user2 <user2@example.com> 1752194028 -0700
committer user2 <user2@example.com> 1752194028 -0700
gpgsig -----BEGIN SSH SIGNATURE-----
@ -68,7 +68,7 @@ init project
defer test.MockVariableValue(&setting.Repository.Signing.SigningEmail, "gitea@fake.local")()
defer test.MockVariableValue(&setting.Repository.Signing.TrustedSSHKeys, []string{"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH6Y4idVaW3E+bLw1uqoAfJD7o5Siu+HqS51E9oQLPE9"})()
commit, err := git.CommitFromReader(nil, git.Sha1ObjectFormat.EmptyObjectID(), strings.NewReader(`tree 9a93ffa76e8b72bdb6431910b3a506fa2b39f42e
commit, err := git.CommitFromReader(git.Sha1ObjectFormat.EmptyObjectID(), strings.NewReader(`tree 9a93ffa76e8b72bdb6431910b3a506fa2b39f42e
author User Two <user2@example.com> 1749230009 +0200
committer User Two <user2@example.com> 1749230009 +0200
gpgsig -----BEGIN SSH SIGNATURE-----

View File

@ -212,7 +212,7 @@ Loop:
if commit.Signature == nil {
return false, nil, nil, &ErrWontSign{parentSigned}
}
verification := ParseCommitWithSignature(ctx, commit)
verification := ParseCommitWithSignature(ctx, gitRepo, commit)
if !verification.Verified {
return false, nil, nil, &ErrWontSign{parentSigned}
}
@ -270,7 +270,7 @@ Loop:
if commit.Signature == nil {
return false, nil, nil, &ErrWontSign{parentSigned}
}
verification := ParseCommitWithSignature(ctx, commit)
verification := ParseCommitWithSignature(ctx, gitRepo, commit)
if !verification.Verified {
return false, nil, nil, &ErrWontSign{parentSigned}
}
@ -343,7 +343,7 @@ Loop:
if err != nil {
return false, nil, nil, err
}
verification := ParseCommitWithSignature(ctx, commit)
verification := ParseCommitWithSignature(ctx, gitRepo, commit)
if !verification.Verified {
return false, nil, nil, &ErrWontSign{baseSigned}
}
@ -359,7 +359,7 @@ Loop:
if err != nil {
return false, nil, nil, err
}
verification := ParseCommitWithSignature(ctx, commit)
verification := ParseCommitWithSignature(ctx, gitRepo, commit)
if !verification.Verified {
return false, nil, nil, &ErrWontSign{headSigned}
}
@ -375,21 +375,25 @@ Loop:
if err != nil {
return false, nil, nil, err
}
verification := ParseCommitWithSignature(ctx, commit)
verification := ParseCommitWithSignature(ctx, gitRepo, commit)
if !verification.Verified {
return false, nil, nil, &ErrWontSign{commitsSigned}
}
// need to work out merge-base
mergeBaseCommit, _, err := gitRepo.GetMergeBase("", baseCommit, headCommit)
mergeBaseCommitID, _, err := gitRepo.GetMergeBase("", baseCommit, headCommit)
if err != nil {
return false, nil, nil, err
}
commitList, err := commit.CommitsBeforeUntil(mergeBaseCommit)
mergeBaseCommit, err := gitRepo.GetCommit(mergeBaseCommitID)
if err != nil {
return false, nil, nil, err
}
commitList, err := gitRepo.CommitsBetween(commit, mergeBaseCommit)
if err != nil {
return false, nil, nil, err
}
for _, commit := range commitList {
verification := ParseCommitWithSignature(ctx, commit)
verification := ParseCommitWithSignature(ctx, gitRepo, commit)
if !verification.Verified {
return false, nil, nil, &ErrWontSign{commitsSigned}
}

View File

@ -209,7 +209,7 @@ func (r *Repository) GetCommitsCount() (int64, error) {
contextName := r.RefFullName.ShortName()
isRef := r.RefFullName.IsBranch() || r.RefFullName.IsTag()
return cache.GetInt64(r.Repository.GetCommitsCountCacheKey(contextName, isRef), func() (int64, error) {
return r.Commit.CommitsCount()
return r.GitRepo.CommitsCount(r.Commit.ID.String())
})
}
@ -256,7 +256,7 @@ func (r *Repository) GetEditorconfig(optCommit ...*git.Commit) (cfg *editorconfi
return nil, nil, err
}
}
treeEntry, err := commit.GetTreeEntryByPath(".editorconfig")
treeEntry, err := git.NewTree(r.GitRepo, commit.TreeID).GetTreeEntryByPath(".editorconfig")
if err != nil {
return nil, nil, err
}

View File

@ -61,7 +61,7 @@ func ToEmailSearch(email *user_model.SearchEmailResult) *api.Email {
}
// ToBranch convert a git.Commit and git.Branch to an api.Branch
func ToBranch(ctx context.Context, repo *repo_model.Repository, branchName string, c *git.Commit, bp *git_model.ProtectedBranch, user *user_model.User, isRepoAdmin bool) (*api.Branch, error) {
func ToBranch(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, branchName string, c *git.Commit, bp *git_model.ProtectedBranch, user *user_model.User, isRepoAdmin bool) (*api.Branch, error) {
if bp == nil {
var hasPerm bool
var canPush bool
@ -81,7 +81,7 @@ func ToBranch(ctx context.Context, repo *repo_model.Repository, branchName strin
return &api.Branch{
Name: branchName,
Commit: ToPayloadCommit(ctx, repo, c),
Commit: ToPayloadCommit(ctx, repo, gitRepo, c),
Protected: false,
RequiredApprovals: 0,
EnableStatusCheck: false,
@ -93,7 +93,7 @@ func ToBranch(ctx context.Context, repo *repo_model.Repository, branchName strin
branch := &api.Branch{
Name: branchName,
Commit: ToPayloadCommit(ctx, repo, c),
Commit: ToPayloadCommit(ctx, repo, gitRepo, c),
Protected: true,
RequiredApprovals: bp.RequiredApprovals,
EnableStatusCheck: bp.EnableStatusCheck,
@ -390,11 +390,11 @@ func ToActionWorkflowJob(ctx context.Context, repo *repo_model.Repository, task
}, nil
}
func getActionWorkflowEntry(ctx context.Context, repo *repo_model.Repository, commit *git.Commit, folder string, entry *git.TreeEntry) *api.ActionWorkflow {
func getActionWorkflowEntry(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, commit *git.Commit, folder string, entry *git.TreeEntry) *api.ActionWorkflow {
cfgUnit := repo.MustGetUnit(ctx, unit.TypeActions)
cfg := cfgUnit.ActionsConfig()
defaultBranch, _ := commit.GetBranchName()
defaultBranch, _ := gitRepo.GetClosestBranchName(commit)
workflowURL := fmt.Sprintf("%s/actions/workflows/%s", repo.APIURL(), util.PathEscapeSegments(entry.Name()))
workflowRepoURL := fmt.Sprintf("%s/src/branch/%s/%s/%s", repo.HTMLURL(ctx), util.PathEscapeSegments(defaultBranch), util.PathEscapeSegments(folder), util.PathEscapeSegments(entry.Name()))
@ -455,14 +455,14 @@ func ListActionWorkflows(ctx context.Context, gitrepo *git.Repository, repo *rep
return nil, err
}
folder, entries, err := actions.ListWorkflows(defaultBranchCommit)
folder, entries, err := actions.ListWorkflows(git.NewTree(gitrepo, defaultBranchCommit.TreeID))
if err != nil {
return nil, err
}
workflows := make([]*api.ActionWorkflow, len(entries))
for i, entry := range entries {
workflows[i] = getActionWorkflowEntry(ctx, repo, defaultBranchCommit, folder, entry)
workflows[i] = getActionWorkflowEntry(ctx, repo, gitrepo, defaultBranchCommit, folder, entry)
}
return workflows, nil
@ -530,8 +530,8 @@ func ToActionRunner(ctx context.Context, runner *actions_model.ActionRunner) *ap
}
// ToVerification convert a git.Commit.Signature to an api.PayloadCommitVerification
func ToVerification(ctx context.Context, c *git.Commit) *api.PayloadCommitVerification {
verif := asymkey_service.ParseCommitWithSignature(ctx, c)
func ToVerification(ctx context.Context, gitRepo *git.Repository, c *git.Commit) *api.PayloadCommitVerification {
verif := asymkey_service.ParseCommitWithSignature(ctx, gitRepo, c)
commitVerification := &api.PayloadCommitVerification{
Verified: verif.Verified,
Reason: verif.Reason,
@ -697,7 +697,7 @@ func ToTeams(ctx context.Context, teams []*organization.Team, loadOrgs bool) ([]
}
// ToAnnotatedTag convert git.Tag to api.AnnotatedTag
func ToAnnotatedTag(ctx context.Context, repo *repo_model.Repository, t *git.Tag, c *git.Commit) *api.AnnotatedTag {
func ToAnnotatedTag(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, t *git.Tag, c *git.Commit) *api.AnnotatedTag {
return &api.AnnotatedTag{
Tag: t.Name,
SHA: t.ID.String(),
@ -705,7 +705,7 @@ func ToAnnotatedTag(ctx context.Context, repo *repo_model.Repository, t *git.Tag
Message: t.Message,
URL: util.URLJoin(repo.APIURL(), "git/tags", t.ID.String()),
Tagger: ToCommitUser(t.Tagger),
Verification: ToVerification(ctx, c),
Verification: ToVerification(ctx, gitRepo, c),
}
}

View File

@ -39,7 +39,7 @@ func ToCommitMeta(repo *repo_model.Repository, tag *git.Tag) *api.CommitMeta {
}
// ToPayloadCommit convert a git.Commit to api.PayloadCommit
func ToPayloadCommit(ctx context.Context, repo *repo_model.Repository, c *git.Commit) *api.PayloadCommit {
func ToPayloadCommit(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, c *git.Commit) *api.PayloadCommit {
authorUsername := ""
if author, err := user_model.GetUserByEmail(ctx, c.Author.Email); err == nil {
authorUsername = author.Name
@ -69,7 +69,7 @@ func ToPayloadCommit(ctx context.Context, repo *repo_model.Repository, c *git.Co
UserName: committerUsername,
},
Timestamp: c.Author.When,
Verification: ToVerification(ctx, c),
Verification: ToVerification(ctx, gitRepo, c),
}
}
@ -185,7 +185,7 @@ func ToCommit(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Rep
// Retrieve verification for commit
if opts.Verification {
res.RepoCommit.Verification = ToVerification(ctx, commit)
res.RepoCommit.Verification = ToVerification(ctx, gitRepo, commit)
}
// Retrieve files affected by the commit

View File

@ -17,7 +17,7 @@ import (
)
// ParseCommitsWithSignature checks if signaute of commits are corresponding to users gpg keys.
func ParseCommitsWithSignature(ctx context.Context, repo *repo_model.Repository, oldCommits []*user_model.UserCommit, repoTrustModel repo_model.TrustModelType) ([]*asymkey_model.SignCommit, error) {
func ParseCommitsWithSignature(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, oldCommits []*user_model.UserCommit, repoTrustModel repo_model.TrustModelType) ([]*asymkey_model.SignCommit, error) {
newCommits := make([]*asymkey_model.SignCommit, 0, len(oldCommits))
keyMap := map[string]bool{}
@ -37,7 +37,7 @@ func ParseCommitsWithSignature(ctx context.Context, repo *repo_model.Repository,
committerUser := emailUsers.GetByEmail(c.Committer.Email) // FIXME: why ValidateCommitsWithEmails uses "Author", but ParseCommitsWithSignature uses "Committer"?
signCommit := &asymkey_model.SignCommit{
UserCommit: c,
Verification: asymkey_service.ParseCommitWithSignatureCommitter(ctx, c.Commit, committerUser),
Verification: asymkey_service.ParseCommitWithSignatureCommitter(ctx, gitRepo, c.Commit, committerUser),
}
isOwnerMemberCollaborator := func(user *user_model.User) (bool, error) {
@ -52,7 +52,7 @@ func ParseCommitsWithSignature(ctx context.Context, repo *repo_model.Repository,
}
// ConvertFromGitCommit converts git commits into SignCommitWithStatuses
func ConvertFromGitCommit(ctx context.Context, commits []*git.Commit, repo *repo_model.Repository) ([]*git_model.SignCommitWithStatuses, error) {
func ConvertFromGitCommit(ctx context.Context, commits []*git.Commit, repo *repo_model.Repository, gitRepo *git.Repository) ([]*git_model.SignCommitWithStatuses, error) {
validatedCommits, err := user_model.ValidateCommitsWithEmails(ctx, commits)
if err != nil {
return nil, err
@ -60,6 +60,7 @@ func ConvertFromGitCommit(ctx context.Context, commits []*git.Commit, repo *repo
signedCommits, err := ParseCommitsWithSignature(
ctx,
repo,
gitRepo,
validatedCommits,
repo.GetTrustModel(),
)

View File

@ -97,7 +97,7 @@ func validateGitDiffTreeArguments(gitRepo *git.Repository, useMergeBase bool, ba
return false, objectFormat.EmptyTree().String(), headCommitID, nil
}
baseCommit, err := headCommit.Parent(0)
baseCommit, err := gitRepo.ParentCommit(headCommit, 0)
if err != nil {
return false, "", "", fmt.Errorf("baseSha is '', attempted to use parent of commit %s, got error: %v", headCommit.ID.String(), err)
}

View File

@ -421,17 +421,17 @@ type DiffLimitedContent struct {
}
// GetTailSectionAndLimitedContent creates a fake DiffLineSection if the last section is not the end of the file
func (diffFile *DiffFile) GetTailSectionAndLimitedContent(leftCommit, rightCommit *git.Commit) (_ *DiffSection, diffLimitedContent DiffLimitedContent) {
func (diffFile *DiffFile) GetTailSectionAndLimitedContent(gitRepo *git.Repository, leftCommit, rightCommit *git.Commit) (_ *DiffSection, diffLimitedContent DiffLimitedContent) {
var leftLineCount, rightLineCount int
diffLimitedContent = DiffLimitedContent{}
if diffFile.IsBin || diffFile.IsLFSFile {
return nil, diffLimitedContent
}
if (diffFile.Type == DiffFileDel || diffFile.Type == DiffFileChange) && leftCommit != nil {
leftLineCount, diffLimitedContent.LeftContent = getCommitFileLineCountAndLimitedContent(leftCommit, diffFile.OldName)
leftLineCount, diffLimitedContent.LeftContent = getCommitFileLineCountAndLimitedContent(gitRepo, leftCommit, diffFile.OldName)
}
if (diffFile.Type == DiffFileAdd || diffFile.Type == DiffFileChange) && rightCommit != nil {
rightLineCount, diffLimitedContent.RightContent = getCommitFileLineCountAndLimitedContent(rightCommit, diffFile.OldName)
rightLineCount, diffLimitedContent.RightContent = getCommitFileLineCountAndLimitedContent(gitRepo, rightCommit, diffFile.OldName)
}
if len(diffFile.Sections) == 0 || diffFile.Type != DiffFileChange {
return nil, diffLimitedContent
@ -505,8 +505,8 @@ func (l *limitByteWriter) Write(p []byte) (n int, err error) {
return l.buf.Write(p)
}
func getCommitFileLineCountAndLimitedContent(commit *git.Commit, filePath string) (lineCount int, limitWriter *limitByteWriter) {
blob, err := commit.GetBlobByPath(filePath)
func getCommitFileLineCountAndLimitedContent(gitRepo *git.Repository, commit *git.Commit, filePath string) (lineCount int, limitWriter *limitByteWriter) {
blob, err := git.NewTree(gitRepo, commit.TreeID).GetBlobByPath(filePath)
if err != nil {
return 0, nil
}
@ -1176,7 +1176,7 @@ func guessBeforeCommitForDiff(gitRepo *git.Repository, beforeCommitID string, af
actualBeforeCommitID = commitObjectFormat.EmptyTree()
} else {
if isBeforeCommitIDEmpty {
actualBeforeCommit, err = afterCommit.Parent(0)
actualBeforeCommit, err = gitRepo.ParentCommit(afterCommit, 0)
} else {
actualBeforeCommit, err = gitRepo.GetCommit(beforeCommitID)
}
@ -1286,7 +1286,7 @@ func GetDiffForRender(ctx context.Context, repoLink string, gitRepo *git.Reposit
// Populate Submodule URLs
if diffFile.SubmoduleDiffInfo != nil {
diffFile.SubmoduleDiffInfo.PopulateURL(repoLink, diffFile, beforeCommit, afterCommit)
diffFile.SubmoduleDiffInfo.PopulateURL(gitRepo, repoLink, diffFile, beforeCommit, afterCommit)
}
if !isVendored.Has() {
@ -1298,7 +1298,7 @@ func GetDiffForRender(ctx context.Context, repoLink string, gitRepo *git.Reposit
isGenerated = optional.Some(analyze.IsGenerated(diffFile.Name))
}
diffFile.IsGenerated = isGenerated.Value()
tailSection, limitedContent := diffFile.GetTailSectionAndLimitedContent(beforeCommit, afterCommit)
tailSection, limitedContent := diffFile.GetTailSectionAndLimitedContent(gitRepo, beforeCommit, afterCommit)
if tailSection != nil {
diffFile.Sections = append(diffFile.Sections, tailSection)
}

View File

@ -15,12 +15,12 @@ import (
type SubmoduleDiffInfo struct {
SubmoduleName string
SubmoduleFile *git.CommitSubmoduleFile // it might be nil if the submodule is not found or unable to parse
SubmoduleFile *git.SubmoduleFile // it might be nil if the submodule is not found or unable to parse
NewRefID string
PreviousRefID string
}
func (si *SubmoduleDiffInfo) PopulateURL(repoLink string, diffFile *DiffFile, leftCommit, rightCommit *git.Commit) {
func (si *SubmoduleDiffInfo) PopulateURL(gitRepo *git.Repository, repoLink string, diffFile *DiffFile, leftCommit, rightCommit *git.Commit) {
si.SubmoduleName = diffFile.Name
submoduleCommit := rightCommit // If the submodule is added or updated, check at the right commit
if diffFile.IsDeleted {
@ -31,13 +31,13 @@ func (si *SubmoduleDiffInfo) PopulateURL(repoLink string, diffFile *DiffFile, le
}
submoduleFullPath := diffFile.GetDiffFileName()
submodule, err := submoduleCommit.GetSubModule(submoduleFullPath)
submodule, err := git.NewTree(gitRepo, submoduleCommit.TreeID).GetSubModule(submoduleFullPath)
if err != nil {
log.Error("Unable to PopulateURL for submodule %q: GetSubModule: %v", submoduleFullPath, err)
return // ignore the error, do not cause 500 errors for end users
}
if submodule != nil {
si.SubmoduleFile = git.NewCommitSubmoduleFile(repoLink, submoduleFullPath, submodule.URL, submoduleCommit.ID.String())
si.SubmoduleFile = git.NewSubmoduleFile(repoLink, submoduleFullPath, submodule.URL, submoduleCommit.ID.String())
}
}

View File

@ -226,7 +226,7 @@ func TestSubmoduleInfo(t *testing.T) {
assert.EqualValues(t, "aaaa...bbbb", sdi.CompareRefIDLinkHTML(ctx))
assert.EqualValues(t, "name", sdi.SubmoduleRepoLinkHTML(ctx))
sdi.SubmoduleFile = git.NewCommitSubmoduleFile("/any/repo-link", "fullpath", "https://github.com/owner/repo", "1234")
sdi.SubmoduleFile = git.NewSubmoduleFile("/any/repo-link", "fullpath", "https://github.com/owner/repo", "1234")
assert.EqualValues(t, `<a href="https://github.com/owner/repo/tree/1111">1111</a>`, sdi.CommitRefIDLinkHTML(ctx, "1111"))
assert.EqualValues(t, `<a href="https://github.com/owner/repo/compare/aaaa...bbbb">aaaa...bbbb</a>`, sdi.CompareRefIDLinkHTML(ctx))
assert.EqualValues(t, `<a href="https://github.com/owner/repo">name</a>`, sdi.SubmoduleRepoLinkHTML(ctx))

View File

@ -184,7 +184,7 @@ func LoadCommentPushCommits(ctx context.Context, c *issues_model.Comment) error
}
defer closer.Close()
c.Commits, err = git_service.ConvertFromGitCommit(ctx, gitRepo.GetCommitsFromIDs(data.CommitIDs), c.Issue.Repo)
c.Commits, err = git_service.ConvertFromGitCommit(ctx, gitRepo.GetCommitsFromIDs(data.CommitIDs), c.Issue.Repo, gitRepo)
if err != nil {
log.Debug("ConvertFromGitCommit: %v", err) // no need to show 500 error to end user when the commit does not exist
} else {

View File

@ -80,9 +80,10 @@ func PullRequestCodeOwnersReview(ctx context.Context, pr *issues_model.PullReque
return nil, err
}
tree := git.NewTree(repo, commit.TreeID)
var data string
for _, file := range codeOwnerFiles {
if blob, err := commit.GetBlobByPath(file); err == nil {
if blob, err := tree.GetBlobByPath(file); err == nil {
data, err = blob.GetBlobContent(setting.UI.MaxDisplayFileSize)
if err == nil {
break

View File

@ -47,12 +47,12 @@ func GetDefaultTemplateConfig() api.IssueConfig {
// GetTemplateConfig loads the given issue config file.
// It never returns a nil config.
func GetTemplateConfig(gitRepo *git.Repository, path string, commit *git.Commit) (api.IssueConfig, error) {
func GetTemplateConfig(gitRepo *git.Repository, path string, tree *git.Tree) (api.IssueConfig, error) {
if gitRepo == nil {
return GetDefaultTemplateConfig(), nil
}
treeEntry, err := commit.GetTreeEntryByPath(path)
treeEntry, err := tree.GetTreeEntryByPath(path)
if err != nil {
return GetDefaultTemplateConfig(), err
}
@ -124,8 +124,10 @@ func ParseTemplatesFromDefaultBranch(repo *repo.Repository, gitRepo *git.Reposit
return ret
}
tree := git.NewTree(gitRepo, commit.TreeID)
for _, dirName := range templateDirCandidates {
tree, err := commit.SubTree(dirName)
tree, err := tree.SubTree(dirName)
if err != nil {
log.Debug("get sub tree of %s: %v", dirName, err)
continue
@ -165,13 +167,15 @@ func GetTemplateConfigFromDefaultBranch(repo *repo.Repository, gitRepo *git.Repo
return GetDefaultTemplateConfig(), err
}
tree := git.NewTree(gitRepo, commit.TreeID)
for _, configName := range templateConfigCandidates {
if _, err := commit.GetTreeEntryByPath(configName + ".yaml"); err == nil {
return GetTemplateConfig(gitRepo, configName+".yaml", commit)
if _, err := tree.GetTreeEntryByPath(configName + ".yaml"); err == nil {
return GetTemplateConfig(gitRepo, configName+".yaml", tree)
}
if _, err := commit.GetTreeEntryByPath(configName + ".yml"); err == nil {
return GetTemplateConfig(gitRepo, configName+".yml", commit)
if _, err := tree.GetTreeEntryByPath(configName + ".yml"); err == nil {
return GetTemplateConfig(gitRepo, configName+".yml", tree)
}
}

View File

@ -14,6 +14,7 @@ import (
"code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/modules/charset"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/git/languagestats"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/indexer/code"
@ -62,7 +63,7 @@ func renderRepoFileCodePreview(ctx context.Context, opts markup.RenderCodePrevie
}
language, _ := languagestats.GetFileLanguage(ctx, gitRepo, opts.CommitID, opts.FilePath)
blob, err := commit.GetBlobByPath(opts.FilePath)
blob, err := git.NewTree(gitRepo, commit.TreeID).GetBlobByPath(opts.FilePath)
if err != nil {
return "", err
}

View File

@ -303,7 +303,7 @@ func (g *GiteaLocalUploader) CreateReleases(ctx context.Context, releases ...*ba
return fmt.Errorf("GetTagCommit[%v]: %w", rel.TagName, err)
}
rel.Sha1 = commit.ID.String()
rel.NumCommits, err = commit.CommitsCount()
rel.NumCommits, err = g.gitRepo.CommitsCount(commit.ID.String())
if err != nil {
return fmt.Errorf("CommitsCount: %w", err)
}

View File

@ -72,7 +72,7 @@ func getMergeMessage(ctx context.Context, baseGitRepo *git.Repository, pr *issue
if err != nil {
return "", "", err
}
templateContent, err := commit.GetFileContent(templateFilepath, setting.Repository.PullRequest.DefaultMergeMessageSize)
templateContent, err := git.NewTree(baseGitRepo, commit.TreeID).GetFileContent(templateFilepath, setting.Repository.PullRequest.DefaultMergeMessageSize)
if err != nil {
if !git.IsErrNotExist(err) {
return "", "", err

View File

@ -1040,7 +1040,7 @@ func IsHeadEqualWithBranch(ctx context.Context, pr *issues_model.PullRequest, br
return false, err
}
}
return baseCommit.HasPreviousCommit(headCommit.ID)
return baseGitRepo.HasPreviousCommit(baseCommit, headCommit.ID)
}
type CommitInfo struct {

View File

@ -148,7 +148,7 @@ func createTag(ctx context.Context, gitRepo *git.Repository, rel *repo_model.Rel
}
rel.Sha1 = commit.ID.String()
rel.NumCommits, err = commit.CommitsCount()
rel.NumCommits, err = gitRepo.CommitsCount(commit.ID.String())
if err != nil {
return false, fmt.Errorf("CommitsCount: %w", err)
}

View File

@ -733,7 +733,7 @@ func GetBranchDivergingInfo(ctx reqctx.RequestContext, baseRepo *repo_model.Repo
if err != nil {
return nil, err
}
hasPreviousCommit, _ := headCommit.HasPreviousCommit(baseCommitID)
hasPreviousCommit, _ := headGitRepo.HasPreviousCommit(headCommit, baseCommitID)
info.BaseHasNewCommits = !hasPreviousCommit
return info, nil
}

View File

@ -19,12 +19,17 @@ func CacheRef(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Rep
}
if gitRepo.LastCommitCache == nil {
commitsCount, err := cache.GetInt64(repo.GetCommitsCountCacheKey(fullRefName.ShortName(), true), commit.CommitsCount)
commitsCount, err := cache.GetInt64(repo.GetCommitsCountCacheKey(fullRefName.ShortName(), true), func() (int64, error) {
return git.CommitsCount(gitRepo.Ctx, git.CommitsCountOptions{
RepoPath: gitRepo.Path,
Revision: []string{commit.ID.String()},
})
})
if err != nil {
return err
}
gitRepo.LastCommitCache = git.NewLastCommitCache(commitsCount, repo.FullName(), gitRepo, cache.GetCache())
}
return commit.CacheCommit(ctx)
return gitRepo.CacheCommit(ctx, commit)
}

View File

@ -140,8 +140,8 @@ func CherryPick(ctx context.Context, repo *repo_model.Repository, doer *user_mod
return nil, err
}
fileCommitResponse, _ := GetFileCommitResponse(repo, commit) // ok if fails, then will be nil
verification := GetPayloadCommitVerification(ctx, commit)
fileCommitResponse, _ := GetFileCommitResponse(repo, t.gitRepo, commit) // ok if fails, then will be nil
verification := GetPayloadCommitVerification(ctx, t.gitRepo, commit)
fileResponse := &structs.FileResponse{
Commit: fileCommitResponse,
Verification: verification,

View File

@ -12,9 +12,9 @@ import (
)
// GetPayloadCommitVerification returns the verification information of a commit
func GetPayloadCommitVerification(ctx context.Context, commit *git.Commit) *structs.PayloadCommitVerification {
func GetPayloadCommitVerification(ctx context.Context, gitRepo *git.Repository, commit *git.Commit) *structs.PayloadCommitVerification {
verification := &structs.PayloadCommitVerification{}
commitVerification := asymkey_service.ParseCommitWithSignature(ctx, commit)
commitVerification := asymkey_service.ParseCommitWithSignature(ctx, gitRepo, commit)
if commit.Signature != nil {
verification.Signature = commit.Signature.Signature
verification.Payload = commit.Signature.Payload

View File

@ -46,7 +46,7 @@ type GetContentsOrListOptions struct {
// GetContentsOrList gets the metadata of a file's contents (*ContentsResponse) if treePath not a tree
// directory, otherwise a listing of file contents ([]*ContentsResponse). Ref can be a branch, commit or tag
func GetContentsOrList(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, refCommit *utils.RefCommit, opts GetContentsOrListOptions) (ret api.ContentsExtResponse, _ error) {
entry, err := prepareGetContentsEntry(refCommit, &opts.TreePath)
entry, err := prepareGetContentsEntry(gitRepo, refCommit, &opts.TreePath)
if repo.IsEmpty && opts.TreePath == "" {
return api.ContentsExtResponse{DirContents: make([]*api.ContentsResponse, 0)}, nil
}
@ -61,7 +61,8 @@ func GetContentsOrList(ctx context.Context, repo *repo_model.Repository, gitRepo
}
// list directory contents
gitTree, err := refCommit.Commit.SubTree(opts.TreePath)
tree := git.NewTree(gitRepo, refCommit.Commit.TreeID)
gitTree, err := tree.SubTree(opts.TreePath)
if err != nil {
return ret, err
}
@ -99,7 +100,7 @@ func GetObjectTypeFromTreeEntry(entry *git.TreeEntry) ContentType {
}
}
func prepareGetContentsEntry(refCommit *utils.RefCommit, treePath *string) (*git.TreeEntry, error) {
func prepareGetContentsEntry(gitRepo *git.Repository, refCommit *utils.RefCommit, treePath *string) (*git.TreeEntry, error) {
// Check that the path given in opts.treePath is valid (not a git path)
cleanTreePath := CleanGitTreePath(*treePath)
if cleanTreePath == "" && *treePath != "" {
@ -113,12 +114,13 @@ func prepareGetContentsEntry(refCommit *utils.RefCommit, treePath *string) (*git
return nil, util.NewNotExistErrorf("no commit found for the ref [ref: %s]", refCommit.RefName)
}
return refCommit.Commit.GetTreeEntryByPath(*treePath)
tree := git.NewTree(gitRepo, refCommit.Commit.TreeID)
return tree.GetTreeEntryByPath(*treePath)
}
// GetFileContents gets the metadata on a file's contents. Ref can be a branch, commit or tag
func GetFileContents(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, refCommit *utils.RefCommit, opts GetContentsOrListOptions) (*api.ContentsResponse, error) {
entry, err := prepareGetContentsEntry(refCommit, &opts.TreePath)
entry, err := prepareGetContentsEntry(gitRepo, refCommit, &opts.TreePath)
if err != nil {
return nil, err
}
@ -146,13 +148,15 @@ func getFileContentsByEntryInternal(_ context.Context, repo *repo_model.Reposito
},
}
tree := git.NewTree(gitRepo, commit.TreeID)
if opts.IncludeCommitMetadata || opts.IncludeCommitMessage {
err = gitRepo.AddLastCommitCache(repo.GetCommitsCountCacheKey(refCommit.InputRef, refType != git.RefTypeCommit), repo.FullName(), refCommit.CommitID)
if err != nil {
return nil, err
}
lastCommit, err := refCommit.Commit.GetCommitByPath(opts.TreePath)
lastCommit, err := gitRepo.GetCommitByPath(refCommit.Commit.ID, opts.TreePath)
if err != nil {
return nil, err
}
@ -202,7 +206,7 @@ func getFileContentsByEntryInternal(_ context.Context, repo *repo_model.Reposito
contentsResponse.Target = &targetFromContent
} else if entry.IsSubModule() {
contentsResponse.Type = string(ContentTypeSubmodule)
submodule, err := commit.GetSubModule(opts.TreePath)
submodule, err := tree.GetSubModule(opts.TreePath)
if err != nil {
return nil, err
}

View File

@ -45,8 +45,8 @@ func GetContentsListFromTreePaths(ctx context.Context, repo *repo_model.Reposito
func GetFilesResponseFromCommit(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, refCommit *utils.RefCommit, treeNames []string) (*api.FilesResponse, error) {
files := GetContentsListFromTreePaths(ctx, repo, gitRepo, refCommit, treeNames)
fileCommitResponse, _ := GetFileCommitResponse(repo, refCommit.Commit) // ok if fails, then will be nil
verification := GetPayloadCommitVerification(ctx, refCommit.Commit)
fileCommitResponse, _ := GetFileCommitResponse(repo, gitRepo, refCommit.Commit) // ok if fails, then will be nil
verification := GetPayloadCommitVerification(ctx, gitRepo, refCommit.Commit)
filesResponse := &api.FilesResponse{
Files: files,
Commit: fileCommitResponse,
@ -70,18 +70,19 @@ func GetFileResponseFromFilesResponse(filesResponse *api.FilesResponse, index in
}
// GetFileCommitResponse Constructs a FileCommitResponse from a Commit object
func GetFileCommitResponse(repo *repo_model.Repository, commit *git.Commit) (*api.FileCommitResponse, error) {
func GetFileCommitResponse(repo *repo_model.Repository, gitRepo *git.Repository, commit *git.Commit) (*api.FileCommitResponse, error) {
if repo == nil {
return nil, errors.New("repo cannot be nil")
}
if commit == nil {
return nil, errors.New("commit cannot be nil")
}
commitURL, _ := url.Parse(repo.APIURL() + "/git/commits/" + url.PathEscape(commit.ID.String()))
commitTreeURL, _ := url.Parse(repo.APIURL() + "/git/trees/" + url.PathEscape(commit.Tree.ID.String()))
commitTreeURL, _ := url.Parse(repo.APIURL() + "/git/trees/" + url.PathEscape(commit.TreeID.String()))
parents := make([]*api.CommitMeta, commit.ParentCount())
for i := 0; i <= commit.ParentCount(); i++ {
if parent, err := commit.Parent(i); err == nil && parent != nil {
if parent, err := gitRepo.ParentCommit(commit, i); err == nil && parent != nil {
parentCommitURL, _ := url.Parse(repo.APIURL() + "/git/commits/" + url.PathEscape(parent.ID.String()))
parents[i] = &api.CommitMeta{
SHA: parent.ID.String(),
@ -113,7 +114,7 @@ func GetFileCommitResponse(repo *repo_model.Repository, commit *git.Commit) (*ap
Message: commit.Message(),
Tree: &api.CommitMeta{
URL: commitTreeURL.String(),
SHA: commit.Tree.ID.String(),
SHA: commit.TreeID.String(),
},
Parents: parents,
}

Some files were not shown because too many files have changed in this diff Show More