Files
gitea/modules/git/repo_ref.go
wxiaoguang 9dc04289aa refactor: make git package handle all git operations (#38543)
before: gitrepo vs git packages
after: git package fully handle all git operations

by the way, use `WithRepo(repo)` instead of `WithDir(repo.Path)` to hide
path details.

benefits:

1. remove all unnecessary wrappers, developers no need to struggle with
"which package should be used"
2. simplify code, RepositoryFacade can (will) be used everywhere, all
"path" details are (will be) hidden
2026-07-20 16:07:38 +00:00

99 lines
3.2 KiB
Go

// Copyright 2018 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package git
import (
"context"
"strings"
"gitea.dev/modules/git/gitcmd"
"gitea.dev/modules/setting"
"gitea.dev/modules/util"
)
// GetRefs returns all references of the repository.
func (repo *Repository) GetRefs(ctx context.Context) ([]*Reference, error) {
return repo.GetRefsFiltered(ctx, "")
}
// ListOccurrences lists all refs of the given refType the given commit appears in sorted by creation date DESC
// refType should only be a literal "branch" or "tag" and nothing else
func (repo *Repository) ListOccurrences(ctx context.Context, refType, commitSHA string) ([]string, error) {
cmd := gitcmd.NewCommand()
switch refType {
case "branch":
cmd.AddArguments("branch")
case "tag":
cmd.AddArguments("tag")
default:
return nil, util.NewInvalidArgumentErrorf(`can only use "branch" or "tag" for refType, but got %q`, refType)
}
stdout, _, err := cmd.AddArguments("--no-color", "--sort=-creatordate", "--contains").
AddDynamicArguments(commitSHA).WithRepo(repo).RunStdString(ctx)
if err != nil {
return nil, err
}
refs := strings.Split(strings.TrimSpace(stdout), "\n")
if refType == "branch" {
return parseBranches(refs), nil
}
return parseTags(refs), nil
}
func parseBranches(refs []string) []string {
results := make([]string, 0, len(refs))
for _, ref := range refs {
if strings.HasPrefix(ref, "* ") { // current branch (main branch)
results = append(results, ref[len("* "):])
} else if strings.HasPrefix(ref, " ") { // all other branches
results = append(results, ref[len(" "):])
} else if ref != "" {
results = append(results, ref)
}
}
return results
}
func parseTags(refs []string) []string {
results := make([]string, 0, len(refs))
for _, ref := range refs {
if ref != "" {
results = append(results, ref)
}
}
return results
}
// UnstableGuessRefByShortName does the best guess to see whether a "short name" provided by user is a branch, tag or commit.
// It could guess wrongly if the input is already ambiguous. For example:
// * "refs/heads/the-name" vs "refs/heads/refs/heads/the-name"
// * "refs/tags/1234567890" vs commit "1234567890"
// In most cases, it SHOULD AVOID using this function, unless there is an irresistible reason (eg: make API friendly to end users)
// If the function is used, the caller SHOULD CHECK the ref type carefully.
func (repo *Repository) UnstableGuessRefByShortName(ctx context.Context, shortName string) RefName {
if repo.IsBranchExist(ctx, shortName) {
return RefNameFromBranch(shortName)
}
if repo.IsTagExist(ctx, shortName) {
return RefNameFromTag(shortName)
}
if strings.HasPrefix(shortName, "refs/") {
if repo.IsReferenceExist(ctx, shortName) {
return RefName(shortName)
}
}
commit, err := repo.GetCommit(ctx, shortName)
if err == nil {
commitIDString := commit.ID.String()
// make sure the "shortName" is either partial commit ID, or it is HEAD
if strings.HasPrefix(commitIDString, shortName) || shortName == RefNameHead {
return RefName(commitIDString)
} else {
setting.PanicInDevOrTesting("abuse of UnstableGuessRefByShortName, queried %s, got %s", shortName, commitIDString)
}
}
return ""
}