mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 08:30:25 +08:00 
			
		
		
		
	Abstract hash function usage (#28138)
Refactor Hash interfaces and centralize hash function. This will allow easier introduction of different hash function later on. This forms the "no-op" part of the SHA256 enablement patch.
This commit is contained in:
		@@ -9,7 +9,6 @@ import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
@@ -36,10 +35,6 @@ type ArchiveRequest struct {
 | 
			
		||||
	CommitID string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SHA1 hashes will only go up to 40 characters, but SHA256 hashes will go all
 | 
			
		||||
// the way to 64.
 | 
			
		||||
var shaRegex = regexp.MustCompile(`^[0-9a-f]{4,64}$`)
 | 
			
		||||
 | 
			
		||||
// ErrUnknownArchiveFormat request archive format is not supported
 | 
			
		||||
type ErrUnknownArchiveFormat struct {
 | 
			
		||||
	RequestFormat string
 | 
			
		||||
@@ -96,30 +91,13 @@ func NewRequest(repoID int64, repo *git.Repository, uri string) (*ArchiveRequest
 | 
			
		||||
 | 
			
		||||
	r.refName = strings.TrimSuffix(uri, ext)
 | 
			
		||||
 | 
			
		||||
	var err error
 | 
			
		||||
	// Get corresponding commit.
 | 
			
		||||
	if repo.IsBranchExist(r.refName) {
 | 
			
		||||
		r.CommitID, err = repo.GetBranchCommitID(r.refName)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	} else if repo.IsTagExist(r.refName) {
 | 
			
		||||
		r.CommitID, err = repo.GetTagCommitID(r.refName)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	} else if shaRegex.MatchString(r.refName) {
 | 
			
		||||
		if repo.IsCommitExist(r.refName) {
 | 
			
		||||
			r.CommitID = r.refName
 | 
			
		||||
		} else {
 | 
			
		||||
			return nil, git.ErrNotExist{
 | 
			
		||||
				ID: r.refName,
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
	commitID, err := repo.ConvertToGitID(r.refName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, RepoRefNotFoundError{RefName: r.refName}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r.CommitID = commitID.String()
 | 
			
		||||
	return r, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -377,6 +377,11 @@ func DeleteBranch(ctx context.Context, doer *user_model.User, repo *repo_model.R
 | 
			
		||||
		return fmt.Errorf("GetBranch: %vc", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	objectFormat, err := gitRepo.GetObjectFormat()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if rawBranch.IsDeleted {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
@@ -403,7 +408,7 @@ func DeleteBranch(ctx context.Context, doer *user_model.User, repo *repo_model.R
 | 
			
		||||
		&repo_module.PushUpdateOptions{
 | 
			
		||||
			RefFullName:  git.RefNameFromBranch(branchName),
 | 
			
		||||
			OldCommitID:  commit.ID.String(),
 | 
			
		||||
			NewCommitID:  git.EmptySHA,
 | 
			
		||||
			NewCommitID:  objectFormat.Empty().String(),
 | 
			
		||||
			PusherID:     doer.ID,
 | 
			
		||||
			PusherName:   doer.Name,
 | 
			
		||||
			RepoUserName: repo.OwnerName,
 | 
			
		||||
 
 | 
			
		||||
@@ -192,7 +192,7 @@ func ReinitMissingRepositories(ctx context.Context) error {
 | 
			
		||||
		default:
 | 
			
		||||
		}
 | 
			
		||||
		log.Trace("Initializing %d/%d...", repo.OwnerID, repo.ID)
 | 
			
		||||
		if err := git.InitRepository(ctx, repo.RepoPath(), true); err != nil {
 | 
			
		||||
		if err := git.InitRepository(ctx, repo.RepoPath(), true, repo.ObjectFormat); err != nil {
 | 
			
		||||
			log.Error("Unable (re)initialize repository %d at %s. Error: %v", repo.ID, repo.RepoPath(), err)
 | 
			
		||||
			if err2 := system_model.CreateRepositoryNotice("InitRepository [%d]: %v", repo.ID, err); err2 != nil {
 | 
			
		||||
				log.Error("CreateRepositoryNotice: %v", err2)
 | 
			
		||||
 
 | 
			
		||||
@@ -43,6 +43,7 @@ type CreateRepoOptions struct {
 | 
			
		||||
	Status         repo_model.RepositoryStatus
 | 
			
		||||
	TrustModel     repo_model.TrustModelType
 | 
			
		||||
	MirrorInterval string
 | 
			
		||||
	ObjectFormat   git.ObjectFormat
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func prepareRepoCommit(ctx context.Context, repo *repo_model.Repository, tmpDir, repoPath string, opts CreateRepoOptions) error {
 | 
			
		||||
@@ -134,7 +135,7 @@ func prepareRepoCommit(ctx context.Context, repo *repo_model.Repository, tmpDir,
 | 
			
		||||
 | 
			
		||||
// InitRepository initializes README and .gitignore if needed.
 | 
			
		||||
func initRepository(ctx context.Context, repoPath string, u *user_model.User, repo *repo_model.Repository, opts CreateRepoOptions) (err error) {
 | 
			
		||||
	if err = repo_module.CheckInitRepository(ctx, repo.OwnerName, repo.Name); err != nil {
 | 
			
		||||
	if err = repo_module.CheckInitRepository(ctx, repo.OwnerName, repo.Name, opts.ObjectFormat); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -209,6 +210,10 @@ func CreateRepositoryDirectly(ctx context.Context, doer, u *user_model.User, opt
 | 
			
		||||
		opts.DefaultBranch = setting.Repository.DefaultBranch
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if opts.ObjectFormat == nil {
 | 
			
		||||
		opts.ObjectFormat = git.ObjectFormatFromID(git.Sha1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Check if label template exist
 | 
			
		||||
	if len(opts.IssueLabels) > 0 {
 | 
			
		||||
		if _, err := repo_module.LoadTemplateLabelsByDisplayName(opts.IssueLabels); err != nil {
 | 
			
		||||
@@ -234,6 +239,7 @@ func CreateRepositoryDirectly(ctx context.Context, doer, u *user_model.User, opt
 | 
			
		||||
		TrustModel:                      opts.TrustModel,
 | 
			
		||||
		IsMirror:                        opts.IsMirror,
 | 
			
		||||
		DefaultBranch:                   opts.DefaultBranch,
 | 
			
		||||
		ObjectFormat:                    opts.ObjectFormat,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var rollbackRepo *repo_model.Repository
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,6 @@ import (
 | 
			
		||||
	"code.gitea.io/gitea/models"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
	user_model "code.gitea.io/gitea/models/user"
 | 
			
		||||
	"code.gitea.io/gitea/modules/git"
 | 
			
		||||
	"code.gitea.io/gitea/modules/log"
 | 
			
		||||
	"code.gitea.io/gitea/modules/structs"
 | 
			
		||||
	"code.gitea.io/gitea/services/pull"
 | 
			
		||||
@@ -48,7 +47,7 @@ func CherryPick(ctx context.Context, repo *repo_model.Repository, doer *user_mod
 | 
			
		||||
	if opts.LastCommitID == "" {
 | 
			
		||||
		opts.LastCommitID = commit.ID.String()
 | 
			
		||||
	} else {
 | 
			
		||||
		lastCommitID, err := t.gitRepo.ConvertToSHA1(opts.LastCommitID)
 | 
			
		||||
		lastCommitID, err := t.gitRepo.ConvertToGitID(opts.LastCommitID)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, fmt.Errorf("CherryPick: Invalid last commit ID: %w", err)
 | 
			
		||||
		}
 | 
			
		||||
@@ -67,7 +66,7 @@ func CherryPick(ctx context.Context, repo *repo_model.Repository, doer *user_mod
 | 
			
		||||
	}
 | 
			
		||||
	parent, err := commit.ParentID(0)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		parent = git.MustIDFromString(git.EmptyTreeSHA)
 | 
			
		||||
		parent = repo.ObjectFormat.EmptyTree()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	base, right := parent.String(), commit.ID.String()
 | 
			
		||||
 
 | 
			
		||||
@@ -29,10 +29,15 @@ func CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, creato
 | 
			
		||||
	}
 | 
			
		||||
	defer closer.Close()
 | 
			
		||||
 | 
			
		||||
	if commit, err := gitRepo.GetCommit(sha); err != nil {
 | 
			
		||||
	objectFormat, err := gitRepo.GetObjectFormat()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("GetObjectFormat[%s]: %w", repoPath, err)
 | 
			
		||||
	}
 | 
			
		||||
	commit, err := gitRepo.GetCommit(sha)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		gitRepo.Close()
 | 
			
		||||
		return fmt.Errorf("GetCommit[%s]: %w", sha, err)
 | 
			
		||||
	} else if len(sha) != git.SHAFullLength {
 | 
			
		||||
	} else if len(sha) != objectFormat.FullLength() {
 | 
			
		||||
		// use complete commit sha
 | 
			
		||||
		sha = commit.ID.String()
 | 
			
		||||
	}
 | 
			
		||||
@@ -41,7 +46,7 @@ func CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, creato
 | 
			
		||||
	if err := git_model.NewCommitStatus(ctx, git_model.NewCommitStatusOptions{
 | 
			
		||||
		Repo:         repo,
 | 
			
		||||
		Creator:      creator,
 | 
			
		||||
		SHA:          sha,
 | 
			
		||||
		SHA:          commit.ID,
 | 
			
		||||
		CommitStatus: status,
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return fmt.Errorf("NewCommitStatus[repo_id: %d, user_id: %d, sha: %s]: %w", repo.ID, creator.ID, sha, err)
 | 
			
		||||
 
 | 
			
		||||
@@ -130,7 +130,7 @@ func ApplyDiffPatch(ctx context.Context, repo *repo_model.Repository, doer *user
 | 
			
		||||
	if opts.LastCommitID == "" {
 | 
			
		||||
		opts.LastCommitID = commit.ID.String()
 | 
			
		||||
	} else {
 | 
			
		||||
		lastCommitID, err := t.gitRepo.ConvertToSHA1(opts.LastCommitID)
 | 
			
		||||
		lastCommitID, err := t.gitRepo.ConvertToGitID(opts.LastCommitID)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, fmt.Errorf("ApplyPatch: Invalid last commit ID: %w", err)
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -77,8 +77,8 @@ func (t *TemporaryUploadRepository) Clone(branch string) error {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Init the repository
 | 
			
		||||
func (t *TemporaryUploadRepository) Init() error {
 | 
			
		||||
	if err := git.InitRepository(t.ctx, t.basePath, false); err != nil {
 | 
			
		||||
func (t *TemporaryUploadRepository) Init(objectFormat git.ObjectFormat) error {
 | 
			
		||||
	if err := git.InitRepository(t.ctx, t.basePath, false, objectFormat); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	gitRepo, err := git.OpenRepository(t.ctx, t.basePath)
 | 
			
		||||
 
 | 
			
		||||
@@ -37,19 +37,21 @@ func GetTreeBySHA(ctx context.Context, repo *repo_model.Repository, gitRepo *git
 | 
			
		||||
	}
 | 
			
		||||
	apiURL := repo.APIURL()
 | 
			
		||||
	apiURLLen := len(apiURL)
 | 
			
		||||
	objectFormat, _ := gitRepo.GetObjectFormat()
 | 
			
		||||
	hashLen := objectFormat.FullLength()
 | 
			
		||||
 | 
			
		||||
	// 51 is len(sha1) + len("/git/blobs/"). 40 + 11.
 | 
			
		||||
	blobURL := make([]byte, apiURLLen+51)
 | 
			
		||||
	const gitBlobsPath = "/git/blobs/"
 | 
			
		||||
	blobURL := make([]byte, apiURLLen+hashLen+len(gitBlobsPath))
 | 
			
		||||
	copy(blobURL, apiURL)
 | 
			
		||||
	copy(blobURL[apiURLLen:], "/git/blobs/")
 | 
			
		||||
	copy(blobURL[apiURLLen:], []byte(gitBlobsPath))
 | 
			
		||||
 | 
			
		||||
	// 51 is len(sha1) + len("/git/trees/"). 40 + 11.
 | 
			
		||||
	treeURL := make([]byte, apiURLLen+51)
 | 
			
		||||
	const gitTreePath = "/git/trees/"
 | 
			
		||||
	treeURL := make([]byte, apiURLLen+hashLen+len(gitTreePath))
 | 
			
		||||
	copy(treeURL, apiURL)
 | 
			
		||||
	copy(treeURL[apiURLLen:], "/git/trees/")
 | 
			
		||||
	copy(treeURL[apiURLLen:], []byte(gitTreePath))
 | 
			
		||||
 | 
			
		||||
	// 40 is the size of the sha1 hash in hexadecimal format.
 | 
			
		||||
	copyPos := len(treeURL) - git.SHAFullLength
 | 
			
		||||
	// copyPos is at the start of the hash
 | 
			
		||||
	copyPos := len(treeURL) - hashLen
 | 
			
		||||
 | 
			
		||||
	if perPage <= 0 || perPage > setting.API.DefaultGitTreesPerPage {
 | 
			
		||||
		perPage = setting.API.DefaultGitTreesPerPage
 | 
			
		||||
 
 | 
			
		||||
@@ -155,7 +155,8 @@ func ChangeRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use
 | 
			
		||||
		if !git.IsErrBranchNotExist(err) || !repo.IsEmpty {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		if err := t.Init(); err != nil {
 | 
			
		||||
		objectFormat, _ := gitRepo.GetObjectFormat()
 | 
			
		||||
		if err := t.Init(objectFormat); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		hasOldBranch = false
 | 
			
		||||
@@ -202,7 +203,7 @@ func ChangeRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use
 | 
			
		||||
		if opts.LastCommitID == "" {
 | 
			
		||||
			opts.LastCommitID = commit.ID.String()
 | 
			
		||||
		} else {
 | 
			
		||||
			lastCommitID, err := t.gitRepo.ConvertToSHA1(opts.LastCommitID)
 | 
			
		||||
			lastCommitID, err := t.gitRepo.ConvertToGitID(opts.LastCommitID)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, fmt.Errorf("ConvertToSHA1: Invalid last commit ID: %w", err)
 | 
			
		||||
			}
 | 
			
		||||
 
 | 
			
		||||
@@ -91,7 +91,7 @@ func UploadRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use
 | 
			
		||||
		if !git.IsErrBranchNotExist(err) || !repo.IsEmpty {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		if err = t.Init(); err != nil {
 | 
			
		||||
		if err = t.Init(repo.ObjectFormat); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		hasOldBranch = false
 | 
			
		||||
 
 | 
			
		||||
@@ -78,13 +78,14 @@ func GarbageCollectLFSMetaObjectsForRepo(ctx context.Context, repo *repo_model.R
 | 
			
		||||
 | 
			
		||||
	store := lfs.NewContentStore()
 | 
			
		||||
	errStop := errors.New("STOPERR")
 | 
			
		||||
	objectFormat, _ := gitRepo.GetObjectFormat()
 | 
			
		||||
 | 
			
		||||
	err = git_model.IterateLFSMetaObjectsForRepo(ctx, repo.ID, func(ctx context.Context, metaObject *git_model.LFSMetaObject, count int64) error {
 | 
			
		||||
		if opts.NumberToCheckPerRepo > 0 && total > opts.NumberToCheckPerRepo {
 | 
			
		||||
			return errStop
 | 
			
		||||
		}
 | 
			
		||||
		total++
 | 
			
		||||
		pointerSha := git.ComputeBlobHash([]byte(metaObject.Pointer.StringContent()))
 | 
			
		||||
		pointerSha := git.ComputeBlobHash(objectFormat, []byte(metaObject.Pointer.StringContent()))
 | 
			
		||||
 | 
			
		||||
		if gitRepo.IsObjectExist(pointerSha.String()) {
 | 
			
		||||
			return git_model.MarkLFSMetaObject(ctx, metaObject.ID)
 | 
			
		||||
 
 | 
			
		||||
@@ -65,7 +65,7 @@ func PushUpdates(opts []*repo_module.PushUpdateOptions) error {
 | 
			
		||||
 | 
			
		||||
	for _, opt := range opts {
 | 
			
		||||
		if opt.IsNewRef() && opt.IsDelRef() {
 | 
			
		||||
			return fmt.Errorf("Old and new revisions are both %s", git.EmptySHA)
 | 
			
		||||
			return fmt.Errorf("Old and new revisions are both NULL")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -94,6 +94,11 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error {
 | 
			
		||||
	}
 | 
			
		||||
	defer gitRepo.Close()
 | 
			
		||||
 | 
			
		||||
	objectFormat, err := gitRepo.GetObjectFormat()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("unknown repository ObjectFormat [%s]: %w", repoPath, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err = repo_module.UpdateRepoSize(ctx, repo); err != nil {
 | 
			
		||||
		return fmt.Errorf("Failed to update size for repository: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
@@ -106,7 +111,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error {
 | 
			
		||||
		log.Trace("pushUpdates: %-v %s %s %s", repo, opts.OldCommitID, opts.NewCommitID, opts.RefFullName)
 | 
			
		||||
 | 
			
		||||
		if opts.IsNewRef() && opts.IsDelRef() {
 | 
			
		||||
			return fmt.Errorf("old and new revisions are both %s", git.EmptySHA)
 | 
			
		||||
			return fmt.Errorf("old and new revisions are both %s", objectFormat.Empty())
 | 
			
		||||
		}
 | 
			
		||||
		if opts.RefFullName.IsTag() {
 | 
			
		||||
			if pusher == nil || pusher.ID != opts.PusherID {
 | 
			
		||||
@@ -126,7 +131,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error {
 | 
			
		||||
					&repo_module.PushUpdateOptions{
 | 
			
		||||
						RefFullName: git.RefNameFromTag(tagName),
 | 
			
		||||
						OldCommitID: opts.OldCommitID,
 | 
			
		||||
						NewCommitID: git.EmptySHA,
 | 
			
		||||
						NewCommitID: objectFormat.Empty().String(),
 | 
			
		||||
					}, repo_module.NewPushCommits())
 | 
			
		||||
 | 
			
		||||
				delTags = append(delTags, tagName)
 | 
			
		||||
@@ -139,13 +144,13 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error {
 | 
			
		||||
 | 
			
		||||
				commits := repo_module.NewPushCommits()
 | 
			
		||||
				commits.HeadCommit = repo_module.CommitToPushCommit(newCommit)
 | 
			
		||||
				commits.CompareURL = repo.ComposeCompareURL(git.EmptySHA, opts.NewCommitID)
 | 
			
		||||
				commits.CompareURL = repo.ComposeCompareURL(objectFormat.Empty().String(), opts.NewCommitID)
 | 
			
		||||
 | 
			
		||||
				notify_service.PushCommits(
 | 
			
		||||
					ctx, pusher, repo,
 | 
			
		||||
					&repo_module.PushUpdateOptions{
 | 
			
		||||
						RefFullName: opts.RefFullName,
 | 
			
		||||
						OldCommitID: git.EmptySHA,
 | 
			
		||||
						OldCommitID: objectFormat.Empty().String(),
 | 
			
		||||
						NewCommitID: opts.NewCommitID,
 | 
			
		||||
					}, commits)
 | 
			
		||||
 | 
			
		||||
@@ -229,7 +234,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error {
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				oldCommitID := opts.OldCommitID
 | 
			
		||||
				if oldCommitID == git.EmptySHA && len(commits.Commits) > 0 {
 | 
			
		||||
				if oldCommitID == objectFormat.Empty().String() && len(commits.Commits) > 0 {
 | 
			
		||||
					oldCommit, err := gitRepo.GetCommit(commits.Commits[len(commits.Commits)-1].Sha1)
 | 
			
		||||
					if err != nil && !git.IsErrNotExist(err) {
 | 
			
		||||
						log.Error("unable to GetCommit %s from %-v: %v", oldCommitID, repo, err)
 | 
			
		||||
@@ -245,11 +250,11 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error {
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if oldCommitID == git.EmptySHA && repo.DefaultBranch != branch {
 | 
			
		||||
				if oldCommitID == objectFormat.Empty().String() && repo.DefaultBranch != branch {
 | 
			
		||||
					oldCommitID = repo.DefaultBranch
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if oldCommitID != git.EmptySHA {
 | 
			
		||||
				if oldCommitID != objectFormat.Empty().String() {
 | 
			
		||||
					commits.CompareURL = repo.ComposeCompareURL(oldCommitID, opts.NewCommitID)
 | 
			
		||||
				} else {
 | 
			
		||||
					commits.CompareURL = ""
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user