Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
devel:Factory:git-workflow
gitea
23894.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 23894.patch of Package gitea
From 817c3a6e21ec4bf4b73e9f79984a5a86820006ef Mon Sep 17 00:00:00 2001 From: Adam Majer <amajer@suse.de> Date: Wed, 13 Dec 2023 21:02:00 +0000 Subject: [PATCH 1/6] 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. --- cmd/hook.go | 7 +- models/git/branch_test.go | 2 +- models/git/commit_status.go | 13 +- models/repo/repo.go | 6 +- modules/context/api.go | 9 +- modules/context/repo.go | 18 ++- modules/git/batch_reader.go | 30 ++-- modules/git/blame.go | 39 ++--- modules/git/blame_test.go | 4 +- modules/git/blob_gogit.go | 2 +- modules/git/blob_nogogit.go | 2 +- modules/git/commit.go | 19 ++- modules/git/commit_convert_gogit.go | 4 +- modules/git/commit_info_gogit.go | 2 +- modules/git/commit_info_nogogit.go | 2 +- modules/git/commit_reader.go | 8 +- modules/git/commit_test.go | 6 +- modules/git/last_commit_cache.go | 10 +- modules/git/last_commit_cache_gogit.go | 3 +- modules/git/log_name_status.go | 13 +- modules/git/notes_gogit.go | 3 +- modules/git/object_format.go | 103 +++++++++++++ modules/git/object_id.go | 143 ++++++++++++++++++ modules/git/object_id_gogit.go | 28 ++++ modules/git/object_id_test.go | 21 +++ modules/git/parse_gogit.go | 16 +- modules/git/parse_gogit_test.go | 20 ++- modules/git/parse_nogogit.go | 16 +- modules/git/parse_nogogit_test.go | 22 +-- modules/git/pipeline/lfs.go | 14 +- modules/git/pipeline/lfs_nogogit.go | 39 ++--- modules/git/ref.go | 4 +- modules/git/repo.go | 31 +++- modules/git/repo_base_gogit.go | 3 + modules/git/repo_base_nogogit.go | 7 + modules/git/repo_blob.go | 2 +- modules/git/repo_blob_gogit.go | 4 +- modules/git/repo_blob_nogogit.go | 2 +- modules/git/repo_blob_test.go | 2 +- modules/git/repo_commit.go | 35 ++--- modules/git/repo_commit_gogit.go | 35 +++-- modules/git/repo_commit_nogogit.go | 25 +-- modules/git/repo_compare.go | 2 +- modules/git/repo_compare_test.go | 6 +- modules/git/repo_gpg.go | 2 +- modules/git/repo_index.go | 19 ++- modules/git/repo_language_stats_nogogit.go | 2 +- modules/git/repo_object.go | 44 +++++- modules/git/repo_ref_gogit.go | 4 +- modules/git/repo_ref_nogogit.go | 2 +- modules/git/repo_tag.go | 14 +- modules/git/repo_tag_gogit.go | 12 +- modules/git/repo_tag_nogogit.go | 8 +- modules/git/repo_tag_test.go | 15 +- modules/git/repo_tree.go | 6 +- modules/git/repo_tree_gogit.go | 14 +- modules/git/repo_tree_nogogit.go | 10 +- modules/git/sha1.go | 72 --------- modules/git/sha1_gogit.go | 19 --- modules/git/sha1_nogogit.go | 61 -------- modules/git/sha1_test.go | 20 --- modules/git/tag.go | 10 +- modules/git/tag_test.go | 10 +- modules/git/tree.go | 2 +- modules/git/tree_blob_gogit.go | 2 +- modules/git/tree_entry_gogit.go | 4 +- modules/git/tree_entry_nogogit.go | 2 +- modules/git/tree_gogit.go | 10 +- modules/git/tree_nogogit.go | 10 +- modules/indexer/code/git.go | 17 ++- modules/repository/commits_test.go | 7 +- modules/repository/generate.go | 6 +- modules/repository/init.go | 4 +- modules/repository/push.go | 6 +- routers/api/v1/repo/notes.go | 4 +- routers/api/v1/repo/repo.go | 1 + routers/api/v1/utils/git.go | 17 ++- routers/private/hook_post_receive.go | 3 +- routers/private/hook_pre_receive.go | 7 +- routers/private/hook_verification.go | 8 +- routers/private/hook_verification_test.go | 7 +- routers/web/repo/blame.go | 9 +- routers/web/repo/branch.go | 9 +- routers/web/repo/commit.go | 2 +- routers/web/repo/compare.go | 3 +- routers/web/repo/githttp.go | 2 +- routers/web/repo/repo.go | 2 + routers/web/repo/setting/lfs.go | 11 +- routers/web/repo/setting/webhook.go | 8 +- services/actions/commit_status.go | 7 +- services/agit/agit.go | 6 +- services/convert/git_commit_test.go | 10 +- services/forms/repo_form.go | 3 + services/gitdiff/gitdiff.go | 24 ++- services/migrations/common.go | 8 +- services/migrations/gitea_uploader.go | 3 +- services/migrations/gitea_uploader_test.go | 2 +- services/mirror/mirror_pull.go | 6 +- services/packages/cargo/index.go | 2 +- services/pull/check.go | 19 ++- services/pull/merge.go | 3 +- services/pull/patch.go | 9 +- services/pull/pull.go | 3 +- services/pull/temp_repo.go | 10 +- services/release/release.go | 11 +- services/repository/archiver/archiver.go | 28 +--- services/repository/branch.go | 7 +- services/repository/check.go | 2 +- services/repository/create.go | 8 +- services/repository/files/cherry_pick.go | 5 +- services/repository/files/commit.go | 11 +- services/repository/files/patch.go | 2 +- services/repository/files/temp_repo.go | 4 +- services/repository/files/tree.go | 18 ++- services/repository/files/update.go | 5 +- services/repository/files/upload.go | 2 +- services/repository/lfs.go | 3 +- services/repository/push.go | 21 ++- services/webhook/slack.go | 1 + services/wiki/wiki.go | 2 +- services/wiki/wiki_test.go | 2 +- .../git_helper_for_declarative_test.go | 2 +- 122 files changed, 946 insertions(+), 592 deletions(-) create mode 100644 modules/git/object_format.go create mode 100644 modules/git/object_id.go create mode 100644 modules/git/object_id_gogit.go create mode 100644 modules/git/object_id_test.go delete mode 100644 modules/git/sha1.go delete mode 100644 modules/git/sha1_gogit.go delete mode 100644 modules/git/sha1_nogogit.go delete mode 100644 modules/git/sha1_test.go Index: gitea-1.21.11/cmd/hook.go =================================================================== --- gitea-1.21.11.orig/cmd/hook.go +++ gitea-1.21.11/cmd/hook.go @@ -376,7 +376,9 @@ Gitea or set your environment appropriat oldCommitIDs[count] = string(fields[0]) newCommitIDs[count] = string(fields[1]) refFullNames[count] = git.RefName(fields[2]) - if refFullNames[count] == git.BranchPrefix+"master" && newCommitIDs[count] != git.EmptySHA && count == total { + + commitID, _ := git.NewIDFromString(newCommitIDs[count]) + if refFullNames[count] == git.BranchPrefix+"master" && !commitID.IsZero() && count == total { masterPushed = true } count++ @@ -672,7 +674,8 @@ Gitea or set your environment appropriat if err != nil { return err } - if rs.OldOID != git.EmptySHA { + commitID, _ := git.NewIDFromString(rs.OldOID) + if !commitID.IsZero() { err = writeDataPktLine(ctx, os.Stdout, []byte("option old-oid "+rs.OldOID)) if err != nil { return err Index: gitea-1.21.11/models/git/branch_test.go =================================================================== --- gitea-1.21.11.orig/models/git/branch_test.go +++ gitea-1.21.11/models/git/branch_test.go @@ -21,6 +21,7 @@ import ( func TestAddDeletedBranch(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + assert.EqualValues(t, git.Sha1ObjectFormat.Name(), repo.ObjectFormatName) firstBranch := unittest.AssertExistsAndLoadBean(t, &git_model.Branch{ID: 1}) assert.True(t, firstBranch.IsDeleted) Index: gitea-1.21.11/models/git/commit_status.go =================================================================== --- gitea-1.21.11.orig/models/git/commit_status.go +++ gitea-1.21.11/models/git/commit_status.go @@ -38,7 +38,7 @@ type CommitStatus struct { SHA string `xorm:"VARCHAR(64) NOT NULL INDEX UNIQUE(repo_sha_index)"` TargetURL string `xorm:"TEXT"` Description string `xorm:"TEXT"` - ContextHash string `xorm:"char(40) index"` + ContextHash string `xorm:"VARCHAR(64) index"` Context string `xorm:"TEXT"` Creator *user_model.User `xorm:"-"` CreatorID int64 @@ -114,7 +114,8 @@ WHEN NOT MATCHED // GetNextCommitStatusIndex retried 3 times to generate a resource index func GetNextCommitStatusIndex(ctx context.Context, repoID int64, sha string) (int64, error) { - if !git.IsValidSHAPattern(sha) { + _, err := git.NewIDFromString(sha) + if err != nil { return 0, git.ErrInvalidSHA{SHA: sha} } @@ -446,7 +447,7 @@ func FindRepoRecentCommitStatusContexts( type NewCommitStatusOptions struct { Repo *repo_model.Repository Creator *user_model.User - SHA string + SHA git.ObjectID CommitStatus *CommitStatus } @@ -461,10 +462,6 @@ func NewCommitStatus(ctx context.Context return fmt.Errorf("NewCommitStatus[%s, %s]: no user specified", repoPath, opts.SHA) } - if _, err := git.NewIDFromString(opts.SHA); err != nil { - return fmt.Errorf("NewCommitStatus[%s, %s]: invalid sha: %w", repoPath, opts.SHA, err) - } - ctx, committer, err := db.TxContext(ctx) if err != nil { return fmt.Errorf("NewCommitStatus[repo_id: %d, user_id: %d, sha: %s]: %w", opts.Repo.ID, opts.Creator.ID, opts.SHA, err) @@ -472,7 +469,7 @@ func NewCommitStatus(ctx context.Context defer committer.Close() // Get the next Status Index - idx, err := GetNextCommitStatusIndex(ctx, opts.Repo.ID, opts.SHA) + idx, err := GetNextCommitStatusIndex(ctx, opts.Repo.ID, opts.SHA.String()) if err != nil { return fmt.Errorf("generate commit status index failed: %w", err) } @@ -480,7 +477,7 @@ func NewCommitStatus(ctx context.Context opts.CommitStatus.Description = strings.TrimSpace(opts.CommitStatus.Description) opts.CommitStatus.Context = strings.TrimSpace(opts.CommitStatus.Context) opts.CommitStatus.TargetURL = strings.TrimSpace(opts.CommitStatus.TargetURL) - opts.CommitStatus.SHA = opts.SHA + opts.CommitStatus.SHA = opts.SHA.String() opts.CommitStatus.CreatorID = opts.Creator.ID opts.CommitStatus.RepoID = opts.Repo.ID opts.CommitStatus.Index = idx Index: gitea-1.21.11/models/repo/repo.go =================================================================== --- gitea-1.21.11.orig/models/repo/repo.go +++ gitea-1.21.11/models/repo/repo.go @@ -17,6 +17,7 @@ import ( "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/setting" @@ -179,6 +180,7 @@ type Repository struct { IsFsckEnabled bool `xorm:"NOT NULL DEFAULT true"` CloseIssuesViaCommitInAnyBranch bool `xorm:"NOT NULL DEFAULT false"` Topics []string `xorm:"TEXT JSON"` + ObjectFormatName string `xorm:"VARCHAR(6) NOT NULL DEFAULT 'sha1'"` TrustModel TrustModelType @@ -313,7 +315,7 @@ func (repo *Repository) HTMLURL() string // CommitLink make link to by commit full ID // note: won't check whether it's an right id func (repo *Repository) CommitLink(commitID string) (result string) { - if commitID == "" || commitID == "0000000000000000000000000000000000000000" { + if git.IsEmptyCommitID(commitID) { result = "" } else { result = repo.Link() + "/commit/" + url.PathEscape(commitID) Index: gitea-1.21.11/modules/context/api.go =================================================================== --- gitea-1.21.11.orig/modules/context/api.go +++ gitea-1.21.11/modules/context/api.go @@ -302,6 +302,12 @@ func RepoRefForAPI(next http.Handler) ht return } + objectFormat, err := ctx.Repo.GitRepo.GetObjectFormat() + if err != nil { + ctx.Error(http.StatusInternalServerError, "GetCommit", err) + return + } + if ref := ctx.FormTrim("ref"); len(ref) > 0 { commit, err := ctx.Repo.GitRepo.GetCommit(ref) if err != nil { @@ -319,7 +325,6 @@ func RepoRefForAPI(next http.Handler) ht return } - var err error refName := getRefName(ctx.Base, ctx.Repo, RepoRefAny) if ctx.Repo.GitRepo.IsBranchExist(refName) { @@ -336,7 +341,7 @@ func RepoRefForAPI(next http.Handler) ht return } ctx.Repo.CommitID = ctx.Repo.Commit.ID.String() - } else if len(refName) == git.SHAFullLength { + } else if len(refName) == objectFormat.FullLength() { ctx.Repo.CommitID = refName ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommit(refName) if err != nil { Index: gitea-1.21.11/modules/context/repo.go =================================================================== --- gitea-1.21.11.orig/modules/context/repo.go +++ gitea-1.21.11/modules/context/repo.go @@ -824,7 +824,9 @@ func getRefName(ctx *Base, repo *Reposit } // For legacy and API support only full commit sha parts := strings.Split(path, "/") - if len(parts) > 0 && len(parts[0]) == git.SHAFullLength { + objectFormat, _ := repo.GitRepo.GetObjectFormat() + + if len(parts) > 0 && len(parts[0]) == objectFormat.FullLength() { repo.TreePath = strings.Join(parts[1:], "/") return parts[0] } @@ -868,7 +870,9 @@ func getRefName(ctx *Base, repo *Reposit return getRefNameFromPath(ctx, repo, path, repo.GitRepo.IsTagExist) case RepoRefCommit: parts := strings.Split(path, "/") - if len(parts) > 0 && len(parts[0]) >= 7 && len(parts[0]) <= git.SHAFullLength { + objectFormat, _ := repo.GitRepo.GetObjectFormat() + + if len(parts) > 0 && len(parts[0]) >= 7 && len(parts[0]) <= objectFormat.FullLength() { repo.TreePath = strings.Join(parts[1:], "/") return parts[0] } @@ -928,6 +932,12 @@ func RepoRefByType(refType RepoRefType, } } + objectFormat, err := ctx.Repo.GitRepo.GetObjectFormat() + if err != nil { + log.Error("Cannot determine objectFormat for repository: %w", err) + ctx.Repo.Repository.MarkAsBrokenEmpty() + } + // Get default branch. if len(ctx.Params("*")) == 0 { refName = ctx.Repo.Repository.DefaultBranch @@ -994,7 +1004,7 @@ func RepoRefByType(refType RepoRefType, return cancel } ctx.Repo.CommitID = ctx.Repo.Commit.ID.String() - } else if len(refName) >= 7 && len(refName) <= git.SHAFullLength { + } else if len(refName) >= 7 && len(refName) <= objectFormat.FullLength() { ctx.Repo.IsViewCommit = true ctx.Repo.CommitID = refName @@ -1004,7 +1014,7 @@ func RepoRefByType(refType RepoRefType, return cancel } // If short commit ID add canonical link header - if len(refName) < git.SHAFullLength { + if len(refName) < objectFormat.FullLength() { ctx.RespHeader().Set("Link", fmt.Sprintf("<%s>; rel=\"canonical\"", util.URLJoin(setting.AppURL, strings.Replace(ctx.Req.URL.RequestURI(), util.PathEscapeSegments(refName), url.PathEscape(ctx.Repo.Commit.ID.String()), 1)))) } Index: gitea-1.21.11/modules/git/batch_reader.go =================================================================== --- gitea-1.21.11.orig/modules/git/batch_reader.go +++ gitea-1.21.11/modules/git/batch_reader.go @@ -148,7 +148,7 @@ func CatFileBatch(ctx context.Context, r // ReadBatchLine reads the header line from cat-file --batch // We expect: // <sha> SP <type> SP <size> LF -// sha is a 40byte not 20byte here +// sha is a hex encoded here func ReadBatchLine(rd *bufio.Reader) (sha []byte, typ string, size int64, err error) { typ, err = rd.ReadString('\n') if err != nil { @@ -233,20 +233,19 @@ headerLoop: } // git tree files are a list: -// <mode-in-ascii> SP <fname> NUL <20-byte SHA> +// <mode-in-ascii> SP <fname> NUL <binary Hash> // // Unfortunately this 20-byte notation is somewhat in conflict to all other git tools -// Therefore we need some method to convert these 20-byte SHAs to a 40-byte SHA +// Therefore we need some method to convert these binary hashes to hex hashes -// constant hextable to help quickly convert between 20byte and 40byte hashes +// constant hextable to help quickly convert between binary and hex representation const hextable = "0123456789abcdef" -// To40ByteSHA converts a 20-byte SHA into a 40-byte sha. Input and output can be the -// same 40 byte slice to support in place conversion without allocations. +// BinToHexHeash converts a binary Hash into a hex encoded one. Input and output can be the +// same byte slice to support in place conversion without allocations. // This is at least 100x quicker that hex.EncodeToString -// NB This requires that out is a 40-byte slice -func To40ByteSHA(sha, out []byte) []byte { - for i := 19; i >= 0; i-- { +func BinToHex(objectFormat ObjectFormat, sha, out []byte) []byte { + for i := objectFormat.FullLength()/2 - 1; i >= 0; i-- { v := sha[i] vhi, vlo := v>>4, v&0x0f shi, slo := hextable[vhi], hextable[vlo] @@ -260,10 +259,10 @@ func To40ByteSHA(sha, out []byte) []byte // It is recommended therefore to pass in an fnameBuf large enough to avoid almost all allocations // // Each line is composed of: -// <mode-in-ascii-dropping-initial-zeros> SP <fname> NUL <20-byte SHA> +// <mode-in-ascii-dropping-initial-zeros> SP <fname> NUL <binary HASH> // -// We don't attempt to convert the 20-byte SHA to 40-byte SHA to save a lot of time -func ParseTreeLine(rd *bufio.Reader, modeBuf, fnameBuf, shaBuf []byte) (mode, fname, sha []byte, n int, err error) { +// We don't attempt to convert the raw HASH to save a lot of time +func ParseTreeLine(objectFormat ObjectFormat, rd *bufio.Reader, modeBuf, fnameBuf, shaBuf []byte) (mode, fname, sha []byte, n int, err error) { var readBytes []byte // Read the Mode & fname @@ -306,11 +305,12 @@ func ParseTreeLine(rd *bufio.Reader, mod fnameBuf = fnameBuf[:len(fnameBuf)-1] fname = fnameBuf - // Deal with the 20-byte SHA + // Deal with the binary hash idx = 0 - for idx < 20 { + len := objectFormat.FullLength() / 2 + for idx < len { var read int - read, err = rd.Read(shaBuf[idx:20]) + read, err = rd.Read(shaBuf[idx:len]) n += read if err != nil { return mode, fname, sha, n, err Index: gitea-1.21.11/modules/git/blame.go =================================================================== --- gitea-1.21.11.orig/modules/git/blame.go +++ gitea-1.21.11/modules/git/blame.go @@ -10,8 +10,6 @@ import ( "fmt" "io" "os" - "regexp" - "strings" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/util" @@ -33,14 +31,13 @@ type BlameReader struct { done chan error lastSha *string ignoreRevsFile *string + objectFormat ObjectFormat } func (r *BlameReader) UsesIgnoreRevs() bool { return r.ignoreRevsFile != nil } -var shaLineRegex = regexp.MustCompile("^([a-z0-9]{40})") - // NextPart returns next part of blame (sequential code lines with the same commit) func (r *BlameReader) NextPart() (*BlamePart, error) { var blamePart *BlamePart @@ -52,6 +49,7 @@ func (r *BlameReader) NextPart() (*Blame } } + const previousHeader = "previous " var lineBytes []byte var isPrefix bool var err error @@ -67,21 +65,22 @@ func (r *BlameReader) NextPart() (*Blame continue } - line := string(lineBytes) - - lines := shaLineRegex.FindStringSubmatch(line) - if lines != nil { - sha1 := lines[1] + var objectID string + objectFormatLength := r.objectFormat.FullLength() + if len(lineBytes) > objectFormatLength && lineBytes[objectFormatLength] == ' ' && r.objectFormat.IsValid(string(lineBytes[0:objectFormatLength])) { + objectID = string(lineBytes[0:objectFormatLength]) + } + if len(objectID) > 0 { if blamePart == nil { blamePart = &BlamePart{ - Sha: sha1, + Sha: objectID, Lines: make([]string, 0), } } - if blamePart.Sha != sha1 { - r.lastSha = &sha1 + if blamePart.Sha != objectID { + r.lastSha = &objectID // need to munch to end of line... for isPrefix { _, isPrefix, err = r.bufferedReader.ReadLine() @@ -91,12 +90,13 @@ func (r *BlameReader) NextPart() (*Blame } return blamePart, nil } - } else if line[0] == '\t' { - blamePart.Lines = append(blamePart.Lines, line[1:]) - } else if strings.HasPrefix(line, "previous ") { - parts := strings.SplitN(line[len("previous "):], " ", 2) - blamePart.PreviousSha = parts[0] - blamePart.PreviousPath = parts[1] + } else if lineBytes[0] == '\t' { + blamePart.Lines = append(blamePart.Lines, string(lineBytes[1:])) + } else if bytes.HasPrefix(lineBytes, []byte(previousHeader)) { + offset := len(previousHeader) // already includes a space + blamePart.PreviousSha = string(lineBytes[offset : offset+objectFormatLength]) + offset += objectFormatLength + 1 // +1 for space + blamePart.PreviousPath = string(lineBytes[offset:]) } // need to munch to end of line... @@ -126,7 +126,7 @@ func (r *BlameReader) Close() error { } // CreateBlameReader creates reader for given repository, commit and file -func CreateBlameReader(ctx context.Context, repoPath string, commit *Commit, file string, bypassBlameIgnore bool) (*BlameReader, error) { +func CreateBlameReader(ctx context.Context, objectFormat ObjectFormat, repoPath string, commit *Commit, file string, bypassBlameIgnore bool) (*BlameReader, error) { var ignoreRevsFile *string if CheckGitVersionAtLeast("2.23") == nil && !bypassBlameIgnore { ignoreRevsFile = tryCreateBlameIgnoreRevsFile(commit) @@ -175,6 +175,7 @@ func CreateBlameReader(ctx context.Conte bufferedReader: bufferedReader, done: done, ignoreRevsFile: ignoreRevsFile, + objectFormat: objectFormat, }, nil } Index: gitea-1.21.11/modules/git/blame_test.go =================================================================== --- gitea-1.21.11.orig/modules/git/blame_test.go +++ gitea-1.21.11/modules/git/blame_test.go @@ -39,7 +39,7 @@ func TestReadingBlameOutput(t *testing.T } for _, bypass := range []bool{false, true} { - blameReader, err := CreateBlameReader(ctx, "./tests/repos/repo5_pulls", commit, "README.md", bypass) + blameReader, err := CreateBlameReader(ctx, Sha1ObjectFormat, "./tests/repos/repo5_pulls", commit, "README.md", bypass) assert.NoError(t, err) assert.NotNil(t, blameReader) defer blameReader.Close() @@ -122,7 +122,7 @@ func TestReadingBlameOutput(t *testing.T commit, err := repo.GetCommit(c.CommitID) assert.NoError(t, err) - blameReader, err := CreateBlameReader(ctx, "./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() Index: gitea-1.21.11/modules/git/blob_gogit.go =================================================================== --- gitea-1.21.11.orig/modules/git/blob_gogit.go +++ gitea-1.21.11/modules/git/blob_gogit.go @@ -14,7 +14,7 @@ import ( // Blob represents a Git object. type Blob struct { - ID SHA1 + ID ObjectID gogitEncodedObj plumbing.EncodedObject name string Index: gitea-1.21.11/modules/git/blob_nogogit.go =================================================================== --- gitea-1.21.11.orig/modules/git/blob_nogogit.go +++ gitea-1.21.11/modules/git/blob_nogogit.go @@ -15,7 +15,7 @@ import ( // Blob represents a Git object. type Blob struct { - ID SHA1 + ID ObjectID gotSize bool size int64 Index: gitea-1.21.11/modules/git/commit.go =================================================================== --- gitea-1.21.11.orig/modules/git/commit.go +++ gitea-1.21.11/modules/git/commit.go @@ -21,13 +21,13 @@ import ( // Commit represents a git commit. type Commit struct { Tree - ID SHA1 // The ID of this commit object + ID ObjectID // The ID of this commit object Author *Signature Committer *Signature CommitMessage string Signature *CommitGPGSignature - Parents []SHA1 // SHA1 strings + Parents []ObjectID // ID strings submoduleCache *ObjectCache } @@ -50,9 +50,9 @@ func (c *Commit) Summary() string { // ParentID returns oid of n-th parent (0-based index). // It returns nil if no such parent exists. -func (c *Commit) ParentID(n int) (SHA1, error) { +func (c *Commit) ParentID(n int) (ObjectID, error) { if n >= len(c.Parents) { - return SHA1{}, ErrNotExist{"", ""} + return nil, ErrNotExist{"", ""} } return c.Parents[n], nil } @@ -209,9 +209,9 @@ func (c *Commit) CommitsBefore() ([]*Com } // HasPreviousCommit returns true if a given commitHash is contained in commit's parents -func (c *Commit) HasPreviousCommit(commitHash SHA1) (bool, error) { +func (c *Commit) HasPreviousCommit(objectID ObjectID) (bool, error) { this := c.ID.String() - that := commitHash.String() + that := objectID.String() if this == that { return false, nil @@ -232,9 +232,14 @@ func (c *Commit) HasPreviousCommit(commi // IsForcePush returns true if a push from oldCommitHash to this is a force push func (c *Commit) IsForcePush(oldCommitID string) (bool, error) { - if oldCommitID == EmptySHA { + 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 Index: gitea-1.21.11/modules/git/commit_convert_gogit.go =================================================================== --- gitea-1.21.11.orig/modules/git/commit_convert_gogit.go +++ gitea-1.21.11/modules/git/commit_convert_gogit.go @@ -65,11 +65,11 @@ func convertPGPSignature(c *object.Commi func convertCommit(c *object.Commit) *Commit { return &Commit{ - ID: c.Hash, + ID: ParseGogitHash(c.Hash), CommitMessage: c.Message, Committer: &c.Committer, Author: &c.Author, Signature: convertPGPSignature(c), - Parents: c.ParentHashes, + Parents: ParseGogitHashArray(c.ParentHashes), } } Index: gitea-1.21.11/modules/git/commit_info_gogit.go =================================================================== --- gitea-1.21.11.orig/modules/git/commit_info_gogit.go +++ gitea-1.21.11/modules/git/commit_info_gogit.go @@ -29,7 +29,7 @@ func (tes Entries) GetCommitsInfo(ctx co defer commitGraphFile.Close() } - c, err := commitNodeIndex.Get(commit.ID) + c, err := commitNodeIndex.Get(plumbing.Hash(commit.ID.RawValue())) if err != nil { return nil, nil, err } Index: gitea-1.21.11/modules/git/commit_reader.go =================================================================== --- gitea-1.21.11.orig/modules/git/commit_reader.go +++ gitea-1.21.11/modules/git/commit_reader.go @@ -14,9 +14,9 @@ import ( // 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, sha SHA1, reader io.Reader) (*Commit, error) { +func CommitFromReader(gitRepo *Repository, objectID ObjectID, reader io.Reader) (*Commit, error) { commit := &Commit{ - ID: sha, + ID: objectID, Author: &Signature{}, Committer: &Signature{}, } @@ -87,6 +87,8 @@ readLoop: case "encoding": _, _ = payloadSB.Write(line) case "gpgsig": + fallthrough + case "gpgsig-sha256": // FIXME: no intertop, so only 1 exists at present. _, _ = signatureSB.Write(data) _ = signatureSB.WriteByte('\n') pgpsig = true Index: gitea-1.21.11/modules/git/commit_test.go =================================================================== --- gitea-1.21.11.orig/modules/git/commit_test.go +++ gitea-1.21.11/modules/git/commit_test.go @@ -81,7 +81,7 @@ gpgsig -----BEGIN PGP SIGNATURE----- empty commit` - sha := SHA1{0xfe, 0xaf, 0x4b, 0xa6, 0xbc, 0x63, 0x5f, 0xec, 0x44, 0x2f, 0x46, 0xdd, 0xd4, 0x51, 0x24, 0x16, 0xec, 0x43, 0xc2, 0xc2} + sha := &Sha1Hash{0xfe, 0xaf, 0x4b, 0xa6, 0xbc, 0x63, 0x5f, 0xec, 0x44, 0x2f, 0x46, 0xdd, 0xd4, 0x51, 0x24, 0x16, 0xec, 0x43, 0xc2, 0xc2} gitRepo, err := openRepositoryWithDefaultContext(filepath.Join(testReposDir, "repo1_bare")) assert.NoError(t, err) assert.NotNil(t, gitRepo) Index: gitea-1.21.11/modules/git/last_commit_cache.go =================================================================== --- gitea-1.21.11.orig/modules/git/last_commit_cache.go +++ gitea-1.21.11/modules/git/last_commit_cache.go @@ -92,17 +92,17 @@ func (c *LastCommitCache) Get(ref, entry // GetCommitByPath gets the last commit for the entry in the provided commit func (c *LastCommitCache) GetCommitByPath(commitID, entryPath string) (*Commit, error) { - sha1, err := NewIDFromString(commitID) + sha, err := NewIDFromString(commitID) if err != nil { return nil, err } - lastCommit, err := c.Get(sha1.String(), entryPath) + lastCommit, err := c.Get(sha.String(), entryPath) if err != nil || lastCommit != nil { return lastCommit, err } - lastCommit, err = c.repo.getCommitByPathWithID(sha1, entryPath) + lastCommit, err = c.repo.getCommitByPathWithID(sha, entryPath) if err != nil { return nil, err } Index: gitea-1.21.11/modules/git/last_commit_cache_gogit.go =================================================================== --- gitea-1.21.11.orig/modules/git/last_commit_cache_gogit.go +++ gitea-1.21.11/modules/git/last_commit_cache_gogit.go @@ -8,6 +8,7 @@ package git import ( "context" + "github.com/go-git/go-git/v5/plumbing" cgobject "github.com/go-git/go-git/v5/plumbing/object/commitgraph" ) @@ -18,7 +19,7 @@ func (c *Commit) CacheCommit(ctx context } commitNodeIndex, _ := c.repo.CommitNodeIndex() - index, err := commitNodeIndex.Get(c.ID) + index, err := commitNodeIndex.Get(plumbing.Hash(c.ID.RawValue())) if err != nil { return err } Index: gitea-1.21.11/modules/git/log_name_status.go =================================================================== --- gitea-1.21.11.orig/modules/git/log_name_status.go +++ gitea-1.21.11/modules/git/log_name_status.go @@ -143,17 +143,20 @@ func (g *LogNameStatusRepoParser) Next(t } // Our "line" must look like: <commitid> SP (<parent> SP) * NUL - ret.CommitID = string(g.next[0:40]) - parents := string(g.next[41:]) + commitIds := string(g.next) if g.buffull { more, err := g.rd.ReadString('\x00') if err != nil { return nil, err } - parents += more + commitIds += more + } + commitIds = commitIds[:len(commitIds)-1] + splitIds := strings.Split(commitIds, " ") + ret.CommitID = splitIds[0] + if len(splitIds) > 1 { + ret.ParentIDs = splitIds[1:] } - parents = parents[:len(parents)-1] - ret.ParentIDs = strings.Split(parents, " ") // now read the next "line" g.buffull = false Index: gitea-1.21.11/modules/git/notes_gogit.go =================================================================== --- gitea-1.21.11.orig/modules/git/notes_gogit.go +++ gitea-1.21.11/modules/git/notes_gogit.go @@ -11,6 +11,7 @@ import ( "code.gitea.io/gitea/modules/log" + "github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing/object" ) @@ -72,7 +73,7 @@ func GetNote(ctx context.Context, repo * defer commitGraphFile.Close() } - commitNode, err := commitNodeIndex.Get(notes.ID) + commitNode, err := commitNodeIndex.Get(plumbing.Hash(notes.ID.RawValue())) if err != nil { return err } Index: gitea-1.21.11/modules/git/object_format.go =================================================================== --- /dev/null +++ gitea-1.21.11/modules/git/object_format.go @@ -0,0 +1,146 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package git + +import ( + "crypto/sha1" + "crypto/sha256" + "regexp" + "strconv" +) + +// sha1Pattern can be used to determine if a string is an valid sha +var sha1Pattern = regexp.MustCompile(`^[0-9a-f]{4,40}$`) + +// sha256Pattern can be used to determine if a string is an valid sha +var sha256Pattern = regexp.MustCompile(`^[0-9a-f]{4,64}$`) + +type ObjectFormat interface { + // Name returns the name of the object format + Name() string + // EmptyObjectID creates a new empty ObjectID from an object format hash name + EmptyObjectID() ObjectID + // EmptyTree is the hash of an empty tree + EmptyTree() ObjectID + // FullLength is the length of the hash's hex string + FullLength() int + // IsValid returns true if the input is a valid hash + IsValid(input string) bool + // MustID creates a new ObjectID from a byte slice + MustID(b []byte) ObjectID + // ComputeHash compute the hash for a given ObjectType and content + ComputeHash(t ObjectType, content []byte) ObjectID +} + +/* SHA1 Type */ +type Sha1ObjectFormatImpl struct{} + +var ( + emptySha1ObjectID = &Sha1Hash{} + emptySha1Tree = &Sha1Hash{ + 0x4b, 0x82, 0x5d, 0xc6, 0x42, 0xcb, 0x6e, 0xb9, 0xa0, 0x60, + 0xe5, 0x4b, 0xf8, 0xd6, 0x92, 0x88, 0xfb, 0xee, 0x49, 0x04, + } +) + +func (Sha1ObjectFormatImpl) Name() string { return "sha1" } +func (Sha1ObjectFormatImpl) EmptyObjectID() ObjectID { + return emptySha1ObjectID +} + +func (Sha1ObjectFormatImpl) EmptyTree() ObjectID { + return emptySha1Tree +} +func (Sha1ObjectFormatImpl) FullLength() int { return 40 } +func (Sha1ObjectFormatImpl) IsValid(input string) bool { + return sha1Pattern.MatchString(input) +} + +func (Sha1ObjectFormatImpl) MustID(b []byte) ObjectID { + var id Sha1Hash + copy(id[0:20], b) + return &id +} + +// ComputeHash compute the hash for a given ObjectType and content +func (h Sha1ObjectFormatImpl) ComputeHash(t ObjectType, content []byte) ObjectID { + hasher := sha1.New() + _, _ = hasher.Write(t.Bytes()) + _, _ = hasher.Write([]byte(" ")) + _, _ = hasher.Write([]byte(strconv.FormatInt(int64(len(content)), 10))) + _, _ = hasher.Write([]byte{0}) + + // HashSum generates a SHA1 for the provided hash + var sha1 Sha1Hash + copy(sha1[:], hasher.Sum(nil)) + return &sha1 +} + +/* SHA256 Type */ +type Sha256ObjectFormatImpl struct{} + +var ( + emptySha256ObjectID = &Sha256Hash{} + emptySha256Tree = &Sha256Hash{ + 0x6e, 0xf1, 0x9b, 0x41, 0x22, 0x5c, 0x53, 0x69, 0xf1, 0xc1, + 0x04, 0xd4, 0x5d, 0x8d, 0x85, 0xef, 0xa9, 0xb0, 0x57, 0xb5, + 0x3b, 0x14, 0xb4, 0xb9, 0xb9, 0x39, 0xdd, 0x74, 0xde, 0xcc, + 0x53, 0x21, + } +) + +func (Sha256ObjectFormatImpl) Name() string { return "sha256" } +func (Sha256ObjectFormatImpl) EmptyObjectID() ObjectID { + return emptySha256ObjectID +} + +func (Sha256ObjectFormatImpl) EmptyTree() ObjectID { + return emptySha256Tree +} +func (Sha256ObjectFormatImpl) FullLength() int { return 64 } +func (Sha256ObjectFormatImpl) IsValid(input string) bool { + return sha256Pattern.MatchString(input) +} + +func (Sha256ObjectFormatImpl) MustID(b []byte) ObjectID { + var id Sha256Hash + copy(id[0:32], b) + return &id +} + +// ComputeHash compute the hash for a given ObjectType and content +func (h Sha256ObjectFormatImpl) ComputeHash(t ObjectType, content []byte) ObjectID { + hasher := sha256.New() + _, _ = hasher.Write(t.Bytes()) + _, _ = hasher.Write([]byte(" ")) + _, _ = hasher.Write([]byte(strconv.FormatInt(int64(len(content)), 10))) + _, _ = hasher.Write([]byte{0}) + + // HashSum generates a SHA256 for the provided hash + var sha256 Sha1Hash + copy(sha256[:], hasher.Sum(nil)) + return &sha256 +} + +var ( + Sha1ObjectFormat ObjectFormat = Sha1ObjectFormatImpl{} + Sha256ObjectFormat ObjectFormat = Sha256ObjectFormatImpl{} +) + +var SupportedObjectFormats = []ObjectFormat{ + Sha1ObjectFormat, +} + +func ObjectFormatFromName(name string) ObjectFormat { + for _, objectFormat := range SupportedObjectFormats { + if name == objectFormat.Name() { + return objectFormat + } + } + return nil +} + +func IsValidObjectFormat(name string) bool { + return ObjectFormatFromName(name) != nil +} Index: gitea-1.21.11/modules/git/object_id.go =================================================================== --- /dev/null +++ gitea-1.21.11/modules/git/object_id.go @@ -0,0 +1,106 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package git + +import ( + "bytes" + "encoding/hex" + "fmt" +) + +type ObjectID interface { + String() string + IsZero() bool + RawValue() []byte + Type() ObjectFormat +} + +/* SHA1 */ +type Sha1Hash [20]byte + +func (h *Sha1Hash) String() string { + return hex.EncodeToString(h[:]) +} + +func (h *Sha1Hash) IsZero() bool { + empty := Sha1Hash{} + return bytes.Equal(empty[:], h[:]) +} +func (h *Sha1Hash) RawValue() []byte { return h[:] } +func (*Sha1Hash) Type() ObjectFormat { return Sha1ObjectFormat } + +var _ ObjectID = &Sha1Hash{} + +func MustIDFromString(hexHash string) ObjectID { + id, err := NewIDFromString(hexHash) + if err != nil { + panic(err) + } + return id +} + +/* SHA256 */ +type Sha256Hash [32]byte + +func (h *Sha256Hash) String() string { + return hex.EncodeToString(h[:]) +} + +func (h *Sha256Hash) IsZero() bool { + empty := Sha256Hash{} + return bytes.Equal(empty[:], h[:]) +} +func (h *Sha256Hash) RawValue() []byte { return h[:] } +func (*Sha256Hash) Type() ObjectFormat { return Sha256ObjectFormat } + +/* utility */ +func NewIDFromString(hexHash string) (ObjectID, error) { + var theObjectFormat ObjectFormat + for _, objectFormat := range SupportedObjectFormats { + if len(hexHash) == objectFormat.FullLength() { + theObjectFormat = objectFormat + break + } + } + + if theObjectFormat == nil { + return nil, fmt.Errorf("length %d has no matched object format: %s", len(hexHash), hexHash) + } + + b, err := hex.DecodeString(hexHash) + if err != nil { + return nil, err + } + + if len(b) != theObjectFormat.FullLength()/2 { + return theObjectFormat.EmptyObjectID(), fmt.Errorf("length must be %d: %v", theObjectFormat.FullLength(), b) + } + return theObjectFormat.MustID(b), nil +} + +func IsEmptyCommitID(commitID string) bool { + if commitID == "" { + return true + } + + id, err := NewIDFromString(commitID) + if err != nil { + return false + } + + return id.IsZero() +} + +// ComputeBlobHash compute the hash for a given blob content +func ComputeBlobHash(hashType ObjectFormat, content []byte) ObjectID { + return hashType.ComputeHash(ObjectBlob, content) +} + +type ErrInvalidSHA struct { + SHA string +} + +func (err ErrInvalidSHA) Error() string { + return fmt.Sprintf("invalid sha: %s", err.SHA) +} Index: gitea-1.21.11/modules/git/object_id_gogit.go =================================================================== --- /dev/null +++ gitea-1.21.11/modules/git/object_id_gogit.go @@ -0,0 +1,30 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT +//go:build gogit + +package git + +import ( + "github.com/go-git/go-git/v5/plumbing" + "github.com/go-git/go-git/v5/plumbing/hash" +) + +func ParseGogitHash(h plumbing.Hash) ObjectID { + switch hash.Size { + case 20: + return Sha1ObjectFormat.MustID(h[:]) + case 32: + return Sha256ObjectFormat.MustID(h[:]) + } + + return nil +} + +func ParseGogitHashArray(objectIDs []plumbing.Hash) []ObjectID { + ret := make([]ObjectID, len(objectIDs)) + for i, h := range objectIDs { + ret[i] = ParseGogitHash(h) + } + + return ret +} Index: gitea-1.21.11/modules/git/object_id_test.go =================================================================== --- /dev/null +++ gitea-1.21.11/modules/git/object_id_test.go @@ -0,0 +1,21 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package git + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestIsValidSHAPattern(t *testing.T) { + h := Sha1ObjectFormat + assert.True(t, h.IsValid("fee1")) + assert.True(t, h.IsValid("abc000")) + assert.True(t, h.IsValid("9023902390239023902390239023902390239023")) + assert.False(t, h.IsValid("90239023902390239023902390239023902390239023")) + assert.False(t, h.IsValid("abc")) + assert.False(t, h.IsValid("123g")) + assert.False(t, h.IsValid("some random text")) +} Index: gitea-1.21.11/modules/git/parse_gogit.go =================================================================== --- gitea-1.21.11.orig/modules/git/parse_gogit.go +++ gitea-1.21.11/modules/git/parse_gogit.go @@ -11,12 +11,14 @@ import ( "strconv" "strings" + "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/hash" "github.com/go-git/go-git/v5/plumbing/object" ) // ParseTreeEntries parses the output of a `git ls-tree -l` command. -func ParseTreeEntries(data []byte) ([]*TreeEntry, error) { +func ParseTreeEntries(h ObjectFormat, data []byte) ([]*TreeEntry, error) { return parseTreeEntries(data, nil) } @@ -50,15 +52,16 @@ func parseTreeEntries(data []byte, ptree return nil, fmt.Errorf("unknown type: %v", string(data[pos:pos+6])) } - if pos+40 > len(data) { + // in hex format, not byte format .... + if pos+hash.Size*2 > len(data) { return nil, fmt.Errorf("Invalid ls-tree output: %s", string(data)) } - id, err := NewIDFromString(string(data[pos : pos+40])) + var err error + entry.ID, err = NewIDFromString(string(data[pos : pos+hash.Size*2])) if err != nil { - return nil, fmt.Errorf("Invalid ls-tree output: %w", err) + return nil, fmt.Errorf("invalid ls-tree output: %w", err) } - entry.ID = id - entry.gogitTreeEntry.Hash = id + entry.gogitTreeEntry.Hash = plumbing.Hash(entry.ID.RawValue()) pos += 41 // skip over sha and trailing space end := pos + bytes.IndexByte(data[pos:], '\t') @@ -77,6 +80,7 @@ func parseTreeEntries(data []byte, ptree // In case entry name is surrounded by double quotes(it happens only in git-shell). if data[pos] == '"' { + var err error entry.gogitTreeEntry.Name, err = strconv.Unquote(string(data[pos:end])) if err != nil { return nil, fmt.Errorf("Invalid ls-tree output: %w", err) Index: gitea-1.21.11/modules/git/parse_gogit_test.go =================================================================== --- gitea-1.21.11.orig/modules/git/parse_gogit_test.go +++ gitea-1.21.11/modules/git/parse_gogit_test.go @@ -6,8 +6,10 @@ package git import ( + "fmt" "testing" + "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" "github.com/stretchr/testify/assert" @@ -28,7 +30,7 @@ func TestParseTreeEntries(t *testing.T) { ID: MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c"), gogitTreeEntry: &object.TreeEntry{ - Hash: MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c"), + Hash: plumbing.Hash(MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c").RawValue()), Name: "example/file2.txt", Mode: filemode.Regular, }, @@ -44,7 +46,7 @@ func TestParseTreeEntries(t *testing.T) { ID: MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c"), gogitTreeEntry: &object.TreeEntry{ - Hash: MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c"), + Hash: plumbing.Hash(MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c").RawValue()), Name: "example/\n.txt", Mode: filemode.Symlink, }, @@ -55,7 +57,7 @@ func TestParseTreeEntries(t *testing.T) ID: MustIDFromString("1d01fb729fb0db5881daaa6030f9f2d3cd3d5ae8"), sized: true, gogitTreeEntry: &object.TreeEntry{ - Hash: MustIDFromString("1d01fb729fb0db5881daaa6030f9f2d3cd3d5ae8"), + Hash: plumbing.Hash(MustIDFromString("1d01fb729fb0db5881daaa6030f9f2d3cd3d5ae8").RawValue()), Name: "example", Mode: filemode.Dir, }, @@ -65,8 +67,12 @@ func TestParseTreeEntries(t *testing.T) } for _, testCase := range testCases { - entries, err := ParseTreeEntries([]byte(testCase.Input)) + entries, err := ParseTreeEntries(Sha1ObjectFormat, []byte(testCase.Input)) assert.NoError(t, err) + if len(entries) > 1 { + fmt.Println(testCase.Expected[0].ID) + fmt.Println(entries[0].ID) + } assert.EqualValues(t, testCase.Expected, entries) } } Index: gitea-1.21.11/modules/git/parse_nogogit.go =================================================================== --- gitea-1.21.11.orig/modules/git/parse_nogogit.go +++ gitea-1.21.11/modules/git/parse_nogogit.go @@ -17,13 +17,13 @@ import ( ) // ParseTreeEntries parses the output of a `git ls-tree -l` command. -func ParseTreeEntries(data []byte) ([]*TreeEntry, error) { - return parseTreeEntries(data, nil) +func ParseTreeEntries(objectFormat ObjectFormat, data []byte) ([]*TreeEntry, error) { + return parseTreeEntries(objectFormat, data, nil) } var sepSpace = []byte{' '} -func parseTreeEntries(data []byte, ptree *Tree) ([]*TreeEntry, error) { +func parseTreeEntries(objectFormat ObjectFormat, data []byte, ptree *Tree) ([]*TreeEntry, error) { var err error entries := make([]*TreeEntry, 0, bytes.Count(data, []byte{'\n'})+1) for pos := 0; pos < len(data); { @@ -92,15 +92,15 @@ func parseTreeEntries(data []byte, ptree return entries, nil } -func catBatchParseTreeEntries(ptree *Tree, rd *bufio.Reader, sz int64) ([]*TreeEntry, error) { +func catBatchParseTreeEntries(objectFormat ObjectFormat, ptree *Tree, rd *bufio.Reader, sz int64) ([]*TreeEntry, error) { fnameBuf := make([]byte, 4096) modeBuf := make([]byte, 40) - shaBuf := make([]byte, 40) + shaBuf := make([]byte, objectFormat.FullLength()) entries := make([]*TreeEntry, 0, 10) loop: for sz > 0 { - mode, fname, sha, count, err := ParseTreeLine(rd, modeBuf, fnameBuf, shaBuf) + mode, fname, sha, count, err := ParseTreeLine(objectFormat, rd, modeBuf, fnameBuf, shaBuf) if err != nil { if err == io.EOF { break loop @@ -127,7 +127,7 @@ loop: return nil, fmt.Errorf("unknown mode: %v", string(mode)) } - entry.ID = MustID(sha) + entry.ID = objectFormat.MustID(sha) entry.name = string(fname) entries = append(entries, entry) } Index: gitea-1.21.11/modules/git/parse_nogogit_test.go =================================================================== --- gitea-1.21.11.orig/modules/git/parse_nogogit_test.go +++ gitea-1.21.11/modules/git/parse_nogogit_test.go @@ -12,6 +12,8 @@ import ( ) func TestParseTreeEntriesLong(t *testing.T) { + objectFormat := Sha1ObjectFormat + testCases := []struct { Input string Expected []*TreeEntry @@ -54,7 +56,7 @@ func TestParseTreeEntriesLong(t *testing }, } for _, testCase := range testCases { - entries, err := ParseTreeEntries([]byte(testCase.Input)) + entries, err := ParseTreeEntries(objectFormat, []byte(testCase.Input)) assert.NoError(t, err) assert.Len(t, entries, len(testCase.Expected)) for i, entry := range entries { @@ -64,6 +66,8 @@ func TestParseTreeEntriesLong(t *testing } func TestParseTreeEntriesShort(t *testing.T) { + objectFormat := Sha1ObjectFormat + testCases := []struct { Input string Expected []*TreeEntry @@ -87,7 +91,7 @@ func TestParseTreeEntriesShort(t *testin }, } for _, testCase := range testCases { - entries, err := ParseTreeEntries([]byte(testCase.Input)) + entries, err := ParseTreeEntries(objectFormat, []byte(testCase.Input)) assert.NoError(t, err) assert.Len(t, entries, len(testCase.Expected)) for i, entry := range entries { @@ -98,7 +102,7 @@ func TestParseTreeEntriesShort(t *testin func TestParseTreeEntriesInvalid(t *testing.T) { // there was a panic: "runtime error: slice bounds out of range" when the input was invalid: #20315 - entries, err := ParseTreeEntries([]byte("100644 blob ea0d83c9081af9500ac9f804101b3fd0a5c293af")) + entries, err := ParseTreeEntries(Sha1ObjectFormat, []byte("100644 blob ea0d83c9081af9500ac9f804101b3fd0a5c293af")) assert.Error(t, err) assert.Len(t, entries, 0) } Index: gitea-1.21.11/modules/git/pipeline/lfs.go =================================================================== --- gitea-1.21.11.orig/modules/git/pipeline/lfs.go +++ gitea-1.21.11/modules/git/pipeline/lfs.go @@ -17,6 +17,7 @@ import ( "code.gitea.io/gitea/modules/git" gogit "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing/object" ) @@ -26,7 +27,7 @@ type LFSResult struct { SHA string Summary string When time.Time - ParentHashes []git.SHA1 + ParentHashes []git.ObjectID BranchName string FullCommitName string } @@ -38,7 +39,7 @@ func (a lfsResultSlice) Swap(i, j int) func (a lfsResultSlice) Less(i, j int) bool { return a[j].When.After(a[i].When) } // FindLFSFile finds commits that contain a provided pointer file hash -func FindLFSFile(repo *git.Repository, hash git.SHA1) ([]*LFSResult, error) { +func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, error) { resultsMap := map[string]*LFSResult{} results := make([]*LFSResult, 0) @@ -65,13 +66,18 @@ func FindLFSFile(repo *git.Repository, h if err == io.EOF { break } - if entry.Hash == hash { + if entry.Hash == plumbing.Hash(objectID.RawValue()) { + parents := make([]git.ObjectID, len(gitCommit.ParentHashes)) + for i, parentCommitID := range gitCommit.ParentHashes { + parents[i] = git.ParseGogitHash(parentCommitID) + } + result := LFSResult{ Name: name, SHA: gitCommit.Hash.String(), Summary: strings.Split(strings.TrimSpace(gitCommit.Message), "\n")[0], When: gitCommit.Author.When, - ParentHashes: gitCommit.ParentHashes, + ParentHashes: parents, } resultsMap[gitCommit.Hash.String()+":"+name] = &result } Index: gitea-1.21.11/modules/git/pipeline/lfs_nogogit.go =================================================================== --- gitea-1.21.11.orig/modules/git/pipeline/lfs_nogogit.go +++ gitea-1.21.11/modules/git/pipeline/lfs_nogogit.go @@ -24,7 +24,7 @@ type LFSResult struct { SHA string Summary string When time.Time - ParentHashes []git.SHA1 + ParentIDs []git.ObjectID BranchName string FullCommitName string } @@ -36,7 +36,7 @@ func (a lfsResultSlice) Swap(i, j int) func (a lfsResultSlice) Less(i, j int) bool { return a[j].When.After(a[i].When) } // FindLFSFile finds commits that contain a provided pointer file hash -func FindLFSFile(repo *git.Repository, hash git.SHA1) ([]*LFSResult, error) { +func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, error) { resultsMap := map[string]*LFSResult{} results := make([]*LFSResult, 0) @@ -75,7 +75,7 @@ func FindLFSFile(repo *git.Repository, h fnameBuf := make([]byte, 4096) modeBuf := make([]byte, 40) - workingShaBuf := make([]byte, 20) + workingShaBuf := make([]byte, objectID.Type().FullLength()/2) for scan.Scan() { // Get the next commit ID @@ -123,32 +123,31 @@ func FindLFSFile(repo *git.Repository, h return nil, err } - _, err := batchStdinWriter.Write([]byte(curCommit.Tree.ID.String() + "\n")) - if err != nil { + if _, err := batchStdinWriter.Write([]byte(curCommit.Tree.ID.String() + "\n")); err != nil { return nil, err } curPath = "" case "tree": var n int64 for n < size { - mode, fname, sha20byte, count, err := git.ParseTreeLine(batchReader, modeBuf, fnameBuf, workingShaBuf) + mode, fname, binObjectID, count, err := git.ParseTreeLine(objectID.Type(), batchReader, modeBuf, fnameBuf, workingShaBuf) if err != nil { return nil, err } n += int64(count) - if bytes.Equal(sha20byte, hash[:]) { + if bytes.Equal(binObjectID, objectID.RawValue()) { result := LFSResult{ - Name: curPath + string(fname), - SHA: curCommit.ID.String(), - Summary: strings.Split(strings.TrimSpace(curCommit.CommitMessage), "\n")[0], - When: curCommit.Author.When, - ParentHashes: curCommit.Parents, + Name: curPath + string(fname), + SHA: curCommit.ID.String(), + Summary: strings.Split(strings.TrimSpace(curCommit.CommitMessage), "\n")[0], + When: curCommit.Author.When, + ParentIDs: curCommit.Parents, } resultsMap[curCommit.ID.String()+":"+curPath+string(fname)] = &result } else if string(mode) == git.EntryModeTree.String() { - sha40Byte := make([]byte, 40) - git.To40ByteSHA(sha20byte, sha40Byte) - trees = append(trees, sha40Byte) + hexObjectID := make([]byte, objectID.Type().FullLength()) + git.BinToHex(objectID.Type(), binObjectID, hexObjectID) + trees = append(trees, hexObjectID) paths = append(paths, curPath+string(fname)+"/") } } @@ -184,8 +183,8 @@ func FindLFSFile(repo *git.Repository, h for _, result := range resultsMap { hasParent := false - for _, parentHash := range result.ParentHashes { - if _, hasParent = resultsMap[parentHash.String()+":"+result.Name]; hasParent { + for _, parentID := range result.ParentIDs { + if _, hasParent = resultsMap[parentID.String()+":"+result.Name]; hasParent { break } } Index: gitea-1.21.11/modules/git/ref.go =================================================================== --- gitea-1.21.11.orig/modules/git/ref.go +++ gitea-1.21.11/modules/git/ref.go @@ -44,7 +44,7 @@ func SanitizeRefPattern(name string) str type Reference struct { Name string repo *Repository - Object SHA1 // The id of this commit object + Object ObjectID // The id of this commit object Type string } @@ -205,7 +205,7 @@ func RefURL(repoURL, ref string) string return repoURL + "/src/branch/" + refName case refFullName.IsTag(): return repoURL + "/src/tag/" + refName - case !IsValidSHAPattern(ref): + case !Sha1ObjectFormat.IsValid(ref): // assume they mean a branch return repoURL + "/src/branch/" + refName default: Index: gitea-1.21.11/modules/git/repo.go =================================================================== --- gitea-1.21.11.orig/modules/git/repo.go +++ gitea-1.21.11/modules/git/repo.go @@ -7,6 +7,7 @@ package git import ( "bytes" "context" + "errors" "fmt" "io" "net/url" @@ -62,14 +63,46 @@ func IsRepoURLAccessible(ctx context.Con return err == nil } +// GetObjectFormatOfRepo returns the hash type of repository at a given path +func GetObjectFormatOfRepo(ctx context.Context, repoPath string) (ObjectFormat, error) { + var stdout, stderr strings.Builder + + err := NewCommand(ctx, "hash-object", "--stdin").Run(&RunOpts{ + Dir: repoPath, + Stdout: &stdout, + Stderr: &stderr, + Stdin: &strings.Reader{}, + }) + if err != nil { + return nil, err + } + + if stderr.Len() > 0 { + return nil, errors.New(stderr.String()) + } + + h, err := NewIDFromString(strings.TrimRight(stdout.String(), "\n")) + if err != nil { + return nil, err + } + + return h.Type(), nil +} + // InitRepository initializes a new Git repository. -func InitRepository(ctx context.Context, repoPath string, bare bool) error { +func InitRepository(ctx context.Context, repoPath string, bare bool, objectFormatName string) error { err := os.MkdirAll(repoPath, os.ModePerm) if err != nil { return err } cmd := NewCommand(ctx, "init") + + if !IsValidObjectFormat(objectFormatName) { + return fmt.Errorf("invalid object format: %s", objectFormatName) + } + cmd.AddOptionValues("--object-format", objectFormatName) + if bare { cmd.AddArguments("--bare") } Index: gitea-1.21.11/modules/git/repo_base_gogit.go =================================================================== --- gitea-1.21.11.orig/modules/git/repo_base_gogit.go +++ gitea-1.21.11/modules/git/repo_base_gogit.go @@ -17,10 +17,15 @@ import ( "github.com/go-git/go-billy/v5" "github.com/go-git/go-billy/v5/osfs" gogit "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing/cache" "github.com/go-git/go-git/v5/storage/filesystem" ) +func init() { + isGogit = true +} + // Repository represents a Git repository. type Repository struct { Path string @@ -33,6 +38,7 @@ type Repository struct { Ctx context.Context LastCommitCache *LastCommitCache + objectFormat ObjectFormat } // openRepositoryWithDefaultContext opens the repository at the given path with DefaultContext. @@ -77,6 +83,7 @@ func OpenRepository(ctx context.Context, gogitStorage: storage, tagCache: newObjectCache(), Ctx: ctx, + objectFormat: ParseGogitHash(plumbing.ZeroHash).Type(), }, nil } Index: gitea-1.21.11/modules/git/repo_base_nogogit.go =================================================================== --- gitea-1.21.11.orig/modules/git/repo_base_nogogit.go +++ gitea-1.21.11/modules/git/repo_base_nogogit.go @@ -15,6 +15,10 @@ import ( "code.gitea.io/gitea/modules/log" ) +func init() { + isGogit = false +} + // Repository represents a Git repository. type Repository struct { Path string @@ -35,6 +39,8 @@ type Repository struct { Ctx context.Context LastCommitCache *LastCommitCache + + objectFormat ObjectFormat } // openRepositoryWithDefaultContext opens the repository at the given path with DefaultContext. @@ -65,6 +71,11 @@ func OpenRepository(ctx context.Context, repo.batchWriter, repo.batchReader, repo.batchCancel = CatFileBatch(ctx, repoPath) repo.checkWriter, repo.checkReader, repo.checkCancel = CatFileBatchCheck(ctx, repoPath) + repo.objectFormat, err = repo.GetObjectFormat() + if err != nil { + return nil, err + } + return repo, nil } Index: gitea-1.21.11/modules/git/repo_blob_gogit.go =================================================================== --- gitea-1.21.11.orig/modules/git/repo_blob_gogit.go +++ gitea-1.21.11/modules/git/repo_blob_gogit.go @@ -9,8 +9,8 @@ import ( "github.com/go-git/go-git/v5/plumbing" ) -func (repo *Repository) getBlob(id SHA1) (*Blob, error) { - encodedObj, err := repo.gogitRepo.Storer.EncodedObject(plumbing.AnyObject, id) +func (repo *Repository) getBlob(id ObjectID) (*Blob, error) { + encodedObj, err := repo.gogitRepo.Storer.EncodedObject(plumbing.AnyObject, plumbing.Hash(id.RawValue())) if err != nil { return nil, ErrNotExist{id.String(), ""} } Index: gitea-1.21.11/modules/git/repo_blob_nogogit.go =================================================================== --- gitea-1.21.11.orig/modules/git/repo_blob_nogogit.go +++ gitea-1.21.11/modules/git/repo_blob_nogogit.go @@ -5,7 +5,7 @@ package git -func (repo *Repository) getBlob(id SHA1) (*Blob, error) { +func (repo *Repository) getBlob(id ObjectID) (*Blob, error) { if id.IsZero() { return nil, ErrNotExist{id.String(), ""} } Index: gitea-1.21.11/modules/git/repo_blob_test.go =================================================================== --- gitea-1.21.11.orig/modules/git/repo_blob_test.go +++ gitea-1.21.11/modules/git/repo_blob_test.go @@ -61,7 +61,7 @@ func TestRepository_GetBlob_NoId(t *test defer r.Close() testCase := "" - testError := fmt.Errorf("Length must be 40: %s", testCase) + testError := fmt.Errorf("length %d has no matched object format: %s", len(testCase), testCase) blob, err := r.GetBlob(testCase) assert.Nil(t, blob) Index: gitea-1.21.11/modules/git/repo_commit.go =================================================================== --- gitea-1.21.11.orig/modules/git/repo_commit.go +++ gitea-1.21.11/modules/git/repo_commit.go @@ -6,8 +6,6 @@ package git import ( "bytes" - "encoding/hex" - "fmt" "io" "strconv" "strings" @@ -28,7 +26,7 @@ func (repo *Repository) GetTagCommitID(n // GetCommit returns commit object of by ID string. func (repo *Repository) GetCommit(commitID string) (*Commit, error) { - id, err := repo.ConvertToSHA1(commitID) + id, err := repo.ConvertToGitID(commitID) if err != nil { return nil, err } @@ -54,7 +52,7 @@ func (repo *Repository) GetTagCommit(nam return repo.GetCommit(commitID) } -func (repo *Repository) getCommitByPathWithID(id SHA1, relpath string) (*Commit, error) { +func (repo *Repository) getCommitByPathWithID(id ObjectID, relpath string) (*Commit, error) { // File name starts with ':' must be escaped. if relpath[0] == ':' { relpath = `\` + relpath @@ -90,7 +88,7 @@ func (repo *Repository) GetCommitByPath( return commits[0], nil } -func (repo *Repository) commitsByRange(id SHA1, page, pageSize int, not string) ([]*Commit, error) { +func (repo *Repository) commitsByRange(id ObjectID, page, pageSize int, not string) ([]*Commit, error) { cmd := NewCommand(repo.Ctx, "log"). AddOptionFormat("--skip=%d", (page-1)*pageSize). AddOptionFormat("--max-count=%d", pageSize). @@ -109,7 +107,7 @@ func (repo *Repository) commitsByRange(i return repo.parsePrettyFormatLogToList(stdout) } -func (repo *Repository) searchCommits(id SHA1, opts SearchCommitsOptions) ([]*Commit, error) { +func (repo *Repository) searchCommits(id ObjectID, opts SearchCommitsOptions) ([]*Commit, error) { // add common arguments to git command addCommonSearchArgs := func(c *Command) { // ignore case @@ -174,7 +172,7 @@ func (repo *Repository) searchCommits(id if len(opts.Keywords) > 0 { for _, v := range opts.Keywords { // ignore anything not matching a valid sha pattern - if IsValidSHAPattern(v) { + if id.Type().IsValid(v) { // create new git log command with 1 commit limit hashCmd := NewCommand(repo.Ctx, "log", "-1", prettyLogFormat) // add previous arguments except for --grep and --all @@ -256,25 +254,22 @@ func (repo *Repository) CommitsByFileAnd } }() + len := repo.objectFormat.FullLength() commits := []*Commit{} - shaline := [41]byte{} - var sha1 SHA1 + shaline := make([]byte, len+1) for { - n, err := io.ReadFull(stdoutReader, shaline[:]) - if err != nil || n < 40 { + n, err := io.ReadFull(stdoutReader, shaline) + if err != nil || n < len { if err == io.EOF { err = nil } return commits, err } - n, err = hex.Decode(sha1[:], shaline[0:40]) - if n != 20 { - err = fmt.Errorf("invalid sha %q", string(shaline[:40])) - } + objectID, err := NewIDFromString(string(shaline[0:len])) if err != nil { return nil, err } - commit, err := repo.getCommit(sha1) + commit, err := repo.getCommit(objectID) if err != nil { return nil, err } @@ -403,7 +398,7 @@ func (repo *Repository) CommitsCountBetw } // commitsBefore the limit is depth, not total number of returned commits. -func (repo *Repository) commitsBefore(id SHA1, limit int) ([]*Commit, error) { +func (repo *Repository) commitsBefore(id ObjectID, limit int) ([]*Commit, error) { cmd := NewCommand(repo.Ctx, "log", prettyLogFormat) if limit > 0 { cmd.AddOptionFormat("-%d", limit) @@ -437,11 +432,11 @@ func (repo *Repository) commitsBefore(id return commits, nil } -func (repo *Repository) getCommitsBefore(id SHA1) ([]*Commit, error) { +func (repo *Repository) getCommitsBefore(id ObjectID) ([]*Commit, error) { return repo.commitsBefore(id, 0) } -func (repo *Repository) getCommitsBeforeLimit(id SHA1, num int) ([]*Commit, error) { +func (repo *Repository) getCommitsBeforeLimit(id ObjectID, num int) ([]*Commit, error) { return repo.commitsBefore(id, num) } Index: gitea-1.21.11/modules/git/repo_commit_gogit.go =================================================================== --- gitea-1.21.11.orig/modules/git/repo_commit_gogit.go +++ gitea-1.21.11/modules/git/repo_commit_gogit.go @@ -10,6 +10,7 @@ import ( "strings" "github.com/go-git/go-git/v5/plumbing" + "github.com/go-git/go-git/v5/plumbing/hash" "github.com/go-git/go-git/v5/plumbing/object" ) @@ -38,22 +39,24 @@ func (repo *Repository) RemoveReference( return repo.gogitRepo.Storer.RemoveReference(plumbing.ReferenceName(name)) } -// ConvertToSHA1 returns a Hash object from a potential ID string -func (repo *Repository) ConvertToSHA1(commitID string) (SHA1, error) { - if len(commitID) == SHAFullLength { - sha1, err := NewIDFromString(commitID) +// ConvertToHash returns a Hash object from a potential ID string +func (repo *Repository) ConvertToGitID(commitID string) (ObjectID, error) { + objectFormat := repo.objectFormat + if len(commitID) == hash.HexSize && objectFormat.IsValid(commitID) { + ID, err := NewIDFromString(commitID) if err == nil { - return sha1, nil + return ID, nil } } actualCommitID, _, err := NewCommand(repo.Ctx, "rev-parse", "--verify").AddDynamicArguments(commitID).RunStdString(&RunOpts{Dir: repo.Path}) + actualCommitID = strings.TrimSpace(actualCommitID) if err != nil { if strings.Contains(err.Error(), "unknown revision or path") || strings.Contains(err.Error(), "fatal: Needed a single revision") { - return SHA1{}, ErrNotExist{commitID, ""} + return objectFormat.EmptyObjectID(), ErrNotExist{commitID, ""} } - return SHA1{}, err + return objectFormat.EmptyObjectID(), err } return NewIDFromString(actualCommitID) @@ -61,17 +64,21 @@ func (repo *Repository) ConvertToSHA1(co // IsCommitExist returns true if given commit exists in current repository. func (repo *Repository) IsCommitExist(name string) bool { - hash := plumbing.NewHash(name) - _, err := repo.gogitRepo.CommitObject(hash) + hash, err := repo.ConvertToGitID(name) + if err != nil { + return false + } + _, err = repo.gogitRepo.CommitObject(plumbing.Hash(hash.RawValue())) return err == nil } -func (repo *Repository) getCommit(id SHA1) (*Commit, error) { +func (repo *Repository) getCommit(id ObjectID) (*Commit, error) { var tagObject *object.Tag - gogitCommit, err := repo.gogitRepo.CommitObject(id) + commitID := plumbing.Hash(id.RawValue()) + gogitCommit, err := repo.gogitRepo.CommitObject(commitID) if err == plumbing.ErrObjectNotFound { - tagObject, err = repo.gogitRepo.TagObject(id) + tagObject, err = repo.gogitRepo.TagObject(commitID) if err == plumbing.ErrObjectNotFound { return nil, ErrNotExist{ ID: id.String(), @@ -94,7 +101,7 @@ func (repo *Repository) getCommit(id SHA return nil, err } - commit.Tree.ID = tree.Hash + commit.Tree.ID = ParseGogitHash(tree.Hash) commit.Tree.gogitTree = tree return commit, nil Index: gitea-1.21.11/modules/git/repo_commit_nogogit.go =================================================================== --- gitea-1.21.11.orig/modules/git/repo_commit_nogogit.go +++ gitea-1.21.11/modules/git/repo_commit_nogogit.go @@ -65,7 +65,7 @@ func (repo *Repository) IsCommitExist(na return err == nil } -func (repo *Repository) getCommit(id SHA1) (*Commit, error) { +func (repo *Repository) getCommit(id ObjectID) (*Commit, error) { wr, rd, cancel := repo.CatFileBatch(repo.Ctx) defer cancel() @@ -74,7 +74,7 @@ func (repo *Repository) getCommit(id SHA return repo.getCommitFromBatchReader(rd, id) } -func (repo *Repository) getCommitFromBatchReader(rd *bufio.Reader, id SHA1) (*Commit, error) { +func (repo *Repository) getCommitFromBatchReader(rd *bufio.Reader, id ObjectID) (*Commit, error) { _, typ, size, err := ReadBatchLine(rd) if err != nil { if errors.Is(err, io.EOF) || IsErrNotExist(err) { @@ -97,7 +97,7 @@ func (repo *Repository) getCommitFromBat if err != nil { return nil, err } - tag, err := parseTagData(data) + tag, err := parseTagData(id.Type(), data) if err != nil { return nil, err } @@ -130,12 +130,13 @@ func (repo *Repository) getCommitFromBat } } -// ConvertToSHA1 returns a Hash object from a potential ID string -func (repo *Repository) ConvertToSHA1(commitID string) (SHA1, error) { - if len(commitID) == SHAFullLength && IsValidSHAPattern(commitID) { - sha1, err := NewIDFromString(commitID) +// ConvertToGitID returns a GitHash object from a potential ID string +func (repo *Repository) ConvertToGitID(commitID string) (ObjectID, error) { + IDType := repo.objectFormat + if len(commitID) == IDType.FullLength() && IDType.IsValid(commitID) { + ID, err := NewIDFromString(commitID) if err == nil { - return sha1, nil + return ID, nil } } @@ -143,14 +144,14 @@ func (repo *Repository) ConvertToSHA1(co defer cancel() _, err := wr.Write([]byte(commitID + "\n")) if err != nil { - return SHA1{}, err + return nil, err } sha, _, _, err := ReadBatchLine(rd) if err != nil { if IsErrNotExist(err) { - return SHA1{}, ErrNotExist{commitID, ""} + return nil, ErrNotExist{commitID, ""} } - return SHA1{}, err + return nil, err } return MustIDFromString(string(sha)), nil Index: gitea-1.21.11/modules/git/repo_compare.go =================================================================== --- gitea-1.21.11.orig/modules/git/repo_compare.go +++ gitea-1.21.11/modules/git/repo_compare.go @@ -284,7 +284,7 @@ func (repo *Repository) GetPatch(base, h // If base is the SHA of an empty tree (EmptyTreeSHA), it returns the files changes from the initial commit to the head commit func (repo *Repository) GetFilesChangedBetween(base, head string) ([]string, error) { cmd := NewCommand(repo.Ctx, "diff-tree", "--name-only", "--root", "--no-commit-id", "-r", "-z") - if base == EmptySHA { + if base == repo.objectFormat.EmptyObjectID().String() { cmd.AddDynamicArguments(head) } else { cmd.AddDynamicArguments(base, head) Index: gitea-1.21.11/modules/git/repo_compare_test.go =================================================================== --- gitea-1.21.11.orig/modules/git/repo_compare_test.go +++ gitea-1.21.11/modules/git/repo_compare_test.go @@ -131,12 +131,12 @@ func TestGetCommitFilesChanged(t *testin files []string }{ { - EmptySHA, + repo.objectFormat.EmptyObjectID().String(), "95bb4d39648ee7e325106df01a621c530863a653", []string{"file1.txt"}, }, { - EmptySHA, + repo.objectFormat.EmptyObjectID().String(), "8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2", []string{"file2.txt"}, }, @@ -146,7 +146,7 @@ func TestGetCommitFilesChanged(t *testin []string{"file2.txt"}, }, { - EmptyTreeSHA, + repo.objectFormat.EmptyTree().String(), "8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2", []string{"file1.txt", "file2.txt"}, }, Index: gitea-1.21.11/modules/git/repo_gpg.go =================================================================== --- gitea-1.21.11.orig/modules/git/repo_gpg.go +++ gitea-1.21.11/modules/git/repo_gpg.go @@ -17,7 +17,7 @@ func (gpgSettings *GPGSettings) LoadPubl "gpg -a --export", "gpg", "-a", "--export", gpgSettings.KeyID) if err != nil { - return fmt.Errorf("Unable to get default signing key: %s, %s, %w", gpgSettings.KeyID, stderr, err) + return fmt.Errorf("unable to get default signing key: %s, %s, %w", gpgSettings.KeyID, stderr, err) } gpgSettings.PublicKeyContent = content return nil Index: gitea-1.21.11/modules/git/repo_index.go =================================================================== --- gitea-1.21.11.orig/modules/git/repo_index.go +++ gitea-1.21.11/modules/git/repo_index.go @@ -16,7 +16,12 @@ import ( // ReadTreeToIndex reads a treeish to the index func (repo *Repository) ReadTreeToIndex(treeish string, indexFilename ...string) error { - if len(treeish) != SHAFullLength { + objectFormat, err := repo.GetObjectFormat() + if err != nil { + return err + } + + if len(treeish) != objectFormat.FullLength() { res, _, err := NewCommand(repo.Ctx, "rev-parse", "--verify").AddDynamicArguments(treeish).RunStdString(&RunOpts{Dir: repo.Path}) if err != nil { return err @@ -32,7 +37,7 @@ func (repo *Repository) ReadTreeToIndex( return repo.readTreeToIndex(id, indexFilename...) } -func (repo *Repository) readTreeToIndex(id SHA1, indexFilename ...string) error { +func (repo *Repository) readTreeToIndex(id ObjectID, indexFilename ...string) error { var env []string if len(indexFilename) > 0 { env = append(os.Environ(), "GIT_INDEX_FILE="+indexFilename[0]) @@ -95,7 +100,9 @@ func (repo *Repository) RemoveFilesFromI buffer := new(bytes.Buffer) for _, file := range filenames { if file != "" { - buffer.WriteString("0 0000000000000000000000000000000000000000\t") + buffer.WriteString("0 ") + buffer.WriteString(repo.objectFormat.EmptyObjectID().String()) + buffer.WriteByte('\t') buffer.WriteString(file) buffer.WriteByte('\000') } @@ -109,7 +116,7 @@ func (repo *Repository) RemoveFilesFromI } // AddObjectToIndex adds the provided object hash to the index at the provided filename -func (repo *Repository) AddObjectToIndex(mode string, object SHA1, filename string) error { +func (repo *Repository) AddObjectToIndex(mode string, object ObjectID, filename string) error { cmd := NewCommand(repo.Ctx, "update-index", "--add", "--replace", "--cacheinfo").AddDynamicArguments(mode, object.String(), filename) _, _, err := cmd.RunStdString(&RunOpts{Dir: repo.Path}) return err Index: gitea-1.21.11/modules/git/repo_object.go =================================================================== --- gitea-1.21.11.orig/modules/git/repo_object.go +++ gitea-1.21.11/modules/git/repo_object.go @@ -31,17 +31,47 @@ func (o ObjectType) Bytes() []byte { return []byte(o) } -// HashObject takes a reader and returns SHA1 hash for that reader -func (repo *Repository) HashObject(reader io.Reader) (SHA1, error) { - idStr, err := repo.hashObject(reader) +type EmptyReader struct{} + +func (EmptyReader) Read(p []byte) (int, error) { + return 0, io.EOF +} + +func (repo *Repository) GetObjectFormat() (ObjectFormat, error) { + if repo != nil && repo.objectFormat != nil { + return repo.objectFormat, nil + } + + str, err := repo.hashObject(EmptyReader{}, false) + if err != nil { + return nil, err + } + hash, err := NewIDFromString(str) if err != nil { - return SHA1{}, err + return nil, err + } + + repo.objectFormat = hash.Type() + + return repo.objectFormat, nil +} + +// HashObject takes a reader and returns hash for that reader +func (repo *Repository) HashObject(reader io.Reader) (ObjectID, error) { + idStr, err := repo.hashObject(reader, true) + if err != nil { + return nil, err } return NewIDFromString(idStr) } -func (repo *Repository) hashObject(reader io.Reader) (string, error) { - cmd := NewCommand(repo.Ctx, "hash-object", "-w", "--stdin") +func (repo *Repository) hashObject(reader io.Reader, save bool) (string, error) { + var cmd *Command + if save { + cmd = NewCommand(repo.Ctx, "hash-object", "-w", "--stdin") + } else { + cmd = NewCommand(repo.Ctx, "hash-object", "--stdin") + } stdout := new(bytes.Buffer) stderr := new(bytes.Buffer) err := cmd.Run(&RunOpts{ Index: gitea-1.21.11/modules/git/repo_ref_gogit.go =================================================================== --- gitea-1.21.11.orig/modules/git/repo_ref_gogit.go +++ gitea-1.21.11/modules/git/repo_ref_gogit.go @@ -30,13 +30,13 @@ func (repo *Repository) GetRefsFiltered( refType := string(ObjectCommit) if ref.Name().IsTag() { // tags can be of type `commit` (lightweight) or `tag` (annotated) - if tagType, _ := repo.GetTagType(ref.Hash()); err == nil { + if tagType, _ := repo.GetTagType(ParseGogitHash(ref.Hash())); err == nil { refType = tagType } } r := &Reference{ Name: ref.Name().String(), - Object: ref.Hash(), + Object: ParseGogitHash(ref.Hash()), Type: refType, repo: repo, } Index: gitea-1.21.11/modules/git/repo_tag.go =================================================================== --- gitea-1.21.11.orig/modules/git/repo_tag.go +++ gitea-1.21.11/modules/git/repo_tag.go @@ -141,7 +141,7 @@ func (repo *Repository) GetTagInfos(page break } - tag, err := parseTagRef(ref) + tag, err := parseTagRef(repo.objectFormat, ref) if err != nil { return nil, 0, fmt.Errorf("GetTagInfos: parse tag: %w", err) } @@ -161,7 +161,7 @@ func (repo *Repository) GetTagInfos(page } // parseTagRef parses a tag from a 'git for-each-ref'-produced reference. -func parseTagRef(ref map[string]string) (tag *Tag, err error) { +func parseTagRef(objectFormat ObjectFormat, ref map[string]string) (tag *Tag, err error) { tag = &Tag{ Type: ref["objecttype"], Name: ref["refname:lstrip=2"], Index: gitea-1.21.11/modules/git/repo_tag_gogit.go =================================================================== --- gitea-1.21.11.orig/modules/git/repo_tag_gogit.go +++ gitea-1.21.11/modules/git/repo_tag_gogit.go @@ -55,9 +55,9 @@ func (repo *Repository) GetTags(skip, li } // GetTagType gets the type of the tag, either commit (simple) or tag (annotated) -func (repo *Repository) GetTagType(id SHA1) (string, error) { +func (repo *Repository) GetTagType(id ObjectID) (string, error) { // Get tag type - obj, err := repo.gogitRepo.Object(plumbing.AnyObject, id) + obj, err := repo.gogitRepo.Object(plumbing.AnyObject, plumbing.Hash(id.RawValue())) if err != nil { if err == plumbing.ErrReferenceNotFound { return "", &ErrNotExist{ID: id.String()} @@ -68,7 +68,7 @@ func (repo *Repository) GetTagType(id SH return obj.Type().String(), nil } -func (repo *Repository) getTag(tagID SHA1, name string) (*Tag, error) { +func (repo *Repository) getTag(tagID ObjectID, name string) (*Tag, error) { t, ok := repo.tagCache.Get(tagID.String()) if ok { log.Debug("Hit cache: %s", tagID) @@ -112,7 +112,7 @@ func (repo *Repository) getTag(tagID SHA return tag, nil } - gogitTag, err := repo.gogitRepo.TagObject(tagID) + gogitTag, err := repo.gogitRepo.TagObject(plumbing.Hash(tagID.RawValue())) if err != nil { if err == plumbing.ErrReferenceNotFound { return nil, &ErrNotExist{ID: tagID.String()} @@ -124,7 +124,7 @@ func (repo *Repository) getTag(tagID SHA tag := &Tag{ Name: name, ID: tagID, - Object: gogitTag.Target, + Object: commitID.Type().MustID(gogitTag.Target[:]), Type: tp, Tagger: &gogitTag.Tagger, Message: gogitTag.Message, Index: gitea-1.21.11/modules/git/repo_tag_nogogit.go =================================================================== --- gitea-1.21.11.orig/modules/git/repo_tag_nogogit.go +++ gitea-1.21.11/modules/git/repo_tag_nogogit.go @@ -30,7 +30,7 @@ func (repo *Repository) GetTags(skip, li } // GetTagType gets the type of the tag, either commit (simple) or tag (annotated) -func (repo *Repository) GetTagType(id SHA1) (string, error) { +func (repo *Repository) GetTagType(id ObjectID) (string, error) { wr, rd, cancel := repo.CatFileBatchCheck(repo.Ctx) defer cancel() _, err := wr.Write([]byte(id.String() + "\n")) @@ -44,7 +44,7 @@ func (repo *Repository) GetTagType(id SH return typ, nil } -func (repo *Repository) getTag(tagID SHA1, name string) (*Tag, error) { +func (repo *Repository) getTag(tagID ObjectID, name string) (*Tag, error) { t, ok := repo.tagCache.Get(tagID.String()) if ok { log.Debug("Hit cache: %s", tagID) @@ -120,7 +120,7 @@ func (repo *Repository) getTag(tagID SHA return nil, err } - tag, err := parseTagData(data) + tag, err := parseTagData(tagID.Type(), data) if err != nil { return nil, err } Index: gitea-1.21.11/modules/git/repo_tag_test.go =================================================================== --- gitea-1.21.11.orig/modules/git/repo_tag_test.go +++ gitea-1.21.11/modules/git/repo_tag_test.go @@ -196,6 +196,7 @@ func TestRepository_GetAnnotatedTag(t *t } func TestRepository_parseTagRef(t *testing.T) { + sha1 := Sha1ObjectFormat tests := []struct { name string @@ -352,7 +353,7 @@ Add changelog of v1.9.1 (#7859) for _, test := range tests { tc := test // don't close over loop variable t.Run(tc.name, func(t *testing.T) { - got, err := parseTagRef(tc.givenRef) + got, err := parseTagRef(sha1, tc.givenRef) if tc.wantErr { require.Error(t, err) Index: gitea-1.21.11/modules/git/repo_tree.go =================================================================== --- gitea-1.21.11.orig/modules/git/repo_tree.go +++ gitea-1.21.11/modules/git/repo_tree.go @@ -21,7 +21,7 @@ type CommitTreeOpts struct { } // CommitTree creates a commit from a given tree id for the user with provided message -func (repo *Repository) CommitTree(author, committer *Signature, tree *Tree, opts CommitTreeOpts) (SHA1, error) { +func (repo *Repository) CommitTree(author, committer *Signature, tree *Tree, opts CommitTreeOpts) (ObjectID, error) { commitTimeStr := time.Now().Format(time.RFC3339) // Because this may call hooks we should pass in the environment @@ -61,7 +61,7 @@ func (repo *Repository) CommitTree(autho Stderr: stderr, }) if err != nil { - return SHA1{}, ConcatenateError(err, stderr.String()) + return nil, ConcatenateError(err, stderr.String()) } return NewIDFromString(strings.TrimSpace(stdout.String())) } Index: gitea-1.21.11/modules/git/repo_tree_gogit.go =================================================================== --- gitea-1.21.11.orig/modules/git/repo_tree_gogit.go +++ gitea-1.21.11/modules/git/repo_tree_gogit.go @@ -6,8 +6,10 @@ package git -func (repo *Repository) getTree(id SHA1) (*Tree, error) { - gogitTree, err := repo.gogitRepo.TreeObject(id) +import "github.com/go-git/go-git/v5/plumbing" + +func (repo *Repository) getTree(id ObjectID) (*Tree, error) { + gogitTree, err := repo.gogitRepo.TreeObject(plumbing.Hash(id.RawValue())) if err != nil { return nil, err } @@ -19,7 +21,7 @@ func (repo *Repository) getTree(id SHA1) // GetTree find the tree object in the repository. func (repo *Repository) GetTree(idStr string) (*Tree, error) { - if len(idStr) != SHAFullLength { + if len(idStr) != repo.objectFormat.FullLength() { res, _, err := NewCommand(repo.Ctx, "rev-parse", "--verify").AddDynamicArguments(idStr).RunStdString(&RunOpts{Dir: repo.Path}) if err != nil { return nil, err @@ -33,9 +35,9 @@ func (repo *Repository) GetTree(idStr st return nil, err } resolvedID := id - commitObject, err := repo.gogitRepo.CommitObject(id) + commitObject, err := repo.gogitRepo.CommitObject(plumbing.Hash(id.RawValue())) if err == nil { - id = SHA1(commitObject.TreeHash) + id = ParseGogitHash(commitObject.TreeHash) } treeObject, err := repo.getTree(id) if err != nil { Index: gitea-1.21.11/modules/git/repo_tree_nogogit.go =================================================================== --- gitea-1.21.11.orig/modules/git/repo_tree_nogogit.go +++ gitea-1.21.11/modules/git/repo_tree_nogogit.go @@ -9,7 +9,7 @@ import ( "io" ) -func (repo *Repository) getTree(id SHA1) (*Tree, error) { +func (repo *Repository) getTree(id ObjectID) (*Tree, error) { wr, rd, cancel := repo.CatFileBatch(repo.Ctx) defer cancel() @@ -28,7 +28,7 @@ func (repo *Repository) getTree(id SHA1) if err != nil { return nil, err } - tag, err := parseTagData(data) + tag, err := parseTagData(id.Type(), data) if err != nil { return nil, err } @@ -51,7 +51,7 @@ func (repo *Repository) getTree(id SHA1) case "tree": tree := NewTree(repo, id) tree.ResolvedID = id - tree.entries, err = catBatchParseTreeEntries(tree, rd, size) + tree.entries, err = catBatchParseTreeEntries(repo.objectFormat, tree, rd, size) if err != nil { return nil, err } @@ -69,7 +69,7 @@ func (repo *Repository) getTree(id SHA1) // GetTree find the tree object in the repository. func (repo *Repository) GetTree(idStr string) (*Tree, error) { - if len(idStr) != SHAFullLength { + if len(idStr) != repo.objectFormat.FullLength() { res, err := repo.GetRefCommitID(idStr) if err != nil { return nil, err Index: gitea-1.21.11/modules/git/sha1.go =================================================================== --- gitea-1.21.11.orig/modules/git/sha1.go +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2015 The Gogs Authors. All rights reserved. -// Copyright 2019 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package git - -import ( - "encoding/hex" - "fmt" - "regexp" - "strings" -) - -// EmptySHA defines empty git SHA (undefined, non-existent) -const EmptySHA = "0000000000000000000000000000000000000000" - -// EmptyTreeSHA is the SHA of an empty tree, the root of all git repositories -const EmptyTreeSHA = "4b825dc642cb6eb9a060e54bf8d69288fbee4904" - -// SHAFullLength is the full length of a git SHA -const SHAFullLength = 40 - -// SHAPattern can be used to determine if a string is an valid sha -var shaPattern = regexp.MustCompile(`^[0-9a-f]{4,40}$`) - -// IsValidSHAPattern will check if the provided string matches the SHA Pattern -func IsValidSHAPattern(sha string) bool { - return shaPattern.MatchString(sha) -} - -type ErrInvalidSHA struct { - SHA string -} - -func (err ErrInvalidSHA) Error() string { - return fmt.Sprintf("invalid sha: %s", err.SHA) -} - -// MustID always creates a new SHA1 from a [20]byte array with no validation of input. -func MustID(b []byte) SHA1 { - var id SHA1 - copy(id[:], b) - return id -} - -// NewID creates a new SHA1 from a [20]byte array. -func NewID(b []byte) (SHA1, error) { - if len(b) != 20 { - return SHA1{}, fmt.Errorf("Length must be 20: %v", b) - } - return MustID(b), nil -} - -// MustIDFromString always creates a new sha from a ID with no validation of input. -func MustIDFromString(s string) SHA1 { - b, _ := hex.DecodeString(s) - return MustID(b) -} - -// NewIDFromString creates a new SHA1 from a ID string of length 40. -func NewIDFromString(s string) (SHA1, error) { - var id SHA1 - s = strings.TrimSpace(s) - if len(s) != SHAFullLength { - return id, fmt.Errorf("Length must be 40: %s", s) - } - b, err := hex.DecodeString(s) - if err != nil { - return id, err - } - return NewID(b) -} Index: gitea-1.21.11/modules/git/sha1_gogit.go =================================================================== --- gitea-1.21.11.orig/modules/git/sha1_gogit.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2015 The Gogs Authors. All rights reserved. -// Copyright 2019 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -//go:build gogit - -package git - -import ( - "github.com/go-git/go-git/v5/plumbing" -) - -// SHA1 a git commit name -type SHA1 = plumbing.Hash - -// ComputeBlobHash compute the hash for a given blob content -func ComputeBlobHash(content []byte) SHA1 { - return plumbing.ComputeHash(plumbing.BlobObject, content) -} Index: gitea-1.21.11/modules/git/sha1_nogogit.go =================================================================== --- gitea-1.21.11.orig/modules/git/sha1_nogogit.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2015 The Gogs Authors. All rights reserved. -// Copyright 2019 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -//go:build !gogit - -package git - -import ( - "crypto/sha1" - "encoding/hex" - "hash" - "strconv" -) - -// SHA1 a git commit name -type SHA1 [20]byte - -// String returns a string representation of the SHA -func (s SHA1) String() string { - return hex.EncodeToString(s[:]) -} - -// IsZero returns whether this SHA1 is all zeroes -func (s SHA1) IsZero() bool { - var empty SHA1 - return s == empty -} - -// ComputeBlobHash compute the hash for a given blob content -func ComputeBlobHash(content []byte) SHA1 { - return ComputeHash(ObjectBlob, content) -} - -// ComputeHash compute the hash for a given ObjectType and content -func ComputeHash(t ObjectType, content []byte) SHA1 { - h := NewHasher(t, int64(len(content))) - _, _ = h.Write(content) - return h.Sum() -} - -// Hasher is a struct that will generate a SHA1 -type Hasher struct { - hash.Hash -} - -// NewHasher takes an object type and size and creates a hasher to generate a SHA -func NewHasher(t ObjectType, size int64) Hasher { - h := Hasher{sha1.New()} - _, _ = h.Write(t.Bytes()) - _, _ = h.Write([]byte(" ")) - _, _ = h.Write([]byte(strconv.FormatInt(size, 10))) - _, _ = h.Write([]byte{0}) - return h -} - -// Sum generates a SHA1 for the provided hash -func (h Hasher) Sum() (sha1 SHA1) { - copy(sha1[:], h.Hash.Sum(nil)) - return sha1 -} Index: gitea-1.21.11/modules/git/sha1_test.go =================================================================== --- gitea-1.21.11.orig/modules/git/sha1_test.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2022 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package git - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestIsValidSHAPattern(t *testing.T) { - assert.True(t, IsValidSHAPattern("fee1")) - assert.True(t, IsValidSHAPattern("abc000")) - assert.True(t, IsValidSHAPattern("9023902390239023902390239023902390239023")) - assert.False(t, IsValidSHAPattern("90239023902390239023902390239023902390239023")) - assert.False(t, IsValidSHAPattern("abc")) - assert.False(t, IsValidSHAPattern("123g")) - assert.False(t, IsValidSHAPattern("some random text")) -} Index: gitea-1.21.11/modules/git/tag.go =================================================================== --- gitea-1.21.11.orig/modules/git/tag.go +++ gitea-1.21.11/modules/git/tag.go @@ -19,8 +19,8 @@ const ( // Tag represents a Git tag. type Tag struct { Name string - ID SHA1 - Object SHA1 // The id of this commit object + ID ObjectID + Object ObjectID // The id of this commit object Type string Tagger *Signature Message string @@ -35,8 +35,10 @@ func (tag *Tag) Commit(gitRepo *Reposito // Parse commit information from the (uncompressed) raw // data from the commit object. // \n\n separate headers from message -func parseTagData(data []byte) (*Tag, error) { +func parseTagData(objectFormat ObjectFormat, data []byte) (*Tag, error) { tag := new(Tag) + tag.ID = objectFormat.EmptyObjectID() + tag.Object = objectFormat.EmptyObjectID() tag.Tagger = &Signature{} // we now have the contents of the commit object. Let's investigate... nextline := 0 Index: gitea-1.21.11/modules/git/tag_test.go =================================================================== --- gitea-1.21.11.orig/modules/git/tag_test.go +++ gitea-1.21.11/modules/git/tag_test.go @@ -22,8 +22,8 @@ tagger Lucas Michot <lucas@semalead.com> `), tag: Tag{ Name: "", - ID: SHA1{}, - Object: SHA1{0x3b, 0x11, 0x4a, 0xb8, 0x0, 0xc6, 0x43, 0x2a, 0xd4, 0x23, 0x87, 0xcc, 0xf6, 0xbc, 0x8d, 0x43, 0x88, 0xa2, 0x88, 0x5a}, + ID: Sha1ObjectFormat.EmptyObjectID(), + Object: &Sha1Hash{0x3b, 0x11, 0x4a, 0xb8, 0x0, 0xc6, 0x43, 0x2a, 0xd4, 0x23, 0x87, 0xcc, 0xf6, 0xbc, 0x8d, 0x43, 0x88, 0xa2, 0x88, 0x5a}, Type: "commit", Tagger: &Signature{Name: "Lucas Michot", Email: "lucas@semalead.com", When: time.Unix(1484491741, 0)}, Message: "", @@ -39,8 +39,8 @@ o ono`), tag: Tag{ Name: "", - ID: SHA1{}, - Object: SHA1{0x7c, 0xdf, 0x42, 0xc0, 0xb1, 0xcc, 0x76, 0x3a, 0xb7, 0xe4, 0xc3, 0x3c, 0x47, 0xa2, 0x4e, 0x27, 0xc6, 0x6b, 0xfc, 0xcc}, + ID: Sha1ObjectFormat.EmptyObjectID(), + Object: &Sha1Hash{0x7c, 0xdf, 0x42, 0xc0, 0xb1, 0xcc, 0x76, 0x3a, 0xb7, 0xe4, 0xc3, 0x3c, 0x47, 0xa2, 0x4e, 0x27, 0xc6, 0x6b, 0xfc, 0xcc}, Type: "commit", Tagger: &Signature{Name: "Lucas Michot", Email: "lucas@semalead.com", When: time.Unix(1484553735, 0)}, Message: "test message\no\n\nono", @@ -49,7 +49,7 @@ ono`), tag: Tag{ } for _, test := range testData { - tag, err := parseTagData(test.data) + tag, err := parseTagData(Sha1ObjectFormat, test.data) assert.NoError(t, err) assert.EqualValues(t, test.tag.ID, tag.ID) assert.EqualValues(t, test.tag.Object, tag.Object) Index: gitea-1.21.11/modules/git/tree.go =================================================================== --- gitea-1.21.11.orig/modules/git/tree.go +++ gitea-1.21.11/modules/git/tree.go @@ -10,7 +10,7 @@ import ( ) // NewTree create a new tree according the repository and tree id -func NewTree(repo *Repository, id SHA1) *Tree { +func NewTree(repo *Repository, id ObjectID) *Tree { return &Tree{ ID: id, repo: repo, Index: gitea-1.21.11/modules/git/tree_blob_gogit.go =================================================================== --- gitea-1.21.11.orig/modules/git/tree_blob_gogit.go +++ gitea-1.21.11/modules/git/tree_blob_gogit.go @@ -24,7 +24,7 @@ func (t *Tree) GetTreeEntryByPath(relpat gogitTreeEntry: &object.TreeEntry{ Name: "", Mode: filemode.Dir, - Hash: t.ID, + Hash: plumbing.Hash(t.ID.RawValue()), }, }, nil } Index: gitea-1.21.11/modules/git/tree_entry_gogit.go =================================================================== --- gitea-1.21.11.orig/modules/git/tree_entry_gogit.go +++ gitea-1.21.11/modules/git/tree_entry_gogit.go @@ -14,7 +14,7 @@ import ( // TreeEntry the leaf in the git tree type TreeEntry struct { - ID SHA1 + ID ObjectID gogitTreeEntry *object.TreeEntry ptree *Tree @@ -88,7 +88,7 @@ func (te *TreeEntry) Blob() *Blob { } return &Blob{ - ID: te.gogitTreeEntry.Hash, + ID: ParseGogitHash(te.gogitTreeEntry.Hash), gogitEncodedObj: encodedObj, name: te.Name(), } Index: gitea-1.21.11/modules/git/tree_entry_nogogit.go =================================================================== --- gitea-1.21.11.orig/modules/git/tree_entry_nogogit.go +++ gitea-1.21.11/modules/git/tree_entry_nogogit.go @@ -9,7 +9,7 @@ import "code.gitea.io/gitea/modules/log" // TreeEntry the leaf in the git tree type TreeEntry struct { - ID SHA1 + ID ObjectID ptree *Tree Index: gitea-1.21.11/modules/git/tree_gogit.go =================================================================== --- gitea-1.21.11.orig/modules/git/tree_gogit.go +++ gitea-1.21.11/modules/git/tree_gogit.go @@ -15,8 +15,8 @@ import ( // Tree represents a flat directory listing. type Tree struct { - ID SHA1 - ResolvedID SHA1 + ID ObjectID + ResolvedID ObjectID repo *Repository gogitTree *object.Tree @@ -26,7 +26,7 @@ type Tree struct { } func (t *Tree) loadTreeObject() error { - gogitTree, err := t.repo.gogitRepo.TreeObject(t.ID) + gogitTree, err := t.repo.gogitRepo.TreeObject(plumbing.Hash(t.ID.RawValue())) if err != nil { return err } @@ -47,7 +47,7 @@ func (t *Tree) ListEntries() (Entries, e entries := make([]*TreeEntry, len(t.gogitTree.Entries)) for i, entry := range t.gogitTree.Entries { entries[i] = &TreeEntry{ - ID: entry.Hash, + ID: ParseGogitHash(entry.Hash), gogitTreeEntry: &t.gogitTree.Entries[i], ptree: t, } @@ -81,7 +81,7 @@ func (t *Tree) ListEntriesRecursiveWithS } convertedEntry := &TreeEntry{ - ID: entry.Hash, + ID: ParseGogitHash(entry.Hash), gogitTreeEntry: &entry, ptree: t, fullName: fullName, Index: gitea-1.21.11/modules/git/tree_nogogit.go =================================================================== --- gitea-1.21.11.orig/modules/git/tree_nogogit.go +++ gitea-1.21.11/modules/git/tree_nogogit.go @@ -12,8 +12,8 @@ import ( // Tree represents a flat directory listing. type Tree struct { - ID SHA1 - ResolvedID SHA1 + ID ObjectID + ResolvedID ObjectID repo *Repository // parent tree @@ -53,7 +53,7 @@ func (t *Tree) ListEntries() (Entries, e } } if typ == "tree" { - t.entries, err = catBatchParseTreeEntries(t, rd, sz) + t.entries, err = catBatchParseTreeEntries(t.ID.Type(), t, rd, sz) if err != nil { return nil, err } @@ -78,7 +78,7 @@ func (t *Tree) ListEntries() (Entries, e } var err error - t.entries, err = parseTreeEntries(stdout, t) + t.entries, err = parseTreeEntries(t.repo.objectFormat, stdout, t) if err == nil { t.entriesParsed = true } @@ -102,7 +102,7 @@ func (t *Tree) listEntriesRecursive(extr } var err error - t.entriesRecursive, err = parseTreeEntries(stdout, t) + t.entriesRecursive, err = parseTreeEntries(t.repo.objectFormat, stdout, t) if err == nil { t.entriesRecursiveParsed = true } Index: gitea-1.21.11/modules/indexer/code/git.go =================================================================== --- gitea-1.21.11.orig/modules/indexer/code/git.go +++ gitea-1.21.11/modules/indexer/code/git.go @@ -62,8 +62,8 @@ func isIndexable(entry *git.TreeEntry) b } // parseGitLsTreeOutput parses the output of a `git ls-tree -r --full-name` command -func parseGitLsTreeOutput(stdout []byte) ([]internal.FileUpdate, error) { - entries, err := git.ParseTreeEntries(stdout) +func parseGitLsTreeOutput(objectFormat git.ObjectFormat, stdout []byte) ([]internal.FileUpdate, error) { + entries, err := git.ParseTreeEntries(objectFormat, stdout) if err != nil { return nil, err } @@ -92,7 +92,11 @@ func genesisChanges(ctx context.Context, } var err error - changes.Updates, err = parseGitLsTreeOutput(stdout) + objectFormat, err := git.GetObjectFormatOfRepo(ctx, repo.RepoPath()) + if err != nil { + return nil, err + } + changes.Updates, err = parseGitLsTreeOutput(objectFormat, stdout) return &changes, err } @@ -169,6 +173,11 @@ func nonGenesisChanges(ctx context.Conte if err != nil { return nil, err } - changes.Updates, err = parseGitLsTreeOutput(lsTreeStdout) + + objectFormat, err := git.GetObjectFormatOfRepo(ctx, repo.RepoPath()) + if err != nil { + return nil, err + } + changes.Updates, err = parseGitLsTreeOutput(objectFormat, lsTreeStdout) return &changes, err } Index: gitea-1.21.11/modules/repository/generate.go =================================================================== --- gitea-1.21.11.orig/modules/repository/generate.go +++ gitea-1.21.11/modules/repository/generate.go @@ -223,7 +223,8 @@ func generateRepoCommit(ctx context.Cont } } - if err := git.InitRepository(ctx, tmpDir, false); err != nil { + // FIXME: fix the hash + if err := git.InitRepository(ctx, tmpDir, false, git.Sha1ObjectFormat.Name()); err != nil { return err } @@ -356,7 +357,8 @@ func GenerateRepository(ctx context.Cont } } - if err = CheckInitRepository(ctx, owner.Name, generateRepo.Name); err != nil { + // FIXME - fix the hash + if err = CheckInitRepository(ctx, owner.Name, generateRepo.Name, git.Sha1ObjectFormat.Name()); err != nil { return generateRepo, err } Index: gitea-1.21.11/modules/repository/init.go =================================================================== --- gitea-1.21.11.orig/modules/repository/init.go +++ gitea-1.21.11/modules/repository/init.go @@ -188,7 +188,7 @@ func InitRepoCommit(ctx context.Context, return nil } -func CheckInitRepository(ctx context.Context, owner, name string) (err error) { +func CheckInitRepository(ctx context.Context, owner, name, objectFormatName string) (err error) { // Somehow the directory could exist. repoPath := repo_model.RepoPath(owner, name) isExist, err := util.IsExist(repoPath) @@ -204,7 +204,7 @@ func CheckInitRepository(ctx context.Con } // Init git bare new repository. - if err = git.InitRepository(ctx, repoPath, true); err != nil { + if err = git.InitRepository(ctx, repoPath, true, objectFormatName); err != nil { return fmt.Errorf("git.InitRepository: %w", err) } else if err = CreateDelegateHooks(repoPath); err != nil { return fmt.Errorf("createDelegateHooks: %w", err) Index: gitea-1.21.11/modules/repository/push.go =================================================================== --- gitea-1.21.11.orig/modules/repository/push.go +++ gitea-1.21.11/modules/repository/push.go @@ -20,12 +20,14 @@ type PushUpdateOptions struct { // IsNewRef return true if it's a first-time push to a branch, tag or etc. func (opts *PushUpdateOptions) IsNewRef() bool { - return opts.OldCommitID == git.EmptySHA + commitID, err := git.NewIDFromString(opts.OldCommitID) + return err == nil && commitID.IsZero() } // IsDelRef return true if it's a deletion to a branch or tag func (opts *PushUpdateOptions) IsDelRef() bool { - return opts.NewCommitID == git.EmptySHA + commitID, err := git.NewIDFromString(opts.NewCommitID) + return err == nil && commitID.IsZero() } // IsUpdateRef return true if it's an update operation Index: gitea-1.21.11/routers/api/v1/repo/notes.go =================================================================== --- gitea-1.21.11.orig/routers/api/v1/repo/notes.go +++ gitea-1.21.11/routers/api/v1/repo/notes.go @@ -66,7 +66,7 @@ func getNote(ctx *context.APIContext, id return } - commitSHA, err := ctx.Repo.GitRepo.ConvertToSHA1(identifier) + commitID, err := ctx.Repo.GitRepo.ConvertToGitID(identifier) if err != nil { if git.IsErrNotExist(err) { ctx.NotFound(err) @@ -77,7 +77,7 @@ func getNote(ctx *context.APIContext, id } var note git.Note - if err := git.GetNote(ctx, ctx.Repo.GitRepo, commitSHA.String(), ¬e); err != nil { + if err := git.GetNote(ctx, ctx.Repo.GitRepo, commitID.String(), ¬e); err != nil { if git.IsErrNotExist(err) { ctx.NotFound(identifier) return Index: gitea-1.21.11/routers/api/v1/repo/repo.go =================================================================== --- gitea-1.21.11.orig/routers/api/v1/repo/repo.go +++ gitea-1.21.11/routers/api/v1/repo/repo.go @@ -243,17 +243,18 @@ func CreateUserRepo(ctx *context.APICont } repo, err := repo_service.CreateRepository(ctx, ctx.Doer, owner, repo_service.CreateRepoOptions{ - Name: opt.Name, - Description: opt.Description, - IssueLabels: opt.IssueLabels, - Gitignores: opt.Gitignores, - License: opt.License, - Readme: opt.Readme, - IsPrivate: opt.Private, - AutoInit: opt.AutoInit, - DefaultBranch: opt.DefaultBranch, - TrustModel: repo_model.ToTrustModel(opt.TrustModel), - IsTemplate: opt.Template, + Name: opt.Name, + Description: opt.Description, + IssueLabels: opt.IssueLabels, + Gitignores: opt.Gitignores, + License: opt.License, + Readme: opt.Readme, + IsPrivate: opt.Private, + AutoInit: opt.AutoInit, + DefaultBranch: opt.DefaultBranch, + TrustModel: repo_model.ToTrustModel(opt.TrustModel), + IsTemplate: opt.Template, + ObjectFormatName: opt.ObjectFormatName, }) if err != nil { if repo_model.IsErrRepoAlreadyExist(err) { Index: gitea-1.21.11/routers/api/v1/utils/git.go =================================================================== --- gitea-1.21.11.orig/routers/api/v1/utils/git.go +++ gitea-1.21.11/routers/api/v1/utils/git.go @@ -69,27 +69,28 @@ func searchRefCommitByType(ctx *context. return "", "", nil } -// ConvertToSHA1 returns a full-length SHA1 from a potential ID string -func ConvertToSHA1(ctx gocontext.Context, repo *context.Repository, commitID string) (git.SHA1, error) { - if len(commitID) == git.SHAFullLength && git.IsValidSHAPattern(commitID) { - sha1, err := git.NewIDFromString(commitID) +// ConvertToObjectID returns a full-length SHA1 from a potential ID string +func ConvertToObjectID(ctx gocontext.Context, repo *context.Repository, commitID string) (git.ObjectID, error) { + objectFormat, _ := repo.GitRepo.GetObjectFormat() + if len(commitID) == objectFormat.FullLength() && objectFormat.IsValid(commitID) { + sha, err := git.NewIDFromString(commitID) if err == nil { - return sha1, nil + return sha, nil } } gitRepo, closer, err := git.RepositoryFromContextOrOpen(ctx, repo.Repository.RepoPath()) if err != nil { - return git.SHA1{}, fmt.Errorf("RepositoryFromContextOrOpen: %w", err) + return objectFormat.EmptyObjectID(), fmt.Errorf("RepositoryFromContextOrOpen: %w", err) } defer closer.Close() - return gitRepo.ConvertToSHA1(commitID) + return gitRepo.ConvertToGitID(commitID) } // MustConvertToSHA1 returns a full-length SHA1 string from a potential ID string, or returns origin input if it can't convert to SHA1 func MustConvertToSHA1(ctx gocontext.Context, repo *context.Repository, commitID string) string { - sha, err := ConvertToSHA1(ctx, repo, commitID) + sha, err := ConvertToObjectID(ctx, repo, commitID) if err != nil { return commitID } Index: gitea-1.21.11/routers/private/hook_post_receive.go =================================================================== --- gitea-1.21.11.orig/routers/private/hook_post_receive.go +++ gitea-1.21.11/routers/private/hook_post_receive.go @@ -162,8 +162,7 @@ func HookPostReceive(ctx *gitea_context. newCommitID := opts.NewCommitIDs[i] // If we've pushed a branch (and not deleted it) - if newCommitID != git.EmptySHA && refFullName.IsBranch() { - + if git.IsEmptyCommitID(newCommitID) && refFullName.IsBranch() { // First ensure we have the repository loaded, we're allowed pulls requests and we can get the base repo if repo == nil { repo = loadRepository(ctx, ownerName, repoName) Index: gitea-1.21.11/routers/private/hook_pre_receive.go =================================================================== --- gitea-1.21.11.orig/routers/private/hook_pre_receive.go +++ gitea-1.21.11/routers/private/hook_pre_receive.go @@ -145,8 +145,9 @@ func preReceiveBranch(ctx *preReceiveCon repo := ctx.Repo.Repository gitRepo := ctx.Repo.GitRepo + objectFormat, _ := gitRepo.GetObjectFormat() - if branchName == repo.DefaultBranch && newCommitID == git.EmptySHA { + if branchName == repo.DefaultBranch && newCommitID == objectFormat.EmptyObjectID().String() { log.Warn("Forbidden: Branch: %s is the default branch in %-v and cannot be deleted", branchName, repo) ctx.JSON(http.StatusForbidden, private.Response{ UserMsg: fmt.Sprintf("branch %s is the default branch and cannot be deleted", branchName), @@ -174,7 +175,7 @@ func preReceiveBranch(ctx *preReceiveCon // First of all we need to enforce absolutely: // // 1. Detect and prevent deletion of the branch - if newCommitID == git.EmptySHA { + if newCommitID == objectFormat.EmptyObjectID().String() { log.Warn("Forbidden: Branch: %s in %-v is protected from deletion", branchName, repo) ctx.JSON(http.StatusForbidden, private.Response{ UserMsg: fmt.Sprintf("branch %s is protected from deletion", branchName), @@ -183,7 +184,7 @@ func preReceiveBranch(ctx *preReceiveCon } // 2. Disallow force pushes to protected branches - if git.EmptySHA != oldCommitID { + if oldCommitID != objectFormat.EmptyObjectID().String() { output, _, err := git.NewCommand(ctx, "rev-list", "--max-count=1").AddDynamicArguments(oldCommitID, "^"+newCommitID).RunStdString(&git.RunOpts{Dir: repo.RepoPath(), Env: ctx.env}) if err != nil { log.Error("Unable to detect force push between: %s and %s in %-v Error: %v", oldCommitID, newCommitID, repo, err) Index: gitea-1.21.11/routers/private/hook_verification.go =================================================================== --- gitea-1.21.11.orig/routers/private/hook_verification.go +++ gitea-1.21.11/routers/private/hook_verification.go @@ -29,7 +29,8 @@ func verifyCommits(oldCommitID, newCommi }() var command *git.Command - if oldCommitID == git.EmptySHA { + objectFormat, _ := repo.GetObjectFormat() + if oldCommitID == objectFormat.EmptyObjectID().String() { // When creating a new branch, the oldCommitID is empty, by using "newCommitID --not --all": // List commits that are reachable by following the newCommitID, exclude "all" existing heads/tags commits // So, it only lists the new commits received, doesn't list the commits already present in the receiving repository @@ -82,7 +83,8 @@ func readAndVerifyCommit(sha string, rep _ = stdoutReader.Close() _ = stdoutWriter.Close() }() - hash := git.MustIDFromString(sha) + + commitID := git.MustIDFromString(sha) return git.NewCommand(repo.Ctx, "cat-file", "commit").AddDynamicArguments(sha). Run(&git.RunOpts{ @@ -91,7 +93,7 @@ func readAndVerifyCommit(sha string, rep Stdout: stdoutWriter, PipelineFunc: func(ctx context.Context, cancel context.CancelFunc) error { _ = stdoutWriter.Close() - commit, err := git.CommitFromReader(repo, hash, stdoutReader) + commit, err := git.CommitFromReader(repo, commitID, stdoutReader) if err != nil { return err } Index: gitea-1.21.11/routers/private/hook_verification_test.go =================================================================== --- gitea-1.21.11.orig/routers/private/hook_verification_test.go +++ gitea-1.21.11/routers/private/hook_verification_test.go @@ -22,14 +22,17 @@ func TestVerifyCommits(t *testing.T) { defer gitRepo.Close() assert.NoError(t, err) + objectFormat, err := gitRepo.GetObjectFormat() + assert.NoError(t, err) + testCases := []struct { base, head string verified bool }{ {"72920278f2f999e3005801e5d5b8ab8139d3641c", "d766f2917716d45be24bfa968b8409544941be32", true}, - {git.EmptySHA, "93eac826f6188f34646cea81bf426aa5ba7d3bfe", true}, // New branch with verified commit + {objectFormat.EmptyObjectID().String(), "93eac826f6188f34646cea81bf426aa5ba7d3bfe", true}, // New branch with verified commit {"9779d17a04f1e2640583d35703c62460b2d86e0a", "72920278f2f999e3005801e5d5b8ab8139d3641c", false}, - {git.EmptySHA, "9ce3f779ae33f31fce17fac3c512047b75d7498b", false}, // New branch with unverified commit + {objectFormat.EmptyObjectID().String(), "9ce3f779ae33f31fce17fac3c512047b75d7498b", false}, // New branch with unverified commit } for _, tc := range testCases { Index: gitea-1.21.11/routers/web/repo/blame.go =================================================================== --- gitea-1.21.11.orig/routers/web/repo/blame.go +++ gitea-1.21.11/routers/web/repo/blame.go @@ -131,7 +131,12 @@ type blameResult struct { } func performBlame(ctx *context.Context, repoPath string, commit *git.Commit, file string, bypassBlameIgnore bool) (*blameResult, error) { - blameReader, err := git.CreateBlameReader(ctx, repoPath, commit, file, bypassBlameIgnore) + objectFormat, err := ctx.Repo.GitRepo.GetObjectFormat() + if err != nil { + ctx.NotFound("CreateBlameReader", err) + return nil, err + } + blameReader, err := git.CreateBlameReader(ctx, objectFormat, repoPath, commit, file, bypassBlameIgnore) if err != nil { return nil, err } @@ -147,7 +152,7 @@ func performBlame(ctx *context.Context, if len(r.Parts) == 0 && r.UsesIgnoreRevs { // try again without ignored revs - blameReader, err = git.CreateBlameReader(ctx, repoPath, commit, file, true) + blameReader, err = git.CreateBlameReader(ctx, objectFormat, repoPath, commit, file, true) if err != nil { return nil, err } Index: gitea-1.21.11/routers/web/repo/branch.go =================================================================== --- gitea-1.21.11.orig/routers/web/repo/branch.go +++ gitea-1.21.11/routers/web/repo/branch.go @@ -147,11 +147,18 @@ func RestoreBranchPost(ctx *context.Cont return } + objectFormat, err := git.GetObjectFormatOfRepo(ctx, ctx.Repo.Repository.RepoPath()) + if err != nil { + log.Error("RestoreBranch: CreateBranch: %w", err) + ctx.Flash.Error(ctx.Tr("repo.branch.restore_failed", deletedBranch.Name)) + return + } + // Don't return error below this if err := repo_service.PushUpdate( &repo_module.PushUpdateOptions{ RefFullName: git.RefNameFromBranch(deletedBranch.Name), - OldCommitID: git.EmptySHA, + OldCommitID: objectFormat.EmptyObjectID().String(), NewCommitID: deletedBranch.CommitID, PusherID: ctx.Doer.ID, PusherName: ctx.Doer.Name, Index: gitea-1.21.11/routers/web/repo/commit.go =================================================================== --- gitea-1.21.11.orig/routers/web/repo/commit.go +++ gitea-1.21.11/routers/web/repo/commit.go @@ -298,7 +298,7 @@ func Diff(ctx *context.Context) { } return } - if len(commitID) != git.SHAFullLength { + if len(commitID) != commit.ID.Type().FullLength() { commitID = commit.ID.String() } Index: gitea-1.21.11/routers/web/repo/compare.go =================================================================== --- gitea-1.21.11.orig/routers/web/repo/compare.go +++ gitea-1.21.11/routers/web/repo/compare.go @@ -310,13 +310,14 @@ func ParseCompareInfo(ctx *context.Conte baseIsCommit := ctx.Repo.GitRepo.IsCommitExist(ci.BaseBranch) baseIsBranch := ctx.Repo.GitRepo.IsBranchExist(ci.BaseBranch) baseIsTag := ctx.Repo.GitRepo.IsTagExist(ci.BaseBranch) + objectFormat, _ := ctx.Repo.GitRepo.GetObjectFormat() if !baseIsCommit && !baseIsBranch && !baseIsTag { // Check if baseBranch is short sha commit hash if baseCommit, _ := ctx.Repo.GitRepo.GetCommit(ci.BaseBranch); baseCommit != nil { ci.BaseBranch = baseCommit.ID.String() ctx.Data["BaseBranch"] = ci.BaseBranch baseIsCommit = true - } else if ci.BaseBranch == git.EmptySHA { + } else if ci.BaseBranch == objectFormat.EmptyObjectID().String() { if isSameRepo { ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ci.HeadBranch)) } else { Index: gitea-1.21.11/routers/web/repo/githttp.go =================================================================== --- gitea-1.21.11.orig/routers/web/repo/githttp.go +++ gitea-1.21.11/routers/web/repo/githttp.go @@ -329,7 +329,7 @@ func dummyInfoRefs(ctx *context.Context) } }() - if err := git.InitRepository(ctx, tmpDir, true); err != nil { + if err := git.InitRepository(ctx, tmpDir, true, git.Sha1ObjectFormat.Name()); err != nil { log.Error("Failed to init bare repo for git-receive-pack cache: %v", err) return } Index: gitea-1.21.11/routers/web/repo/repo.go =================================================================== --- gitea-1.21.11.orig/routers/web/repo/repo.go +++ gitea-1.21.11/routers/web/repo/repo.go @@ -179,6 +179,8 @@ func Create(ctx *context.Context) { ctx.Data["CanCreateRepo"] = ctx.Doer.CanCreateRepo() ctx.Data["MaxCreationLimit"] = ctx.Doer.MaxCreationLimit() + ctx.Data["SupportedObjectFormats"] = git.SupportedObjectFormats + ctx.Data["DefaultObjectFormat"] = git.Sha1ObjectFormat ctx.HTML(http.StatusOK, tplCreate) } @@ -278,17 +280,18 @@ func CreatePost(ctx *context.Context) { } } else { repo, err = repo_service.CreateRepository(ctx, ctx.Doer, ctxUser, repo_service.CreateRepoOptions{ - Name: form.RepoName, - Description: form.Description, - Gitignores: form.Gitignores, - IssueLabels: form.IssueLabels, - License: form.License, - Readme: form.Readme, - IsPrivate: form.Private || setting.Repository.ForcePrivate, - DefaultBranch: form.DefaultBranch, - AutoInit: form.AutoInit, - IsTemplate: form.Template, - TrustModel: repo_model.ToTrustModel(form.TrustModel), + Name: form.RepoName, + Description: form.Description, + Gitignores: form.Gitignores, + IssueLabels: form.IssueLabels, + License: form.License, + Readme: form.Readme, + IsPrivate: form.Private || setting.Repository.ForcePrivate, + DefaultBranch: form.DefaultBranch, + AutoInit: form.AutoInit, + IsTemplate: form.Template, + TrustModel: repo_model.ToTrustModel(form.TrustModel), + ObjectFormatName: form.ObjectFormatName, }) if err == nil { log.Trace("Repository created [%d]: %s/%s", repo.ID, ctxUser.Name, repo.Name) Index: gitea-1.21.11/routers/web/repo/setting/lfs.go =================================================================== --- gitea-1.21.11.orig/routers/web/repo/setting/lfs.go +++ gitea-1.21.11/routers/web/repo/setting/lfs.go @@ -388,20 +388,21 @@ func LFSFileFind(ctx *context.Context) { sha := ctx.FormString("sha") ctx.Data["Title"] = oid ctx.Data["PageIsSettingsLFS"] = true - var hash git.SHA1 + objectFormat, _ := ctx.Repo.GitRepo.GetObjectFormat() + var objectID git.ObjectID if len(sha) == 0 { pointer := lfs.Pointer{Oid: oid, Size: size} - hash = git.ComputeBlobHash([]byte(pointer.StringContent())) - sha = hash.String() + objectID = git.ComputeBlobHash(objectFormat, []byte(pointer.StringContent())) + sha = objectID.String() } else { - hash = git.MustIDFromString(sha) + objectID = git.MustIDFromString(sha) } ctx.Data["LFSFilesLink"] = ctx.Repo.RepoLink + "/settings/lfs" ctx.Data["Oid"] = oid ctx.Data["Size"] = size ctx.Data["SHA"] = sha - results, err := pipeline.FindLFSFile(ctx.Repo.GitRepo, hash) + results, err := pipeline.FindLFSFile(ctx.Repo.GitRepo, objectID) if err != nil && err != io.EOF { log.Error("Failure in FindLFSFile: %v", err) ctx.ServerError("LFSFind: FindLFSFile.", err) Index: gitea-1.21.11/routers/web/repo/setting/webhook.go =================================================================== --- gitea-1.21.11.orig/routers/web/repo/setting/webhook.go +++ gitea-1.21.11/routers/web/repo/setting/webhook.go @@ -654,8 +654,14 @@ func TestWebhook(ctx *context.Context) { commit := ctx.Repo.Commit if commit == nil { ghost := user_model.NewGhostUser() + objectFormat, err := git.GetObjectFormatOfRepo(ctx, ctx.Repo.Repository.RepoPath()) + if err != nil { + ctx.Flash.Error("GetObjectFormatOfRepo: " + err.Error()) + ctx.Status(http.StatusInternalServerError) + return + } commit = &git.Commit{ - ID: git.MustIDFromString(git.EmptySHA), + ID: objectFormat.EmptyObjectID(), Author: ghost.NewGitSig(), Committer: ghost.NewGitSig(), CommitMessage: "This is a fake commit", Index: gitea-1.21.11/services/agit/agit.go =================================================================== --- gitea-1.21.11.orig/services/agit/agit.go +++ gitea-1.21.11/services/agit/agit.go @@ -37,9 +37,10 @@ func ProcReceive(ctx context.Context, re topicBranch = opts.GitPushOptions["topic"] _, forcePush = opts.GitPushOptions["force-push"] + objectFormat, _ := gitRepo.GetObjectFormat() for i := range opts.OldCommitIDs { - if opts.NewCommitIDs[i] == git.EmptySHA { + if opts.NewCommitIDs[i] == objectFormat.EmptyObjectID().String() { results = append(results, private.HookProcReceiveRefResult{ OriginalRef: opts.RefFullNames[i], OldOID: opts.OldCommitIDs[i], @@ -149,10 +150,11 @@ func ProcReceive(ctx context.Context, re log.Trace("Pull request created: %d/%d", repo.ID, prIssue.ID) + objectFormat, _ := gitRepo.GetObjectFormat() results = append(results, private.HookProcReceiveRefResult{ Ref: pr.GetGitRefName(), OriginalRef: opts.RefFullNames[i], - OldOID: git.EmptySHA, + OldOID: objectFormat.EmptyObjectID().String(), NewOID: opts.NewCommitIDs[i], IsCreatePR: true, URL: fmt.Sprintf("%s/pulls/%d", repo.HTMLURL(), pr.Index), Index: gitea-1.21.11/services/convert/git_commit_test.go =================================================================== --- gitea-1.21.11.orig/services/convert/git_commit_test.go +++ gitea-1.21.11/services/convert/git_commit_test.go @@ -19,12 +19,12 @@ import ( func TestToCommitMeta(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) headRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) - sha1, _ := git.NewIDFromString("0000000000000000000000000000000000000000") + sha1 := git.Sha1ObjectFormat signature := &git.Signature{Name: "Test Signature", Email: "test@email.com", When: time.Unix(0, 0)} tag := &git.Tag{ Name: "Test Tag", - ID: sha1, - Object: sha1, + ID: sha1.EmptyObjectID(), + Object: sha1.EmptyObjectID(), Type: "Test Type", Tagger: signature, Message: "Test Message", @@ -34,8 +34,8 @@ func TestToCommitMeta(t *testing.T) { assert.NotNil(t, commitMeta) assert.EqualValues(t, &api.CommitMeta{ - SHA: "0000000000000000000000000000000000000000", - URL: util.URLJoin(headRepo.APIURL(), "git/commits", "0000000000000000000000000000000000000000"), + SHA: sha1.EmptyObjectID().String(), + URL: util.URLJoin(headRepo.APIURL(), "git/commits", sha1.EmptyObjectID().String()), Created: time.Unix(0, 0), }, commitMeta) } Index: gitea-1.21.11/services/forms/repo_form.go =================================================================== --- gitea-1.21.11.orig/services/forms/repo_form.go +++ gitea-1.21.11/services/forms/repo_form.go @@ -51,6 +51,8 @@ type CreateRepoForm struct { Labels bool ProtectedBranch bool TrustModel string + + ObjectFormatName string } // Validate validates the fields Index: gitea-1.21.11/services/gitdiff/gitdiff.go =================================================================== --- gitea-1.21.11.orig/services/gitdiff/gitdiff.go +++ gitea-1.21.11/services/gitdiff/gitdiff.go @@ -1115,10 +1115,15 @@ func GetDiff(gitRepo *git.Repository, op } cmdDiff := git.NewCommand(gitRepo.Ctx) - if (len(opts.BeforeCommitID) == 0 || opts.BeforeCommitID == git.EmptySHA) && commit.ParentCount() == 0 { + objectFormat, err := gitRepo.GetObjectFormat() + if err != nil { + return nil, err + } + + if (len(opts.BeforeCommitID) == 0 || opts.BeforeCommitID == objectFormat.EmptyObjectID().String()) && commit.ParentCount() == 0 { cmdDiff.AddArguments("diff", "--src-prefix=\\a/", "--dst-prefix=\\b/", "-M"). AddArguments(opts.WhitespaceBehavior...). - AddArguments("4b825dc642cb6eb9a060e54bf8d69288fbee4904"). // append empty tree ref + AddDynamicArguments(objectFormat.EmptyTree().String()). AddDynamicArguments(opts.AfterCommitID) } else { actualBeforeCommitID := opts.BeforeCommitID @@ -1224,8 +1229,8 @@ func GetDiff(gitRepo *git.Repository, op } diffPaths := []string{opts.BeforeCommitID + separator + opts.AfterCommitID} - if len(opts.BeforeCommitID) == 0 || opts.BeforeCommitID == git.EmptySHA { - diffPaths = []string{git.EmptyTreeSHA, opts.AfterCommitID} + if len(opts.BeforeCommitID) == 0 || opts.BeforeCommitID == objectFormat.EmptyObjectID().String() { + diffPaths = []string{objectFormat.EmptyTree().String(), opts.AfterCommitID} } diff.NumFiles, diff.TotalAddition, diff.TotalDeletion, err = git.GetDiffShortStat(gitRepo.Ctx, repoPath, nil, diffPaths...) if err != nil && strings.Contains(err.Error(), "no merge base") { @@ -1256,12 +1261,15 @@ func GetPullDiffStats(gitRepo *git.Repos separator = ".." } - diffPaths := []string{opts.BeforeCommitID + separator + opts.AfterCommitID} - if len(opts.BeforeCommitID) == 0 || opts.BeforeCommitID == git.EmptySHA { - diffPaths = []string{git.EmptyTreeSHA, opts.AfterCommitID} + objectFormat, err := gitRepo.GetObjectFormat() + if err != nil { + return nil, err } - var err error + diffPaths := []string{opts.BeforeCommitID + separator + opts.AfterCommitID} + if len(opts.BeforeCommitID) == 0 || opts.BeforeCommitID == objectFormat.EmptyObjectID().String() { + diffPaths = []string{objectFormat.EmptyTree().String(), opts.AfterCommitID} + } _, diff.TotalAddition, diff.TotalDeletion, err = git.GetDiffShortStat(gitRepo.Ctx, repoPath, nil, diffPaths...) if err != nil && strings.Contains(err.Error(), "no merge base") { Index: gitea-1.21.11/services/migrations/common.go =================================================================== --- gitea-1.21.11.orig/services/migrations/common.go +++ gitea-1.21.11/services/migrations/common.go @@ -48,16 +48,18 @@ func CheckAndEnsureSafePR(pr *base.PullR } // SECURITY: SHAs Must be a SHA - if pr.MergeCommitSHA != "" && !git.IsValidSHAPattern(pr.MergeCommitSHA) { + // FIXME: hash only a SHA1 + CommitType := git.Sha1ObjectFormat + if pr.MergeCommitSHA != "" && !CommitType.IsValid(pr.MergeCommitSHA) { WarnAndNotice("PR #%d in %s has invalid MergeCommitSHA: %s", pr.Number, g, pr.MergeCommitSHA) pr.MergeCommitSHA = "" } - if pr.Head.SHA != "" && !git.IsValidSHAPattern(pr.Head.SHA) { + if pr.Head.SHA != "" && !CommitType.IsValid(pr.Head.SHA) { WarnAndNotice("PR #%d in %s has invalid HeadSHA: %s", pr.Number, g, pr.Head.SHA) pr.Head.SHA = "" valid = false } - if pr.Base.SHA != "" && !git.IsValidSHAPattern(pr.Base.SHA) { + if pr.Base.SHA != "" && !CommitType.IsValid(pr.Base.SHA) { WarnAndNotice("PR #%d in %s has invalid BaseSHA: %s", pr.Number, g, pr.Base.SHA) pr.Base.SHA = "" valid = false Index: gitea-1.21.11/services/migrations/gitea_uploader.go =================================================================== --- gitea-1.21.11.orig/services/migrations/gitea_uploader.go +++ gitea-1.21.11/services/migrations/gitea_uploader.go @@ -893,7 +893,8 @@ func (g *GiteaLocalUploader) CreateRevie comment.UpdatedAt = comment.CreatedAt } - if !git.IsValidSHAPattern(comment.CommitID) { + objectFormat, _ := g.gitRepo.GetObjectFormat() + if !objectFormat.IsValid(comment.CommitID) { log.Warn("Invalid comment CommitID[%s] on comment[%d] in PR #%d of %s/%s replaced with %s", comment.CommitID, pr.Index, g.repoOwner, g.repoName, headCommitID) comment.CommitID = headCommitID } Index: gitea-1.21.11/services/migrations/gitea_uploader_test.go =================================================================== --- gitea-1.21.11.orig/services/migrations/gitea_uploader_test.go +++ gitea-1.21.11/services/migrations/gitea_uploader_test.go @@ -232,7 +232,7 @@ func TestGiteaUploadUpdateGitForPullRequ // fromRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) baseRef := "master" - assert.NoError(t, git.InitRepository(git.DefaultContext, fromRepo.RepoPath(), false)) + assert.NoError(t, git.InitRepository(git.DefaultContext, fromRepo.RepoPath(), false, fromRepo.ObjectFormatName)) err := git.NewCommand(git.DefaultContext, "symbolic-ref").AddDynamicArguments("HEAD", git.BranchPrefix+baseRef).Run(&git.RunOpts{Dir: fromRepo.RepoPath()}) assert.NoError(t, err) assert.NoError(t, os.WriteFile(filepath.Join(fromRepo.RepoPath(), "README.md"), []byte(fmt.Sprintf("# Testing Repository\n\nOriginally created in: %s", fromRepo.RepoPath())), 0o644)) Index: gitea-1.21.11/services/mirror/mirror_pull.go =================================================================== --- gitea-1.21.11.orig/services/mirror/mirror_pull.go +++ gitea-1.21.11/services/mirror/mirror_pull.go @@ -485,9 +485,13 @@ func SyncPullMirror(ctx context.Context, log.Error("SyncMirrors [repo: %-v]: unable to GetRefCommitID [ref_name: %s]: %v", m.Repo, result.refName, err) continue } + objectFormat, err := git.GetObjectFormatOfRepo(ctx, m.Repo.RepoPath()) + if err != nil { + log.Error("SyncMirrors [repo: %-v]: unable to GetHashTypeOfRepo: %v", m.Repo, err) + } notify_service.SyncPushCommits(ctx, m.Repo.MustOwner(ctx), m.Repo, &repo_module.PushUpdateOptions{ RefFullName: result.refName, - OldCommitID: git.EmptySHA, + OldCommitID: objectFormat.EmptyObjectID().String(), NewCommitID: commitID, }, repo_module.NewPushCommits()) notify_service.SyncCreateRef(ctx, m.Repo.MustOwner(ctx), m.Repo, result.refName, commitID) Index: gitea-1.21.11/services/packages/cargo/index.go =================================================================== --- gitea-1.21.11.orig/services/packages/cargo/index.go +++ gitea-1.21.11/services/packages/cargo/index.go @@ -271,7 +271,7 @@ func alterRepositoryContent(ctx context. if !git.IsErrBranchNotExist(err) || !repo.IsEmpty { return err } - if err := t.Init(); err != nil { + if err := t.Init(repo.ObjectFormatName); err != nil { return err } } else { Index: gitea-1.21.11/services/pull/check.go =================================================================== --- gitea-1.21.11.orig/services/pull/check.go +++ gitea-1.21.11/services/pull/check.go @@ -215,24 +215,29 @@ func getMergeCommit(ctx context.Context, return nil, fmt.Errorf("GetFullCommitID(%s) in %s: %w", prHeadRef, pr.BaseRepo.FullName(), err) } + gitRepo, err := git.OpenRepository(ctx, pr.BaseRepo.RepoPath()) + if err != nil { + return nil, fmt.Errorf("%-v OpenRepository: %w", pr.BaseRepo, err) + } + defer gitRepo.Close() + + objectFormat, err := gitRepo.GetObjectFormat() + if err != nil { + return nil, fmt.Errorf("%-v GetObjectFormat: %w", pr.BaseRepo, err) + } + // Get the commit from BaseBranch where the pull request got merged mergeCommit, _, err := git.NewCommand(ctx, "rev-list", "--ancestry-path", "--merges", "--reverse"). AddDynamicArguments(prHeadCommitID + ".." + pr.BaseBranch). RunStdString(&git.RunOpts{Dir: pr.BaseRepo.RepoPath()}) if err != nil { return nil, fmt.Errorf("git rev-list --ancestry-path --merges --reverse: %w", err) - } else if len(mergeCommit) < git.SHAFullLength { + } else if len(mergeCommit) < objectFormat.FullLength() { // PR was maybe fast-forwarded, so just use last commit of PR mergeCommit = prHeadCommitID } mergeCommit = strings.TrimSpace(mergeCommit) - gitRepo, err := git.OpenRepository(ctx, pr.BaseRepo.RepoPath()) - if err != nil { - return nil, fmt.Errorf("%-v OpenRepository: %w", pr.BaseRepo, err) - } - defer gitRepo.Close() - commit, err := gitRepo.GetCommit(mergeCommit) if err != nil { return nil, fmt.Errorf("GetMergeCommit[%s]: %w", mergeCommit, err) Index: gitea-1.21.11/services/pull/merge.go =================================================================== --- gitea-1.21.11.orig/services/pull/merge.go +++ gitea-1.21.11/services/pull/merge.go @@ -486,7 +486,8 @@ func MergedManually(pr *issues_model.Pul return models.ErrInvalidMergeStyle{ID: pr.BaseRepo.ID, Style: repo_model.MergeStyleManuallyMerged} } - if len(commitID) < git.SHAFullLength { + objectFormat, _ := baseGitRepo.GetObjectFormat() + if len(commitID) != objectFormat.FullLength() { return fmt.Errorf("Wrong commit ID") } Index: gitea-1.21.11/services/pull/patch.go =================================================================== --- gitea-1.21.11.orig/services/pull/patch.go +++ gitea-1.21.11/services/pull/patch.go @@ -129,6 +129,7 @@ func (e *errMergeConflict) Error() strin func attemptMerge(ctx context.Context, file *unmergedFile, tmpBasePath string, gitRepo *git.Repository) error { log.Trace("Attempt to merge:\n%v", file) + switch { case file.stage1 != nil && (file.stage2 == nil || file.stage3 == nil): // 1. Deleted in one or both: Index: gitea-1.21.11/services/pull/pull.go =================================================================== --- gitea-1.21.11.orig/services/pull/pull.go +++ gitea-1.21.11/services/pull/pull.go @@ -333,7 +333,8 @@ func AddTestPullRequestTask(doer *user_m } if err == nil { for _, pr := range prs { - if newCommitID != "" && newCommitID != git.EmptySHA { + objectFormat, _ := git.GetObjectFormatOfRepo(ctx, pr.BaseRepo.RepoPath()) + if newCommitID != "" && newCommitID != objectFormat.EmptyObjectID().String() { changed, err := checkIfPRContentChanged(ctx, pr, oldCommitID, newCommitID) if err != nil { log.Error("checkIfPRContentChanged: %v", err) Index: gitea-1.21.11/services/pull/temp_repo.go =================================================================== --- gitea-1.21.11.orig/services/pull/temp_repo.go +++ gitea-1.21.11/services/pull/temp_repo.go @@ -94,7 +94,7 @@ func createTemporaryRepoForPR(ctx contex baseRepoPath := pr.BaseRepo.RepoPath() headRepoPath := pr.HeadRepo.RepoPath() - if err := git.InitRepository(ctx, tmpBasePath, false); err != nil { + if err := git.InitRepository(ctx, tmpBasePath, false, pr.BaseRepo.ObjectFormatName); err != nil { log.Error("Unable to init tmpBasePath for %-v: %v", pr, err) cancel() return nil, nil, err @@ -168,11 +168,12 @@ func createTemporaryRepoForPR(ctx contex } trackingBranch := "tracking" + objectFormat := git.ObjectFormatFromName(pr.BaseRepo.ObjectFormatName) // Fetch head branch var headBranch string if pr.Flow == issues_model.PullRequestFlowGithub { headBranch = git.BranchPrefix + pr.HeadBranch - } else if len(pr.HeadCommitID) == git.SHAFullLength { // for not created pull request + } else if len(pr.HeadCommitID) == objectFormat.FullLength() { // for not created pull request headBranch = pr.HeadCommitID } else { headBranch = pr.GetGitRefName() Index: gitea-1.21.11/services/release/release.go =================================================================== --- gitea-1.21.11.orig/services/release/release.go +++ gitea-1.21.11/services/release/release.go @@ -76,16 +76,17 @@ func createTag(ctx context.Context, gitR created = true rel.LowerTagName = strings.ToLower(rel.TagName) + objectFormat, _ := gitRepo.GetObjectFormat() commits := repository.NewPushCommits() commits.HeadCommit = repository.CommitToPushCommit(commit) - commits.CompareURL = rel.Repo.ComposeCompareURL(git.EmptySHA, commit.ID.String()) + commits.CompareURL = rel.Repo.ComposeCompareURL(objectFormat.EmptyObjectID().String(), commit.ID.String()) refFullName := git.RefNameFromTag(rel.TagName) notify_service.PushCommits( ctx, rel.Publisher, rel.Repo, &repository.PushUpdateOptions{ RefFullName: refFullName, - OldCommitID: git.EmptySHA, + OldCommitID: objectFormat.EmptyObjectID().String(), NewCommitID: commit.ID.String(), }, commits) notify_service.CreateRef(ctx, rel.Publisher, rel.Repo, refFullName, commit.ID.String()) @@ -313,12 +314,16 @@ func DeleteReleaseByID(ctx context.Conte } refName := git.RefNameFromTag(rel.TagName) + objectFormat, err := git.GetObjectFormatOfRepo(ctx, repo.RepoPath()) + if err != nil { + return err + } notify_service.PushCommits( ctx, doer, repo, &repository.PushUpdateOptions{ RefFullName: refName, OldCommitID: rel.Sha1, - NewCommitID: git.EmptySHA, + NewCommitID: objectFormat.EmptyObjectID().String(), }, repository.NewPushCommits()) notify_service.DeleteRef(ctx, doer, repo, refName) Index: gitea-1.21.11/services/repository/archiver/archiver.go =================================================================== --- gitea-1.21.11.orig/services/repository/archiver/archiver.go +++ gitea-1.21.11/services/repository/archiver/archiver.go @@ -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. 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 } Index: gitea-1.21.11/services/repository/branch.go =================================================================== --- gitea-1.21.11.orig/services/repository/branch.go +++ gitea-1.21.11/services/repository/branch.go @@ -380,6 +380,11 @@ func DeleteBranch(ctx context.Context, d return fmt.Errorf("GetBranch: %vc", err) } + objectFormat, err := gitRepo.GetObjectFormat() + if err != nil { + return err + } + if rawBranch.IsDeleted { return nil } @@ -406,7 +411,7 @@ func DeleteBranch(ctx context.Context, d &repo_module.PushUpdateOptions{ RefFullName: git.RefNameFromBranch(branchName), OldCommitID: commit.ID.String(), - NewCommitID: git.EmptySHA, + NewCommitID: objectFormat.EmptyObjectID().String(), PusherID: doer.ID, PusherName: doer.Name, RepoUserName: repo.OwnerName, Index: gitea-1.21.11/services/repository/check.go =================================================================== --- gitea-1.21.11.orig/services/repository/check.go +++ gitea-1.21.11/services/repository/check.go @@ -192,7 +192,7 @@ func ReinitMissingRepositories(ctx conte 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.ObjectFormatName); 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) Index: gitea-1.21.11/services/repository/create.go =================================================================== --- gitea-1.21.11.orig/services/repository/create.go +++ gitea-1.21.11/services/repository/create.go @@ -27,22 +27,23 @@ import ( // CreateRepoOptions contains the create repository options type CreateRepoOptions struct { - Name string - Description string - OriginalURL string - GitServiceType api.GitServiceType - Gitignores string - IssueLabels string - License string - Readme string - DefaultBranch string - IsPrivate bool - IsMirror bool - IsTemplate bool - AutoInit bool - Status repo_model.RepositoryStatus - TrustModel repo_model.TrustModelType - MirrorInterval string + Name string + Description string + OriginalURL string + GitServiceType api.GitServiceType + Gitignores string + IssueLabels string + License string + Readme string + DefaultBranch string + IsPrivate bool + IsMirror bool + IsTemplate bool + AutoInit bool + Status repo_model.RepositoryStatus + TrustModel repo_model.TrustModelType + MirrorInterval string + ObjectFormatName string } func prepareRepoCommit(ctx context.Context, repo *repo_model.Repository, tmpDir, repoPath string, opts CreateRepoOptions) error { @@ -134,7 +135,7 @@ func prepareRepoCommit(ctx context.Conte // 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.ObjectFormatName); err != nil { return err } @@ -216,6 +217,10 @@ func CreateRepositoryDirectly(ctx contex } } + if opts.ObjectFormatName == "" { + opts.ObjectFormatName = git.Sha1ObjectFormat.Name() + } + repo := &repo_model.Repository{ OwnerID: u.ID, Owner: u, @@ -234,6 +239,7 @@ func CreateRepositoryDirectly(ctx contex TrustModel: opts.TrustModel, IsMirror: opts.IsMirror, DefaultBranch: opts.DefaultBranch, + ObjectFormatName: opts.ObjectFormatName, } var rollbackRepo *repo_model.Repository Index: gitea-1.21.11/services/repository/files/cherry_pick.go =================================================================== --- gitea-1.21.11.orig/services/repository/files/cherry_pick.go +++ gitea-1.21.11/services/repository/files/cherry_pick.go @@ -51,7 +51,7 @@ func CherryPick(ctx context.Context, rep 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) } @@ -70,7 +70,7 @@ func CherryPick(ctx context.Context, rep } parent, err := commit.ParentID(0) if err != nil { - parent = git.MustIDFromString(git.EmptyTreeSHA) + parent = git.ObjectFormatFromName(repo.ObjectFormatName).EmptyTree() } base, right := parent.String(), commit.ID.String() Index: gitea-1.21.11/services/repository/files/patch.go =================================================================== --- gitea-1.21.11.orig/services/repository/files/patch.go +++ gitea-1.21.11/services/repository/files/patch.go @@ -125,7 +125,7 @@ func ApplyDiffPatch(ctx context.Context, 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) } Index: gitea-1.21.11/services/repository/files/temp_repo.go =================================================================== --- gitea-1.21.11.orig/services/repository/files/temp_repo.go +++ gitea-1.21.11/services/repository/files/temp_repo.go @@ -83,8 +83,8 @@ func (t *TemporaryUploadRepository) Clon } // Init the repository -func (t *TemporaryUploadRepository) Init() error { - if err := git.InitRepository(t.ctx, t.basePath, false); err != nil { +func (t *TemporaryUploadRepository) Init(objectFormatName string) error { + if err := git.InitRepository(t.ctx, t.basePath, false, objectFormatName); err != nil { return err } gitRepo, err := git.OpenRepository(t.ctx, t.basePath) Index: gitea-1.21.11/services/repository/files/tree.go =================================================================== --- gitea-1.21.11.orig/services/repository/files/tree.go +++ gitea-1.21.11/services/repository/files/tree.go @@ -37,19 +37,21 @@ func GetTreeBySHA(ctx context.Context, r } 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 Index: gitea-1.21.11/services/repository/files/update.go =================================================================== --- gitea-1.21.11.orig/services/repository/files/update.go +++ gitea-1.21.11/services/repository/files/update.go @@ -150,7 +150,7 @@ func ChangeRepoFiles(ctx context.Context if !git.IsErrBranchNotExist(err) || !repo.IsEmpty { return nil, err } - if err := t.Init(); err != nil { + if err := t.Init(repo.ObjectFormatName); err != nil { return nil, err } hasOldBranch = false @@ -197,7 +197,7 @@ func ChangeRepoFiles(ctx context.Context 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) } Index: gitea-1.21.11/services/repository/files/upload.go =================================================================== --- gitea-1.21.11.orig/services/repository/files/upload.go +++ gitea-1.21.11/services/repository/files/upload.go @@ -91,7 +91,7 @@ func UploadRepoFiles(ctx context.Context if !git.IsErrBranchNotExist(err) || !repo.IsEmpty { return err } - if err = t.Init(); err != nil { + if err = t.Init(repo.ObjectFormatName); err != nil { return err } hasOldBranch = false Index: gitea-1.21.11/services/repository/lfs.go =================================================================== --- gitea-1.21.11.orig/services/repository/lfs.go +++ gitea-1.21.11/services/repository/lfs.go @@ -78,13 +78,14 @@ func GarbageCollectLFSMetaObjectsForRepo 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) Index: gitea-1.21.11/services/repository/push.go =================================================================== --- gitea-1.21.11.orig/services/repository/push.go +++ gitea-1.21.11/services/repository/push.go @@ -63,7 +63,7 @@ func PushUpdates(opts []*repo_module.Pus 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") } } @@ -92,6 +92,11 @@ func pushUpdates(optsList []*repo_module } 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) } @@ -104,7 +109,7 @@ func pushUpdates(optsList []*repo_module 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.EmptyObjectID()) } if opts.RefFullName.IsTag() { if pusher == nil || pusher.ID != opts.PusherID { @@ -124,7 +129,7 @@ func pushUpdates(optsList []*repo_module &repo_module.PushUpdateOptions{ RefFullName: git.RefNameFromTag(tagName), OldCommitID: opts.OldCommitID, - NewCommitID: git.EmptySHA, + NewCommitID: objectFormat.EmptyObjectID().String(), }, repo_module.NewPushCommits()) delTags = append(delTags, tagName) @@ -137,13 +142,13 @@ func pushUpdates(optsList []*repo_module commits := repo_module.NewPushCommits() commits.HeadCommit = repo_module.CommitToPushCommit(newCommit) - commits.CompareURL = repo.ComposeCompareURL(git.EmptySHA, opts.NewCommitID) + commits.CompareURL = repo.ComposeCompareURL(objectFormat.EmptyObjectID().String(), opts.NewCommitID) notify_service.PushCommits( ctx, pusher, repo, &repo_module.PushUpdateOptions{ RefFullName: opts.RefFullName, - OldCommitID: git.EmptySHA, + OldCommitID: objectFormat.EmptyObjectID().String(), NewCommitID: opts.NewCommitID, }, commits) @@ -227,7 +232,7 @@ func pushUpdates(optsList []*repo_module } oldCommitID := opts.OldCommitID - if oldCommitID == git.EmptySHA && len(commits.Commits) > 0 { + if oldCommitID == objectFormat.EmptyObjectID().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) @@ -243,11 +248,11 @@ func pushUpdates(optsList []*repo_module } } - if oldCommitID == git.EmptySHA && repo.DefaultBranch != branch { + if oldCommitID == objectFormat.EmptyObjectID().String() && repo.DefaultBranch != branch { oldCommitID = repo.DefaultBranch } - if oldCommitID != git.EmptySHA { + if oldCommitID != objectFormat.EmptyObjectID().String() { commits.CompareURL = repo.ComposeCompareURL(oldCommitID, opts.NewCommitID) } else { commits.CompareURL = "" Index: gitea-1.21.11/services/webhook/slack.go =================================================================== --- gitea-1.21.11.orig/services/webhook/slack.go +++ gitea-1.21.11/services/webhook/slack.go @@ -92,6 +92,7 @@ func SlackLinkFormatter(url, text string // SlackLinkToRef slack-formatter link to a repo ref func SlackLinkToRef(repoURL, ref string) string { + // FIXME: SHA1 hardcoded here url := git.RefURL(repoURL, ref) refName := git.RefName(ref).ShortName() return SlackLinkFormatter(url, refName) Index: gitea-1.21.11/services/wiki/wiki.go =================================================================== --- gitea-1.21.11.orig/services/wiki/wiki.go +++ gitea-1.21.11/services/wiki/wiki.go @@ -37,7 +37,7 @@ func InitWiki(ctx context.Context, repo return nil } - if err := git.InitRepository(ctx, repo.WikiPath(), true); err != nil { + if err := git.InitRepository(ctx, repo.WikiPath(), true, repo.ObjectFormatName); err != nil { return fmt.Errorf("InitRepository: %w", err) } else if err = repo_module.CreateDelegateHooks(repo.WikiPath()); err != nil { return fmt.Errorf("createDelegateHooks: %w", err) Index: gitea-1.21.11/services/wiki/wiki_test.go =================================================================== --- gitea-1.21.11.orig/services/wiki/wiki_test.go +++ gitea-1.21.11/services/wiki/wiki_test.go @@ -305,7 +305,7 @@ func TestPrepareWikiFileName_FirstPage(t // Now create a temporaryDirectory tmpDir := t.TempDir() - err := git.InitRepository(git.DefaultContext, tmpDir, true) + err := git.InitRepository(git.DefaultContext, tmpDir, true, git.Sha1ObjectFormat.Name()) assert.NoError(t, err) gitRepo, err := git.OpenRepository(git.DefaultContext, tmpDir) Index: gitea-1.21.11/tests/integration/git_helper_for_declarative_test.go =================================================================== --- gitea-1.21.11.orig/tests/integration/git_helper_for_declarative_test.go +++ gitea-1.21.11/tests/integration/git_helper_for_declarative_test.go @@ -120,7 +120,7 @@ func doGitCloneFail(u *url.URL) func(*te func doGitInitTestRepository(dstPath string) func(*testing.T) { return func(t *testing.T) { // Init repository in dstPath - assert.NoError(t, git.InitRepository(git.DefaultContext, dstPath, false)) + assert.NoError(t, git.InitRepository(git.DefaultContext, dstPath, false, git.Sha1ObjectFormat.Name())) // forcibly set default branch to master _, _, err := git.NewCommand(git.DefaultContext, "symbolic-ref", "HEAD", git.BranchPrefix+"master").RunStdString(&git.RunOpts{Dir: dstPath}) assert.NoError(t, err) Index: gitea-1.21.11/modules/git/git.go =================================================================== --- gitea-1.21.11.orig/modules/git/git.go +++ gitea-1.21.11/modules/git/git.go @@ -33,8 +33,8 @@ var ( // DefaultContext is the default context to run git commands in, must be initialized by git.InitXxx DefaultContext context.Context - // SupportProcReceive version >= 2.29.0 - SupportProcReceive bool + SupportProcReceive bool // >= 2.29 + SupportHashSha256 bool // >= 2.42, SHA-256 repositories no longer an ‘experimental curiosity’ gitVersion *version.Version ) @@ -188,6 +188,12 @@ func InitFull(ctx context.Context) (err globalCommandArgs = append(globalCommandArgs, "-c", "credential.helper=") } SupportProcReceive = CheckGitVersionAtLeast("2.29") == nil + SupportHashSha256 = CheckGitVersionAtLeast("2.42") == nil && !isGogit + if SupportHashSha256 { + SupportedObjectFormats = append(SupportedObjectFormats, Sha256ObjectFormat) + } else { + log.Warn("sha256 hash support is disabled - requires Git >= 2.42. Gogit is currently unsupported") + } if setting.LFS.StartServer { if CheckGitVersionAtLeast("2.1.2") != nil { Index: gitea-1.21.11/models/issues/comment.go =================================================================== --- gitea-1.21.11.orig/models/issues/comment.go +++ gitea-1.21.11/models/issues/comment.go @@ -263,7 +263,7 @@ type Comment struct { UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` // Reference issue in commit message - CommitSHA string `xorm:"VARCHAR(40)"` + CommitSHA string `xorm:"VARCHAR(64)"` Attachments []*repo_model.Attachment `xorm:"-"` Reactions ReactionList `xorm:"-"` Index: gitea-1.21.11/models/issues/pull.go =================================================================== --- gitea-1.21.11.orig/models/issues/pull.go +++ gitea-1.21.11/models/issues/pull.go @@ -189,11 +189,11 @@ type PullRequest struct { HeadBranch string HeadCommitID string `xorm:"-"` BaseBranch string - MergeBase string `xorm:"VARCHAR(40)"` + MergeBase string `xorm:"VARCHAR(64)"` AllowMaintainerEdit bool `xorm:"NOT NULL DEFAULT false"` HasMerged bool `xorm:"INDEX"` - MergedCommitID string `xorm:"VARCHAR(40)"` + MergedCommitID string `xorm:"VARCHAR(64)"` MergerID int64 `xorm:"INDEX"` Merger *user_model.User `xorm:"-"` MergedUnix timeutil.TimeStamp `xorm:"updated INDEX"` Index: gitea-1.21.11/models/issues/review.go =================================================================== --- gitea-1.21.11.orig/models/issues/review.go +++ gitea-1.21.11/models/issues/review.go @@ -116,7 +116,7 @@ type Review struct { Content string `xorm:"TEXT"` // Official is a review made by an assigned approver (counts towards approval) Official bool `xorm:"NOT NULL DEFAULT false"` - CommitID string `xorm:"VARCHAR(40)"` + CommitID string `xorm:"VARCHAR(64)"` Stale bool `xorm:"NOT NULL DEFAULT false"` Dismissed bool `xorm:"NOT NULL DEFAULT false"` Index: gitea-1.21.11/models/migrations/fixtures/Test_RepositoryFormat/repository.yml =================================================================== --- /dev/null +++ gitea-1.21.11/models/migrations/fixtures/Test_RepositoryFormat/repository.yml @@ -0,0 +1,11 @@ +# type Repository struct { +# ID int64 `xorm:"pk autoincr"` +# } +- + id: 1 +- + id: 2 +- + id: 3 +- + id: 10 Index: gitea-1.21.11/models/migrations/v1_22/tests/integration/gitea-integration-sqlite/data/home/.gitconfig =================================================================== --- /dev/null +++ gitea-1.21.11/models/migrations/v1_22/tests/integration/gitea-integration-sqlite/data/home/.gitconfig @@ -0,0 +1,22 @@ +[diff] + algorithm = histogram +[core] + logallrefupdates = true + quotePath = false + commitGraph = true +[gc] + reflogexpire = 90 + writeCommitGraph = true +[user] + name = Gitea + email = gitea@fake.local +[receive] + advertisePushOptions = true + procReceiveRefs = refs/for +[fetch] + writeCommitGraph = true +[safe] + directory = * +[uploadpack] + allowfilter = true + allowAnySHA1InWant = true Index: gitea-1.21.11/models/migrations/v1_22/v286.go =================================================================== --- /dev/null +++ gitea-1.21.11/models/migrations/v1_22/v286.go @@ -0,0 +1,104 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT +package v1_22 //nolint + +import ( + "errors" + "fmt" + + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + + "xorm.io/xorm" +) + +func expandHashReferencesToSha256(x *xorm.Engine) error { + alteredTables := [][2]string{ + {"commit_status", "context_hash"}, + {"comment", "commit_sha"}, + {"pull_request", "merge_base"}, + {"pull_request", "merged_commit_id"}, + {"review", "commit_id"}, + {"review_state", "commit_sha"}, + {"repo_archiver", "commit_id"}, + {"release", "sha1"}, + {"repo_indexer_status", "commit_sha"}, + } + + db := x.NewSession() + defer db.Close() + + if err := db.Begin(); err != nil { + return err + } + + if !setting.Database.Type.IsSQLite3() { + if setting.Database.Type.IsMSSQL() { + // drop indexes that need to be re-created afterwards + droppedIndexes := []string{ + "DROP INDEX commit_status.IDX_commit_status_context_hash", + "DROP INDEX review_state.UQE_review_state_pull_commit_user", + "DROP INDEX repo_archiver.UQE_repo_archiver_s", + } + for _, s := range droppedIndexes { + _, err := db.Exec(s) + if err != nil { + return errors.New(s + " " + err.Error()) + } + } + } + + for _, alts := range alteredTables { + var err error + if setting.Database.Type.IsMySQL() { + _, err = db.Exec(fmt.Sprintf("ALTER TABLE `%s` MODIFY COLUMN `%s` VARCHAR(64)", alts[0], alts[1])) + } else if setting.Database.Type.IsMSSQL() { + _, err = db.Exec(fmt.Sprintf("ALTER TABLE `%s` ALTER COLUMN `%s` VARCHAR(64)", alts[0], alts[1])) + } else { + _, err = db.Exec(fmt.Sprintf("ALTER TABLE `%s` ALTER COLUMN `%s` TYPE VARCHAR(64)", alts[0], alts[1])) + } + if err != nil { + return fmt.Errorf("alter column '%s' of table '%s' failed: %w", alts[1], alts[0], err) + } + } + + if setting.Database.Type.IsMSSQL() { + recreateIndexes := []string{ + "CREATE INDEX IDX_commit_status_context_hash ON commit_status(context_hash)", + "CREATE UNIQUE INDEX UQE_review_state_pull_commit_user ON review_state(user_id, pull_id, commit_sha)", + "CREATE UNIQUE INDEX UQE_repo_archiver_s ON repo_archiver(repo_id, type, commit_id)", + } + for _, s := range recreateIndexes { + _, err := db.Exec(s) + if err != nil { + return errors.New(s + " " + err.Error()) + } + } + } + } + log.Debug("Updated database tables to hold SHA256 git hash references") + + return db.Commit() +} + +func addObjectFormatNameToRepository(x *xorm.Engine) error { + type Repository struct { + ObjectFormatName string `xorm:"VARCHAR(6) NOT NULL DEFAULT 'sha1'"` + } + + if err := x.Sync(new(Repository)); err != nil { + return err + } + + // Here to catch weird edge-cases where column constraints above are + // not applied by the DB backend + _, err := x.Exec("UPDATE repository set object_format_name = 'sha1' WHERE object_format_name = '' or object_format_name IS NULL") + return err +} + +func AdjustDBForSha256(x *xorm.Engine) error { + if err := expandHashReferencesToSha256(x); err != nil { + return err + } + return addObjectFormatNameToRepository(x) +} Index: gitea-1.21.11/models/migrations/v1_22/v286_test.go =================================================================== --- /dev/null +++ gitea-1.21.11/models/migrations/v1_22/v286_test.go @@ -0,0 +1,62 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_22 //nolint + +import ( + "testing" + + "code.gitea.io/gitea/models/migrations/base" + + "github.com/stretchr/testify/assert" + "xorm.io/xorm" +) + +func PrepareOldRepository(t *testing.T) (*xorm.Engine, func()) { + type Repository struct { // old struct + ID int64 `xorm:"pk autoincr"` + } + + // Prepare and load the testing database + return base.PrepareTestEnv(t, 0, new(Repository)) +} + +func Test_RepositoryFormat(t *testing.T) { + x, deferable := PrepareOldRepository(t) + defer deferable() + + type Repository struct { + ID int64 `xorm:"pk autoincr"` + ObjectFormatName string `xorg:"not null default('sha1')"` + } + + repo := new(Repository) + + // check we have some records to migrate + count, err := x.Count(new(Repository)) + assert.NoError(t, err) + assert.EqualValues(t, 4, count) + + assert.NoError(t, AdjustDBForSha256(x)) + + repo.ID = 20 + repo.ObjectFormatName = "sha256" + _, err = x.Insert(repo) + assert.NoError(t, err) + + count, err = x.Count(new(Repository)) + assert.NoError(t, err) + assert.EqualValues(t, 5, count) + + repo = new(Repository) + ok, err := x.ID(2).Get(repo) + assert.NoError(t, err) + assert.EqualValues(t, true, ok) + assert.EqualValues(t, "sha1", repo.ObjectFormatName) + + repo = new(Repository) + ok, err = x.ID(20).Get(repo) + assert.NoError(t, err) + assert.EqualValues(t, true, ok) + assert.EqualValues(t, "sha256", repo.ObjectFormatName) +} Index: gitea-1.21.11/models/pull/review_state.go =================================================================== --- gitea-1.21.11.orig/models/pull/review_state.go +++ gitea-1.21.11/models/pull/review_state.go @@ -39,7 +39,7 @@ type ReviewState struct { ID int64 `xorm:"pk autoincr"` UserID int64 `xorm:"NOT NULL UNIQUE(pull_commit_user)"` PullID int64 `xorm:"NOT NULL INDEX UNIQUE(pull_commit_user) DEFAULT 0"` // Which PR was the review on? - CommitSHA string `xorm:"NOT NULL VARCHAR(40) UNIQUE(pull_commit_user)"` // Which commit was the head commit for the review? + CommitSHA string `xorm:"NOT NULL VARCHAR(64) UNIQUE(pull_commit_user)"` // Which commit was the head commit for the review? UpdatedFiles map[string]ViewedState `xorm:"NOT NULL LONGTEXT JSON"` // Stores for each of the changed files of a PR whether they have been viewed, changed since last viewed, or not viewed UpdatedUnix timeutil.TimeStamp `xorm:"updated"` // Is an accurate indicator of the order of commits as we do not expect it to be possible to make reviews on previous commits } Index: gitea-1.21.11/models/repo/archiver.go =================================================================== --- gitea-1.21.11.orig/models/repo/archiver.go +++ gitea-1.21.11/models/repo/archiver.go @@ -33,7 +33,7 @@ type RepoArchiver struct { //revive:disa RepoID int64 `xorm:"index unique(s)"` Type git.ArchiveType `xorm:"unique(s)"` Status ArchiverStatus - CommitID string `xorm:"VARCHAR(40) unique(s)"` + CommitID string `xorm:"VARCHAR(64) unique(s)"` CreatedUnix timeutil.TimeStamp `xorm:"INDEX NOT NULL created"` } Index: gitea-1.21.11/models/repo/release.go =================================================================== --- gitea-1.21.11.orig/models/repo/release.go +++ gitea-1.21.11/models/repo/release.go @@ -75,7 +75,7 @@ type Release struct { Target string TargetBehind string `xorm:"-"` // to handle non-existing or empty target Title string - Sha1 string `xorm:"VARCHAR(40)"` + Sha1 string `xorm:"VARCHAR(64)"` NumCommits int64 NumCommitsBehind int64 `xorm:"-"` Note string `xorm:"TEXT"` Index: gitea-1.21.11/models/repo/repo_indexer.go =================================================================== --- gitea-1.21.11.orig/models/repo/repo_indexer.go +++ gitea-1.21.11/models/repo/repo_indexer.go @@ -27,7 +27,7 @@ const ( type RepoIndexerStatus struct { //revive:disable-line:exported ID int64 `xorm:"pk autoincr"` RepoID int64 `xorm:"INDEX(s)"` - CommitSha string `xorm:"VARCHAR(40)"` + CommitSha string `xorm:"VARCHAR(64)"` IndexerType RepoIndexerType `xorm:"INDEX(s) NOT NULL DEFAULT 0"` } Index: gitea-1.21.11/modules/git/blame_sha256_test.go =================================================================== --- /dev/null +++ gitea-1.21.11/modules/git/blame_sha256_test.go @@ -0,0 +1,144 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package git + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestReadingBlameOutputSha256(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + t.Run("Without .git-blame-ignore-revs", func(t *testing.T) { + repo, err := OpenRepository(ctx, "./tests/repos/repo5_pulls_sha256") + assert.NoError(t, err) + defer repo.Close() + + commit, err := repo.GetCommit("0b69b7bb649b5d46e14cabb6468685e5dd721290acc7ffe604d37cde57927345") + assert.NoError(t, err) + + parts := []*BlamePart{ + { + Sha: "1e35a51dc00fd7de730344c07061acfe80e8117e075ac979b6a29a3a045190ca", + Lines: []string{ + "# test_repo", + "Test repository for testing migration from github to gitea", + }, + }, + { + Sha: "0b69b7bb649b5d46e14cabb6468685e5dd721290acc7ffe604d37cde57927345", + Lines: []string{"", "Do not make any changes to this repo it is used for unit testing"}, + PreviousSha: "1e35a51dc00fd7de730344c07061acfe80e8117e075ac979b6a29a3a045190ca", + PreviousPath: "README.md", + }, + } + + for _, bypass := range []bool{false, true} { + blameReader, err := CreateBlameReader(ctx, Sha256ObjectFormat, "./tests/repos/repo5_pulls_sha256", commit, "README.md", bypass) + assert.NoError(t, err) + assert.NotNil(t, blameReader) + defer blameReader.Close() + + assert.False(t, blameReader.UsesIgnoreRevs()) + + for _, part := range parts { + actualPart, err := blameReader.NextPart() + assert.NoError(t, err) + assert.Equal(t, part, actualPart) + } + + // make sure all parts have been read + actualPart, err := blameReader.NextPart() + assert.Nil(t, actualPart) + assert.NoError(t, err) + } + }) + + t.Run("With .git-blame-ignore-revs", func(t *testing.T) { + repo, err := OpenRepository(ctx, "./tests/repos/repo6_blame_sha256") + assert.NoError(t, err) + defer repo.Close() + + full := []*BlamePart{ + { + Sha: "ab2b57a4fa476fb2edb74dafa577caf918561abbaa8fba0c8dc63c412e17a7cc", + Lines: []string{"line", "line"}, + }, + { + Sha: "9347b0198cd1f25017579b79d0938fa89dba34ad2514f0dd92f6bc975ed1a2fe", + Lines: []string{"changed line"}, + PreviousSha: "ab2b57a4fa476fb2edb74dafa577caf918561abbaa8fba0c8dc63c412e17a7cc", + PreviousPath: "blame.txt", + }, + { + Sha: "ab2b57a4fa476fb2edb74dafa577caf918561abbaa8fba0c8dc63c412e17a7cc", + Lines: []string{"line", "line", ""}, + }, + } + + cases := []struct { + CommitID string + UsesIgnoreRevs bool + Bypass bool + Parts []*BlamePart + }{ + { + CommitID: "e2f5660e15159082902960af0ed74fc144921d2b0c80e069361853b3ece29ba3", + UsesIgnoreRevs: true, + Bypass: false, + Parts: []*BlamePart{ + { + Sha: "ab2b57a4fa476fb2edb74dafa577caf918561abbaa8fba0c8dc63c412e17a7cc", + Lines: []string{"line", "line", "changed line", "line", "line", ""}, + }, + }, + }, + { + CommitID: "e2f5660e15159082902960af0ed74fc144921d2b0c80e069361853b3ece29ba3", + UsesIgnoreRevs: false, + Bypass: true, + Parts: full, + }, + { + CommitID: "9347b0198cd1f25017579b79d0938fa89dba34ad2514f0dd92f6bc975ed1a2fe", + UsesIgnoreRevs: false, + Bypass: false, + Parts: full, + }, + { + CommitID: "9347b0198cd1f25017579b79d0938fa89dba34ad2514f0dd92f6bc975ed1a2fe", + UsesIgnoreRevs: false, + Bypass: false, + Parts: full, + }, + } + + for _, c := range cases { + commit, err := repo.GetCommit(c.CommitID) + assert.NoError(t, err) + + 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() + + assert.Equal(t, c.UsesIgnoreRevs, blameReader.UsesIgnoreRevs()) + + for _, part := range c.Parts { + actualPart, err := blameReader.NextPart() + assert.NoError(t, err) + assert.Equal(t, part, actualPart) + } + + // make sure all parts have been read + actualPart, err := blameReader.NextPart() + assert.Nil(t, actualPart) + assert.NoError(t, err) + } + }) +} Index: gitea-1.21.11/modules/git/commit_sha256_test.go =================================================================== --- /dev/null +++ gitea-1.21.11/modules/git/commit_sha256_test.go @@ -0,0 +1,195 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +//go:build !gogit + +package git + +import ( + "path/filepath" + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestCommitsCountSha256(t *testing.T) { + bareRepo1Path := filepath.Join(testReposDir, "repo1_bare_sha256") + + commitsCount, err := CommitsCount(DefaultContext, + CommitsCountOptions{ + RepoPath: bareRepo1Path, + Revision: []string{"f004f41359117d319dedd0eaab8c5259ee2263da839dcba33637997458627fdc"}, + }) + + assert.NoError(t, err) + assert.Equal(t, int64(3), commitsCount) +} + +func TestCommitsCountWithoutBaseSha256(t *testing.T) { + bareRepo1Path := filepath.Join(testReposDir, "repo1_bare_sha256") + + commitsCount, err := CommitsCount(DefaultContext, + CommitsCountOptions{ + RepoPath: bareRepo1Path, + Not: "main", + Revision: []string{"branch1"}, + }) + + assert.NoError(t, err) + assert.Equal(t, int64(2), commitsCount) +} + +func TestGetFullCommitIDSha256(t *testing.T) { + bareRepo1Path := filepath.Join(testReposDir, "repo1_bare_sha256") + + id, err := GetFullCommitID(DefaultContext, bareRepo1Path, "f004f4") + assert.NoError(t, err) + assert.Equal(t, "f004f41359117d319dedd0eaab8c5259ee2263da839dcba33637997458627fdc", id) +} + +func TestGetFullCommitIDErrorSha256(t *testing.T) { + bareRepo1Path := filepath.Join(testReposDir, "repo1_bare_sha256") + + id, err := GetFullCommitID(DefaultContext, bareRepo1Path, "unknown") + assert.Empty(t, id) + if assert.Error(t, err) { + assert.EqualError(t, err, "object does not exist [id: unknown, rel_path: ]") + } +} + +func TestCommitFromReaderSha256(t *testing.T) { + commitString := `9433b2a62b964c17a4485ae180f45f595d3e69d31b786087775e28c6b6399df0 commit 1114 +tree e7f9e96dd79c09b078cac8b303a7d3b9d65ff9b734e86060a4d20409fd379f9e +parent 26e9ccc29fad747e9c5d9f4c9ddeb7eff61cc45ef6a8dc258cbeb181afc055e8 +author Adam Majer <amajer@suse.de> 1698676906 +0100 +committer Adam Majer <amajer@suse.de> 1698676906 +0100 +gpgsig-sha256 -----BEGIN PGP SIGNATURE----- +` + " " + ` + iQIrBAABCgAtFiEES+fB08xlgTrzSdQvhkUIsBsmec8FAmU/wKoPHGFtYWplckBz + dXNlLmRlAAoJEIZFCLAbJnnP4s4PQIJATa++WPzR6/H4etT7bsOGoMyguEJYyWOd + aTybplzT7QAL7h2to0QszGabtzMJPIA39xSFZNYNN30voK5YyyYibXluPKgjemfK + WNXwF+gkwgZI38gSvKf+vlqI+EYyIFe19wOhiju0m8SIlB5NEPiWHa17q2mqmqqx + 1FWa2JdqLPYjAtSLFXeSZegrY5V1FxdemyMUONkg8YO9OSIMZiE0GsnnOXQ3xcT4 + JTCnmlUxIKw689UiEY80JopUIq+Wl7+qq9507IYYSUCyB6JazL42AKMzVCbD+qBP + oOzh/hafYgk9H9qCQXaLbmvs17zXRpicig1bAzqgAy1FDelvpERyRTydEajSLIG6 + U1cRCkgXCZ0NfsYNPPmBa8b3+rnstypXYTbyMwTln7FfUAaGo6o9JYiPMkzxlmsy + zfp/tcaY8+LlBL9aOJjtv+a0p+HrpCGd6CCa4ARfphTLq8QRSSh8uzlB9N+6HnRI + VAEUo6ecdDxSpyt2naeg9pKus/BRi7P6g4B1hkk/zZstUX/QP4IQuAJbXjkvsC+X + HKRr3NlRM/DygzTyj0gN74uoa0goCIbyAQhiT42nm0cuhM7uN/W0ayrlZjGF1cbR + 8NCJUL2Nwj0ywKIavC99Ipkb8AsFwpVT6U6effs6 + =xybZ + -----END PGP SIGNATURE----- + +signed commit` + + sha := &Sha256Hash{ + 0x94, 0x33, 0xb2, 0xa6, 0x2b, 0x96, 0x4c, 0x17, 0xa4, 0x48, 0x5a, 0xe1, 0x80, 0xf4, 0x5f, 0x59, + 0x5d, 0x3e, 0x69, 0xd3, 0x1b, 0x78, 0x60, 0x87, 0x77, 0x5e, 0x28, 0xc6, 0xb6, 0x39, 0x9d, 0xf0, + } + gitRepo, err := openRepositoryWithDefaultContext(filepath.Join(testReposDir, "repo1_bare_sha256")) + assert.NoError(t, err) + assert.NotNil(t, gitRepo) + defer gitRepo.Close() + + commitFromReader, err := CommitFromReader(gitRepo, sha, strings.NewReader(commitString)) + assert.NoError(t, err) + if !assert.NotNil(t, commitFromReader) { + return + } + assert.EqualValues(t, sha, commitFromReader.ID) + assert.EqualValues(t, `-----BEGIN PGP SIGNATURE----- + +iQIrBAABCgAtFiEES+fB08xlgTrzSdQvhkUIsBsmec8FAmU/wKoPHGFtYWplckBz +dXNlLmRlAAoJEIZFCLAbJnnP4s4PQIJATa++WPzR6/H4etT7bsOGoMyguEJYyWOd +aTybplzT7QAL7h2to0QszGabtzMJPIA39xSFZNYNN30voK5YyyYibXluPKgjemfK +WNXwF+gkwgZI38gSvKf+vlqI+EYyIFe19wOhiju0m8SIlB5NEPiWHa17q2mqmqqx +1FWa2JdqLPYjAtSLFXeSZegrY5V1FxdemyMUONkg8YO9OSIMZiE0GsnnOXQ3xcT4 +JTCnmlUxIKw689UiEY80JopUIq+Wl7+qq9507IYYSUCyB6JazL42AKMzVCbD+qBP +oOzh/hafYgk9H9qCQXaLbmvs17zXRpicig1bAzqgAy1FDelvpERyRTydEajSLIG6 +U1cRCkgXCZ0NfsYNPPmBa8b3+rnstypXYTbyMwTln7FfUAaGo6o9JYiPMkzxlmsy +zfp/tcaY8+LlBL9aOJjtv+a0p+HrpCGd6CCa4ARfphTLq8QRSSh8uzlB9N+6HnRI +VAEUo6ecdDxSpyt2naeg9pKus/BRi7P6g4B1hkk/zZstUX/QP4IQuAJbXjkvsC+X +HKRr3NlRM/DygzTyj0gN74uoa0goCIbyAQhiT42nm0cuhM7uN/W0ayrlZjGF1cbR +8NCJUL2Nwj0ywKIavC99Ipkb8AsFwpVT6U6effs6 +=xybZ +-----END PGP SIGNATURE----- +`, commitFromReader.Signature.Signature) + assert.EqualValues(t, `tree e7f9e96dd79c09b078cac8b303a7d3b9d65ff9b734e86060a4d20409fd379f9e +parent 26e9ccc29fad747e9c5d9f4c9ddeb7eff61cc45ef6a8dc258cbeb181afc055e8 +author Adam Majer <amajer@suse.de> 1698676906 +0100 +committer Adam Majer <amajer@suse.de> 1698676906 +0100 + +signed commit`, commitFromReader.Signature.Payload) + assert.EqualValues(t, "Adam Majer <amajer@suse.de>", commitFromReader.Author.String()) + + commitFromReader2, err := CommitFromReader(gitRepo, sha, strings.NewReader(commitString+"\n\n")) + assert.NoError(t, err) + commitFromReader.CommitMessage += "\n\n" + commitFromReader.Signature.Payload += "\n\n" + assert.EqualValues(t, commitFromReader, commitFromReader2) +} + +func TestHasPreviousCommitSha256(t *testing.T) { + bareRepo1Path := filepath.Join(testReposDir, "repo1_bare_sha256") + + repo, err := openRepositoryWithDefaultContext(bareRepo1Path) + assert.NoError(t, err) + defer repo.Close() + + commit, err := repo.GetCommit("f004f41359117d319dedd0eaab8c5259ee2263da839dcba33637997458627fdc") + assert.NoError(t, err) + + parentSHA := MustIDFromString("b0ec7af4547047f12d5093e37ef8f1b3b5415ed8ee17894d43a34d7d34212e9c") + notParentSHA := MustIDFromString("42e334efd04cd36eea6da0599913333c26116e1a537ca76e5b6e4af4dda00236") + assert.Equal(t, repo.objectFormat, parentSHA.Type()) + assert.Equal(t, repo.objectFormat.Name(), "sha256") + + haz, err := commit.HasPreviousCommit(parentSHA) + assert.NoError(t, err) + assert.True(t, haz) + + hazNot, err := commit.HasPreviousCommit(notParentSHA) + assert.NoError(t, err) + assert.False(t, hazNot) + + selfNot, err := commit.HasPreviousCommit(commit.ID) + assert.NoError(t, err) + assert.False(t, selfNot) +} + +func TestGetCommitFileStatusMergesSha256(t *testing.T) { + bareRepo1Path := filepath.Join(testReposDir, "repo6_merge_sha256") + + commitFileStatus, err := GetCommitFileStatus(DefaultContext, bareRepo1Path, "d2e5609f630dd8db500f5298d05d16def282412e3e66ed68cc7d0833b29129a1") + assert.NoError(t, err) + + expected := CommitFileStatus{ + []string{ + "add_file.txt", + }, + []string{}, + []string{ + "to_modify.txt", + }, + } + + assert.Equal(t, expected.Added, commitFileStatus.Added) + assert.Equal(t, expected.Removed, commitFileStatus.Removed) + assert.Equal(t, expected.Modified, commitFileStatus.Modified) + + expected = CommitFileStatus{ + []string{}, + []string{ + "to_remove.txt", + }, + []string{}, + } + + commitFileStatus, err = GetCommitFileStatus(DefaultContext, bareRepo1Path, "da1ded40dc8e5b7c564171f4bf2fc8370487decfb1cb6a99ef28f3ed73d09172") + assert.NoError(t, err) + + assert.Equal(t, expected.Added, commitFileStatus.Added) + assert.Equal(t, expected.Removed, commitFileStatus.Removed) + assert.Equal(t, expected.Modified, commitFileStatus.Modified) +} Index: gitea-1.21.11/modules/git/repo_base.go =================================================================== --- gitea-1.21.11.orig/modules/git/repo_base.go +++ gitea-1.21.11/modules/git/repo_base.go @@ -8,6 +8,8 @@ import ( "io" ) +var isGogit bool + // contextKey is a value for use with context.WithValue. type contextKey struct { name string Index: gitea-1.21.11/modules/git/tests/repos/repo1_bare_sha256/HEAD =================================================================== --- /dev/null +++ gitea-1.21.11/modules/git/tests/repos/repo1_bare_sha256/HEAD @@ -0,0 +1 @@ +ref: refs/heads/main Index: gitea-1.21.11/modules/git/tests/repos/repo1_bare_sha256/config =================================================================== --- /dev/null +++ gitea-1.21.11/modules/git/tests/repos/repo1_bare_sha256/config @@ -0,0 +1,6 @@ +[core] + repositoryformatversion = 1 + filemode = true + bare = true +[extensions] + objectformat = sha256 Index: gitea-1.21.11/modules/git/tests/repos/repo1_bare_sha256/description =================================================================== --- /dev/null +++ gitea-1.21.11/modules/git/tests/repos/repo1_bare_sha256/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. Index: gitea-1.21.11/modules/git/tests/repos/repo1_bare_sha256/info/exclude =================================================================== --- /dev/null +++ gitea-1.21.11/modules/git/tests/repos/repo1_bare_sha256/info/exclude @@ -0,0 +1,6 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ Index: gitea-1.21.11/modules/git/tests/repos/repo1_bare_sha256/info/refs =================================================================== --- /dev/null +++ gitea-1.21.11/modules/git/tests/repos/repo1_bare_sha256/info/refs @@ -0,0 +1,7 @@ +42e334efd04cd36eea6da0599913333c26116e1a537ca76e5b6e4af4dda00236 refs/heads/branch1 +5bc2249e32e0ba40a08879fba2bd4e97a13cb345831549f4bc5649525da8f6cc refs/heads/branch2 +9433b2a62b964c17a4485ae180f45f595d3e69d31b786087775e28c6b6399df0 refs/heads/main +29a82d4fc02e19190fb489cc90d5730ed91970b49f4e39acda2798b3dd4f814e refs/tags/signed-tag +9433b2a62b964c17a4485ae180f45f595d3e69d31b786087775e28c6b6399df0 refs/tags/signed-tag^{} +171822a62559f3aa28a00aa3785dbe915d6a8eb02712682740db44fc8bd2187a refs/tags/test +6aae864a3d1d0d6a5be0cc64028c1e7021e2632b031fd8eb82afc5a283d1c3d1 refs/tags/test^{} Index: gitea-1.21.11/modules/git/tests/repos/repo1_bare_sha256/objects/info/packs =================================================================== --- /dev/null +++ gitea-1.21.11/modules/git/tests/repos/repo1_bare_sha256/objects/info/packs @@ -0,0 +1,2 @@ +P pack-c01aa121b9c5e345fe0da2f9be78665970b0c38c6b495d5fc034bc7a7b95334b.pack + Index: gitea-1.21.11/modules/git/tests/repos/repo1_bare_sha256/packed-refs =================================================================== --- /dev/null +++ gitea-1.21.11/modules/git/tests/repos/repo1_bare_sha256/packed-refs @@ -0,0 +1,8 @@ +# pack-refs with: peeled fully-peeled sorted +42e334efd04cd36eea6da0599913333c26116e1a537ca76e5b6e4af4dda00236 refs/heads/branch1 +5bc2249e32e0ba40a08879fba2bd4e97a13cb345831549f4bc5649525da8f6cc refs/heads/branch2 +9433b2a62b964c17a4485ae180f45f595d3e69d31b786087775e28c6b6399df0 refs/heads/main +29a82d4fc02e19190fb489cc90d5730ed91970b49f4e39acda2798b3dd4f814e refs/tags/signed-tag +^9433b2a62b964c17a4485ae180f45f595d3e69d31b786087775e28c6b6399df0 +171822a62559f3aa28a00aa3785dbe915d6a8eb02712682740db44fc8bd2187a refs/tags/test +^6aae864a3d1d0d6a5be0cc64028c1e7021e2632b031fd8eb82afc5a283d1c3d1 Index: gitea-1.21.11/modules/git/tests/repos/repo1_bare_sha256/refs/heads/main =================================================================== --- /dev/null +++ gitea-1.21.11/modules/git/tests/repos/repo1_bare_sha256/refs/heads/main @@ -0,0 +1 @@ +9433b2a62b964c17a4485ae180f45f595d3e69d31b786087775e28c6b6399df0 Index: gitea-1.21.11/modules/git/tests/repos/repo5_pulls_sha256/HEAD =================================================================== --- /dev/null +++ gitea-1.21.11/modules/git/tests/repos/repo5_pulls_sha256/HEAD @@ -0,0 +1 @@ +ref: refs/heads/main Index: gitea-1.21.11/modules/git/tests/repos/repo5_pulls_sha256/config =================================================================== --- /dev/null +++ gitea-1.21.11/modules/git/tests/repos/repo5_pulls_sha256/config @@ -0,0 +1,6 @@ +[core] + repositoryformatversion = 1 + filemode = true + bare = true +[extensions] + objectformat = sha256 Index: gitea-1.21.11/modules/git/tests/repos/repo5_pulls_sha256/description =================================================================== --- /dev/null +++ gitea-1.21.11/modules/git/tests/repos/repo5_pulls_sha256/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. Index: gitea-1.21.11/modules/git/tests/repos/repo5_pulls_sha256/info/refs =================================================================== --- /dev/null +++ gitea-1.21.11/modules/git/tests/repos/repo5_pulls_sha256/info/refs @@ -0,0 +1,4 @@ +35ecd0f946c8baeb76fa5a3876f46bf35218655e2304d8505026fa4bfb496a4b refs/heads/main +35ecd0f946c8baeb76fa5a3876f46bf35218655e2304d8505026fa4bfb496a4b refs/heads/main-clone +7f50a4906503378b0bbb7d61bd2ca8d8d8ff4f7a2474980f99402d742ccc9665 refs/heads/test-patch-1 +1e35a51dc00fd7de730344c07061acfe80e8117e075ac979b6a29a3a045190ca refs/tags/v0.9.99 Index: gitea-1.21.11/modules/git/tests/repos/repo5_pulls_sha256/objects/info/packs =================================================================== --- /dev/null +++ gitea-1.21.11/modules/git/tests/repos/repo5_pulls_sha256/objects/info/packs @@ -0,0 +1,2 @@ +P pack-bfe8f09d42ef5dd1610bf42641fe145d4a02b788eb26c31022a362312660a29d.pack + Index: gitea-1.21.11/modules/git/tests/repos/repo5_pulls_sha256/packed-refs =================================================================== --- /dev/null +++ gitea-1.21.11/modules/git/tests/repos/repo5_pulls_sha256/packed-refs @@ -0,0 +1,5 @@ +# pack-refs with: peeled fully-peeled sorted +35ecd0f946c8baeb76fa5a3876f46bf35218655e2304d8505026fa4bfb496a4b refs/heads/main +35ecd0f946c8baeb76fa5a3876f46bf35218655e2304d8505026fa4bfb496a4b refs/heads/main-clone +7f50a4906503378b0bbb7d61bd2ca8d8d8ff4f7a2474980f99402d742ccc9665 refs/heads/test-patch-1 +1e35a51dc00fd7de730344c07061acfe80e8117e075ac979b6a29a3a045190ca refs/tags/v0.9.99 Index: gitea-1.21.11/modules/git/tests/repos/repo5_pulls_sha256/refs/heads/main =================================================================== --- /dev/null +++ gitea-1.21.11/modules/git/tests/repos/repo5_pulls_sha256/refs/heads/main @@ -0,0 +1 @@ +35ecd0f946c8baeb76fa5a3876f46bf35218655e2304d8505026fa4bfb496a4b Index: gitea-1.21.11/modules/git/tests/repos/repo6_blame_sha256/HEAD =================================================================== --- /dev/null +++ gitea-1.21.11/modules/git/tests/repos/repo6_blame_sha256/HEAD @@ -0,0 +1 @@ +ref: refs/heads/main Index: gitea-1.21.11/modules/git/tests/repos/repo6_blame_sha256/config =================================================================== --- /dev/null +++ gitea-1.21.11/modules/git/tests/repos/repo6_blame_sha256/config @@ -0,0 +1,6 @@ +[core] + repositoryformatversion = 1 + filemode = true + bare = true +[extensions] + objectformat = sha256 Index: gitea-1.21.11/modules/git/tests/repos/repo6_blame_sha256/description =================================================================== --- /dev/null +++ gitea-1.21.11/modules/git/tests/repos/repo6_blame_sha256/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. Index: gitea-1.21.11/modules/git/tests/repos/repo6_blame_sha256/info/exclude =================================================================== --- /dev/null +++ gitea-1.21.11/modules/git/tests/repos/repo6_blame_sha256/info/exclude @@ -0,0 +1,6 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ Index: gitea-1.21.11/modules/git/tests/repos/repo6_blame_sha256/info/refs =================================================================== --- /dev/null +++ gitea-1.21.11/modules/git/tests/repos/repo6_blame_sha256/info/refs @@ -0,0 +1 @@ +e2f5660e15159082902960af0ed74fc144921d2b0c80e069361853b3ece29ba3 refs/heads/main Index: gitea-1.21.11/modules/git/tests/repos/repo6_blame_sha256/objects/info/packs =================================================================== --- /dev/null +++ gitea-1.21.11/modules/git/tests/repos/repo6_blame_sha256/objects/info/packs @@ -0,0 +1,2 @@ +P pack-fcb8a221b76025fd8415d3c562b611ac24312a5ffc3d3703d7c5cc906bdaee8e.pack + Index: gitea-1.21.11/modules/git/tests/repos/repo6_blame_sha256/packed-refs =================================================================== --- /dev/null +++ gitea-1.21.11/modules/git/tests/repos/repo6_blame_sha256/packed-refs @@ -0,0 +1,2 @@ +# pack-refs with: peeled fully-peeled sorted +e2f5660e15159082902960af0ed74fc144921d2b0c80e069361853b3ece29ba3 refs/heads/main Index: gitea-1.21.11/modules/git/tests/repos/repo6_blame_sha256/refs/refs/main =================================================================== --- /dev/null +++ gitea-1.21.11/modules/git/tests/repos/repo6_blame_sha256/refs/refs/main @@ -0,0 +1 @@ +e2f5660e15159082902960af0ed74fc144921d2b0c80e069361853b3ece29ba3 Index: gitea-1.21.11/modules/git/tests/repos/repo6_merge_sha256/HEAD =================================================================== --- /dev/null +++ gitea-1.21.11/modules/git/tests/repos/repo6_merge_sha256/HEAD @@ -0,0 +1 @@ +ref: refs/heads/main Index: gitea-1.21.11/modules/git/tests/repos/repo6_merge_sha256/config =================================================================== --- /dev/null +++ gitea-1.21.11/modules/git/tests/repos/repo6_merge_sha256/config @@ -0,0 +1,6 @@ +[core] + repositoryformatversion = 1 + filemode = true + bare = true +[extensions] + objectformat = sha256 Index: gitea-1.21.11/modules/git/tests/repos/repo6_merge_sha256/description =================================================================== --- /dev/null +++ gitea-1.21.11/modules/git/tests/repos/repo6_merge_sha256/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. Index: gitea-1.21.11/modules/git/tests/repos/repo6_merge_sha256/info/exclude =================================================================== --- /dev/null +++ gitea-1.21.11/modules/git/tests/repos/repo6_merge_sha256/info/exclude @@ -0,0 +1,6 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ Index: gitea-1.21.11/modules/git/tests/repos/repo6_merge_sha256/info/refs =================================================================== --- /dev/null +++ gitea-1.21.11/modules/git/tests/repos/repo6_merge_sha256/info/refs @@ -0,0 +1,4 @@ +d2e5609f630dd8db500f5298d05d16def282412e3e66ed68cc7d0833b29129a1 refs/heads/main +b45258e9823233edea2d40d183742f29630e1e69300479fb4a55eabfe9b1d8bf refs/heads/merge/add_file +ff2b996e2fa366146300e4c9e51ccb6818147b360e46fa1437334f4a690955ce refs/heads/merge/modify_file +da1ded40dc8e5b7c564171f4bf2fc8370487decfb1cb6a99ef28f3ed73d09172 refs/heads/merge/remove_file Index: gitea-1.21.11/modules/git/tests/repos/repo6_merge_sha256/objects/info/packs =================================================================== --- /dev/null +++ gitea-1.21.11/modules/git/tests/repos/repo6_merge_sha256/objects/info/packs @@ -0,0 +1,3 @@ +P pack-2fff0848f8d8eab8f7902ac91ab6a096c7530f577d5c0a79c63d9ac2b44f7510.pack +P pack-65162b86afdbac3c566696d487e67bb2a4a5501ca1fa3528fad8a9474fba7e50.pack + Index: gitea-1.21.11/modules/git/tests/repos/repo6_merge_sha256/packed-refs =================================================================== --- /dev/null +++ gitea-1.21.11/modules/git/tests/repos/repo6_merge_sha256/packed-refs @@ -0,0 +1,5 @@ +# pack-refs with: peeled fully-peeled sorted +d2e5609f630dd8db500f5298d05d16def282412e3e66ed68cc7d0833b29129a1 refs/heads/main +b45258e9823233edea2d40d183742f29630e1e69300479fb4a55eabfe9b1d8bf refs/heads/merge/add_file +ff2b996e2fa366146300e4c9e51ccb6818147b360e46fa1437334f4a690955ce refs/heads/merge/modify_file +da1ded40dc8e5b7c564171f4bf2fc8370487decfb1cb6a99ef28f3ed73d09172 refs/heads/merge/remove_file Index: gitea-1.21.11/modules/git/tests/repos/repo6_merge_sha256/refs/heads/main =================================================================== --- /dev/null +++ gitea-1.21.11/modules/git/tests/repos/repo6_merge_sha256/refs/heads/main @@ -0,0 +1 @@ +d2e5609f630dd8db500f5298d05d16def282412e3e66ed68cc7d0833b29129a1 Index: gitea-1.21.11/modules/markup/html.go =================================================================== --- gitea-1.21.11.orig/modules/markup/html.go +++ gitea-1.21.11/modules/markup/html.go @@ -45,19 +45,19 @@ var ( // valid chars in encoded path and parameter: [-+~_%.a-zA-Z0-9/] - // sha1CurrentPattern matches string that represents a commit SHA, e.g. d8a994ef243349f321568f9e36d5c3f444b99cae - // Although SHA1 hashes are 40 chars long, the regex matches the hash from 7 to 40 chars in length + // hashCurrentPattern matches string that represents a commit SHA, e.g. d8a994ef243349f321568f9e36d5c3f444b99cae + // Although SHA1 hashes are 40 chars long, SHA256 are 64, the regex matches the hash from 7 to 64 chars in length // so that abbreviated hash links can be used as well. This matches git and GitHub usability. - sha1CurrentPattern = regexp.MustCompile(`(?:\s|^|\(|\[)([0-9a-f]{7,40})(?:\s|$|\)|\]|[.,](\s|$))`) + hashCurrentPattern = regexp.MustCompile(`(?:\s|^|\(|\[)([0-9a-f]{7,64})(?:\s|$|\)|\]|[.,](\s|$))`) // shortLinkPattern matches short but difficult to parse [[name|link|arg=test]] syntax shortLinkPattern = regexp.MustCompile(`\[\[(.*?)\]\](\w*)`) // anySHA1Pattern splits url containing SHA into parts - anySHA1Pattern = regexp.MustCompile(`https?://(?:\S+/){4,5}([0-9a-f]{40})(/[-+~_%.a-zA-Z0-9/]+)?(#[-+~_%.a-zA-Z0-9]+)?`) + anyHashPattern = regexp.MustCompile(`https?://(?:\S+/){4,5}([0-9a-f]{40,64})(/[-+~_%.a-zA-Z0-9/]+)?(#[-+~_%.a-zA-Z0-9]+)?`) // comparePattern matches "http://domain/org/repo/compare/COMMIT1...COMMIT2#hash" - comparePattern = regexp.MustCompile(`https?://(?:\S+/){4,5}([0-9a-f]{7,40})(\.\.\.?)([0-9a-f]{7,40})?(#[-+~_%.a-zA-Z0-9]+)?`) + comparePattern = regexp.MustCompile(`https?://(?:\S+/){4,5}([0-9a-f]{7,64})(\.\.\.?)([0-9a-f]{7,64})?(#[-+~_%.a-zA-Z0-9]+)?`) validLinksPattern = regexp.MustCompile(`^[a-z][\w-]+://`) @@ -171,13 +171,13 @@ type processor func(ctx *RenderContext, var defaultProcessors = []processor{ fullIssuePatternProcessor, comparePatternProcessor, - fullSha1PatternProcessor, + fullHashPatternProcessor, shortLinkProcessor, linkProcessor, mentionProcessor, issueIndexPatternProcessor, commitCrossReferencePatternProcessor, - sha1CurrentPatternProcessor, + hashCurrentPatternProcessor, emailAddressProcessor, emojiProcessor, emojiShortCodeProcessor, @@ -199,12 +199,12 @@ func PostProcess( var commitMessageProcessors = []processor{ fullIssuePatternProcessor, comparePatternProcessor, - fullSha1PatternProcessor, + fullHashPatternProcessor, linkProcessor, mentionProcessor, issueIndexPatternProcessor, commitCrossReferencePatternProcessor, - sha1CurrentPatternProcessor, + hashCurrentPatternProcessor, emailAddressProcessor, emojiProcessor, emojiShortCodeProcessor, @@ -231,12 +231,12 @@ func RenderCommitMessage( var commitMessageSubjectProcessors = []processor{ fullIssuePatternProcessor, comparePatternProcessor, - fullSha1PatternProcessor, + fullHashPatternProcessor, linkProcessor, mentionProcessor, issueIndexPatternProcessor, commitCrossReferencePatternProcessor, - sha1CurrentPatternProcessor, + hashCurrentPatternProcessor, emojiShortCodeProcessor, emojiProcessor, } @@ -273,7 +273,7 @@ func RenderIssueTitle( return renderProcessString(ctx, []processor{ issueIndexPatternProcessor, commitCrossReferencePatternProcessor, - sha1CurrentPatternProcessor, + hashCurrentPatternProcessor, emojiShortCodeProcessor, emojiProcessor, }, title) @@ -943,15 +943,15 @@ func commitCrossReferencePatternProcesso } } -// fullSha1PatternProcessor renders SHA containing URLs -func fullSha1PatternProcessor(ctx *RenderContext, node *html.Node) { +// fullHashPatternProcessor renders SHA containing URLs +func fullHashPatternProcessor(ctx *RenderContext, node *html.Node) { if ctx.Metas == nil { return } next := node.NextSibling for node != nil && node != next { - m := anySHA1Pattern.FindStringSubmatchIndex(node.Data) + m := anyHashPattern.FindStringSubmatchIndex(node.Data) if m == nil { return } @@ -1108,9 +1108,9 @@ func emojiProcessor(ctx *RenderContext, } } -// sha1CurrentPatternProcessor renders SHA1 strings to corresponding links that +// hashCurrentPatternProcessor renders SHA1 strings to corresponding links that // are assumed to be in the same repository. -func sha1CurrentPatternProcessor(ctx *RenderContext, node *html.Node) { +func hashCurrentPatternProcessor(ctx *RenderContext, node *html.Node) { if ctx.Metas == nil || ctx.Metas["user"] == "" || ctx.Metas["repo"] == "" || ctx.Metas["repoPath"] == "" { return } @@ -1121,7 +1121,7 @@ func sha1CurrentPatternProcessor(ctx *Re ctx.ShaExistCache = make(map[string]bool) } for node != nil && node != next && start < len(node.Data) { - m := sha1CurrentPattern.FindStringSubmatchIndex(node.Data[start:]) + m := hashCurrentPattern.FindStringSubmatchIndex(node.Data[start:]) if m == nil { return } Index: gitea-1.21.11/modules/markup/html_internal_test.go =================================================================== --- gitea-1.21.11.orig/modules/markup/html_internal_test.go +++ gitea-1.21.11/modules/markup/html_internal_test.go @@ -390,10 +390,10 @@ func TestRegExp_sha1CurrentPattern(t *te } for _, testCase := range trueTestCases { - assert.True(t, sha1CurrentPattern.MatchString(testCase)) + assert.True(t, hashCurrentPattern.MatchString(testCase)) } for _, testCase := range falseTestCases { - assert.False(t, sha1CurrentPattern.MatchString(testCase)) + assert.False(t, hashCurrentPattern.MatchString(testCase)) } } @@ -427,7 +427,7 @@ func TestRegExp_anySHA1Pattern(t *testin } for k, v := range testCases { - assert.Equal(t, anySHA1Pattern.FindStringSubmatch(k)[1:], v) + assert.Equal(t, anyHashPattern.FindStringSubmatch(k)[1:], v) } } Index: gitea-1.21.11/modules/references/references.go =================================================================== --- gitea-1.21.11.orig/modules/references/references.go +++ gitea-1.21.11/modules/references/references.go @@ -39,7 +39,7 @@ var ( crossReferenceIssueNumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[)([0-9a-zA-Z-_\.]+/[0-9a-zA-Z-_\.]+[#!][0-9]+)(?:\s|$|\)|\]|[:;,.?!]\s|[:;,.?!]$)`) // crossReferenceCommitPattern matches a string that references a commit in a different repository // e.g. go-gitea/gitea@d8a994ef, go-gitea/gitea@d8a994ef243349f321568f9e36d5c3f444b99cae (7-40 characters) - crossReferenceCommitPattern = regexp.MustCompile(`(?:\s|^|\(|\[)([0-9a-zA-Z-_\.]+)/([0-9a-zA-Z-_\.]+)@([0-9a-f]{7,40})(?:\s|$|\)|\]|[:;,.?!]\s|[:;,.?!]$)`) + crossReferenceCommitPattern = regexp.MustCompile(`(?:\s|^|\(|\[)([0-9a-zA-Z-_\.]+)/([0-9a-zA-Z-_\.]+)@([0-9a-f]{7,64})(?:\s|$|\)|\]|[:;,.?!]\s|[:;,.?!]$)`) // spaceTrimmedPattern let's find the trailing space spaceTrimmedPattern = regexp.MustCompile(`(?:.*[0-9a-zA-Z-_])\s`) // timeLogPattern matches string for time tracking Index: gitea-1.21.11/modules/references/references_test.go =================================================================== --- gitea-1.21.11.orig/modules/references/references_test.go +++ gitea-1.21.11/modules/references/references_test.go @@ -343,7 +343,7 @@ func TestFindRenderizableCommitCrossRefe }, }, { - Input: "go-gitea/gitea@abcd1234abcd1234abcd1234abcd1234abcd12340", // longer than 40 characters + Input: "go-gitea/gitea@abcd1234abcd1234abcd1234abcd1234abcd12341234512345123451234512345", // longer than 64 characters Expected: nil, }, { Index: gitea-1.21.11/modules/structs/repo.go =================================================================== --- gitea-1.21.11.orig/modules/structs/repo.go +++ gitea-1.21.11/modules/structs/repo.go @@ -105,6 +105,9 @@ type Repository struct { AvatarURL string `json:"avatar_url"` Internal bool `json:"internal"` MirrorInterval string `json:"mirror_interval"` + // ObjectFormatName of the underlying git repository + // enum: sha1,sha256 + ObjectFormatName string `json:"object_format_name"` // swagger:strfmt date-time MirrorUpdated time.Time `json:"mirror_updated,omitempty"` RepoTransfer *RepoTransfer `json:"repo_transfer"` @@ -139,6 +142,9 @@ type CreateRepoOption struct { // TrustModel of the repository // enum: default,collaborator,committer,collaboratorcommitter TrustModel string `json:"trust_model"` + // ObjectFormatName of the underlying git repository + // enum: sha1,sha256 + ObjectFormatName string `json:"object_format_name" binding:"MaxSize(6)"` } // EditRepoOption options when editing a repository's properties Index: gitea-1.21.11/modules/templates/util_string.go =================================================================== --- gitea-1.21.11.orig/modules/templates/util_string.go +++ gitea-1.21.11/modules/templates/util_string.go @@ -41,3 +41,7 @@ func (su *StringUtils) Cut(s, sep string func (su *StringUtils) EllipsisString(s string, max int) string { return base.EllipsisString(s, max) } + +func (su *StringUtils) ToUpper(s string) string { + return strings.ToUpper(s) +} Index: gitea-1.21.11/options/locale/locale_en-US.ini =================================================================== --- gitea-1.21.11.orig/options/locale/locale_en-US.ini +++ gitea-1.21.11/options/locale/locale_en-US.ini @@ -967,6 +967,8 @@ issue_labels_helper = Select an issue la license = License license_helper = Select a license file. license_helper_desc = A license governs what others can and can't do with your code. Not sure which one is right for your project? See <a target="_blank" rel="noopener noreferrer" href="%s">Choose a license.</a> +object_format = Object Format +object_format_helper = Object format of the repository. Cannot be changed later. SHA1 is most compatible. readme = README readme_helper = Select a README file template. readme_helper_desc = This is the place where you can write a complete description for your project. @@ -1034,6 +1036,7 @@ desc.public = Public desc.template = Template desc.internal = Internal desc.archived = Archived +desc.sha256 = SHA256 template.items = Template Items template.git_content = Git Content (Default Branch) Index: gitea-1.21.11/routers/web/githttp.go =================================================================== --- gitea-1.21.11.orig/routers/web/githttp.go +++ gitea-1.21.11/routers/web/githttp.go @@ -36,8 +36,8 @@ func gitHTTPRouters(m *web.Route) { m.Methods("GET,OPTIONS", "/objects/info/http-alternates", repo.GetTextFile("objects/info/http-alternates")) m.Methods("GET,OPTIONS", "/objects/info/packs", repo.GetInfoPacks) m.Methods("GET,OPTIONS", "/objects/info/{file:[^/]*}", repo.GetTextFile("")) - m.Methods("GET,OPTIONS", "/objects/{head:[0-9a-f]{2}}/{hash:[0-9a-f]{38}}", repo.GetLooseObject) - m.Methods("GET,OPTIONS", "/objects/pack/pack-{file:[0-9a-f]{40}}.pack", repo.GetPackFile) - m.Methods("GET,OPTIONS", "/objects/pack/pack-{file:[0-9a-f]{40}}.idx", repo.GetIdxFile) + m.Methods("GET,OPTIONS", "/objects/{head:[0-9a-f]{2}}/{hash:[0-9a-f]{38,62}}", repo.GetLooseObject) + m.Methods("GET,OPTIONS", "/objects/pack/pack-{file:[0-9a-f]{40,64}}.pack", repo.GetPackFile) + m.Methods("GET,OPTIONS", "/objects/pack/pack-{file:[0-9a-f]{40,64}}.idx", repo.GetIdxFile) }, ignSignInAndCsrf, requireSignIn, repo.HTTPGitEnabledHandler, repo.CorsHandler(), context_service.UserAssignmentWeb()) } Index: gitea-1.21.11/routers/web/web.go =================================================================== --- gitea-1.21.11.orig/routers/web/web.go +++ gitea-1.21.11/routers/web/web.go @@ -1231,7 +1231,7 @@ func registerRoutes(m *web.Route) { Post(web.Bind(forms.UploadRepoFileForm{}), repo.UploadFilePost) m.Combo("/_diffpatch/*").Get(repo.NewDiffPatch). Post(web.Bind(forms.EditRepoFileForm{}), repo.NewDiffPatchPost) - m.Combo("/_cherrypick/{sha:([a-f0-9]{7,40})}/*").Get(repo.CherryPick). + m.Combo("/_cherrypick/{sha:([a-f0-9]{7,64})}/*").Get(repo.CherryPick). Post(web.Bind(forms.CherryPickForm{}), repo.CherryPickPost) }, repo.MustBeEditable) m.Group("", func() { @@ -1373,8 +1373,8 @@ func registerRoutes(m *web.Route) { m.Combo("/*"). Get(repo.Wiki). Post(context.RepoMustNotBeArchived(), reqSignIn, reqRepoWikiWriter, web.Bind(forms.NewWikiForm{}), repo.WikiPost) - m.Get("/commit/{sha:[a-f0-9]{7,40}}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.Diff) - m.Get("/commit/{sha:[a-f0-9]{7,40}}.{ext:patch|diff}", repo.RawDiff) + m.Get("/commit/{sha:[a-f0-9]{7,64}}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.Diff) + m.Get("/commit/{sha:[a-f0-9]{7,64}}.{ext:patch|diff}", repo.RawDiff) }, repo.MustEnableWiki, func(ctx *context.Context) { ctx.Data["PageIsWiki"] = true ctx.Data["CloneButtonOriginLink"] = ctx.Repo.Repository.WikiCloneLink() @@ -1494,9 +1494,9 @@ func registerRoutes(m *web.Route) { m.Group("", func() { m.Get("/graph", repo.Graph) - m.Get("/commit/{sha:([a-f0-9]{7,40})$}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.Diff) - m.Get("/commit/{sha:([a-f0-9]{7,40})$}/load-branches-and-tags", repo.LoadBranchesAndTags) - m.Get("/cherry-pick/{sha:([a-f0-9]{7,40})$}", repo.SetEditorconfigIfExists, repo.CherryPick) + m.Get("/commit/{sha:([a-f0-9]{7,64})$}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.Diff) + m.Get("/commit/{sha:([a-f0-9]{7,64})$}/load-branches-and-tags", repo.LoadBranchesAndTags) + m.Get("/cherry-pick/{sha:([a-f0-9]{7,64})$}", repo.SetEditorconfigIfExists, repo.CherryPick) }, repo.MustBeNotEmpty, context.RepoRef(), reqRepoCodeReader) m.Get("/rss/branch/*", context.RepoRefByType(context.RepoRefBranch), feedEnabled, feed.RenderBranchFeed) @@ -1513,7 +1513,7 @@ func registerRoutes(m *web.Route) { m.Group("", func() { m.Get("/forks", repo.Forks) }, context.RepoRef(), reqRepoCodeReader) - m.Get("/commit/{sha:([a-f0-9]{7,40})}.{ext:patch|diff}", repo.MustBeNotEmpty, reqRepoCodeReader, repo.RawDiff) + m.Get("/commit/{sha:([a-f0-9]{7,64})}.{ext:patch|diff}", repo.MustBeNotEmpty, reqRepoCodeReader, repo.RawDiff) }, ignSignIn, context.RepoAssignment, context.UnitTypes()) m.Post("/{username}/{reponame}/lastcommit/*", ignSignInAndCsrf, context.RepoAssignment, context.UnitTypes(), context.RepoRefByType(context.RepoRefCommit), reqRepoCodeReader, repo.LastCommit) Index: gitea-1.21.11/services/repository/fork.go =================================================================== --- gitea-1.21.11.orig/services/repository/fork.go +++ gitea-1.21.11/services/repository/fork.go @@ -82,6 +82,7 @@ func ForkRepository(ctx context.Context, IsEmpty: opts.BaseRepo.IsEmpty, IsFork: true, ForkID: opts.BaseRepo.ID, + ObjectFormatName: opts.BaseRepo.ObjectFormatName, } oldRepoPath := opts.BaseRepo.RepoPath() Index: gitea-1.21.11/templates/admin/repo/list.tmpl =================================================================== --- gitea-1.21.11.orig/templates/admin/repo/list.tmpl +++ gitea-1.21.11/templates/admin/repo/list.tmpl @@ -67,6 +67,9 @@ {{if .IsTemplate}} <span class="ui basic label">{{ctx.Locale.Tr "repo.desc.template"}}</span> {{end}} + {{if eq .ObjectFormatName "sha256"}} + <span class="ui basic label">{{ctx.Locale.Tr "repo.desc.sha256"}}</span> + {{end}} {{if .IsMirror}} {{svg "octicon-mirror"}} {{else if .IsFork}} Index: gitea-1.21.11/templates/explore/repo_list.tmpl =================================================================== --- gitea-1.21.11.orig/templates/explore/repo_list.tmpl +++ gitea-1.21.11/templates/explore/repo_list.tmpl @@ -24,6 +24,9 @@ {{if .IsTemplate}} <span class="ui basic label">{{ctx.Locale.Tr "repo.desc.template"}}</span> {{end}} + {{if eq .ObjectFormatName "sha256"}} + <span class="ui basic label">{{ctx.Locale.Tr "repo.desc.sha256"}}</span> + {{end}} </span> </div> <div class="flex-item-trailing"> Index: gitea-1.21.11/templates/repo/commits_list.tmpl =================================================================== --- gitea-1.21.11.orig/templates/repo/commits_list.tmpl +++ gitea-1.21.11/templates/repo/commits_list.tmpl @@ -3,8 +3,8 @@ <thead> <tr> <th class="three wide">{{ctx.Locale.Tr "repo.commits.author"}}</th> - <th class="two wide sha">SHA1</th> - <th class="nine wide message">{{ctx.Locale.Tr "repo.commits.message"}}</th> + <th class="two wide sha">{{StringUtils.ToUpper $.Repository.ObjectFormatName}}</th> + <th class="eight wide message">{{ctx.Locale.Tr "repo.commits.message"}}</th> <th class="two wide right aligned">{{ctx.Locale.Tr "repo.commits.date"}}</th> </tr> </thead> Index: gitea-1.21.11/templates/repo/create.tmpl =================================================================== --- gitea-1.21.11.orig/templates/repo/create.tmpl +++ gitea-1.21.11/templates/repo/create.tmpl @@ -209,6 +209,19 @@ </div> </div> <div class="inline field"> + <label>{{ctx.Locale.Tr "repo.object_format"}}</label> + <div class="ui selection owner dropdown"> + <input type="hidden" id="object_format_name" name="object_format_name" value="{{.DefaultObjectFormat.Name}}" required> + <div class="default text">{{.DefaultObjectFormat.Name}}</div> + <div class="menu"> + {{range .SupportedObjectFormats}} + <div class="item" data-value="{{.Name}}">{{.Name}}</div> + {{end}} + </div> + </div> + <span class="help">{{ctx.Locale.Tr "repo.object_format_helper"}}</span> + </div> + <div class="inline field"> <label>{{ctx.Locale.Tr "repo.template"}}</label> <div class="ui checkbox"> <input name="template" type="checkbox"> Index: gitea-1.21.11/templates/repo/header.tmpl =================================================================== --- gitea-1.21.11.orig/templates/repo/header.tmpl +++ gitea-1.21.11/templates/repo/header.tmpl @@ -28,6 +28,9 @@ {{if $.EnableFeed}} <a class="rss-icon gt-ml-3" href="{{$.RepoLink}}.rss" data-tooltip-content="{{ctx.Locale.Tr "rss_feed"}}">{{svg "octicon-rss" 18}}</a> {{end}} + {{if eq .ObjectFormatName "sha256"}} + <span class="ui basic label">{{ctx.Locale.Tr "repo.desc.sha256"}}</span> + {{end}} </div> {{if $.PullMirror}} <div class="fork-flag">{{ctx.Locale.Tr "repo.mirror_from"}} <a target="_blank" rel="noopener noreferrer" href="{{$.PullMirror.RemoteAddress}}">{{$.PullMirror.RemoteAddress}}</a></div> Index: gitea-1.21.11/templates/swagger/v1_json.tmpl =================================================================== --- gitea-1.21.11.orig/templates/swagger/v1_json.tmpl +++ gitea-1.21.11/templates/swagger/v1_json.tmpl @@ -18191,6 +18191,15 @@ "uniqueItems": true, "x-go-name": "Name" }, + "object_format_name": { + "description": "ObjectFormatName of the underlying git repository", + "type": "string", + "enum": [ + "sha1", + "sha256" + ], + "x-go-name": "ObjectFormatName" + }, "private": { "description": "Whether the repository is private", "type": "boolean", @@ -22000,6 +22009,15 @@ "type": "string", "x-go-name": "Name" }, + "object_format_name": { + "description": "ObjectFormatName of the underlying git repository", + "type": "string", + "enum": [ + "sha1", + "sha256" + ], + "x-go-name": "ObjectFormatName" + }, "open_issues_count": { "type": "integer", "format": "int64", Index: gitea-1.21.11/services/repository/commitstatus/commitstatus.go =================================================================== --- gitea-1.21.11.orig/services/repository/commitstatus/commitstatus.go +++ gitea-1.21.11/services/repository/commitstatus/commitstatus.go @@ -94,10 +94,15 @@ func CreateCommitStatus(ctx context.Cont // use complete commit sha sha = commit.ID.String() + commitID, err := git.NewIDFromString(sha) + if err != nil { + return fmt.Errorf("HashTypeInterfaceFromHashString: %w", err) + } + if err := git_model.NewCommitStatus(ctx, git_model.NewCommitStatusOptions{ Repo: repo, Creator: creator, - SHA: sha, + SHA: commitID, CommitStatus: status, }); err != nil { return fmt.Errorf("NewCommitStatus[repo_id: %d, user_id: %d, sha: %s]: %w", repo.ID, creator.ID, sha, err)
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor