aboutsummaryrefslogtreecommitdiffstats
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/context/api.go9
-rw-r--r--modules/context/repo.go18
-rw-r--r--modules/git/batch_reader.go30
-rw-r--r--modules/git/blame.go39
-rw-r--r--modules/git/blame_test.go4
-rw-r--r--modules/git/blob_gogit.go2
-rw-r--r--modules/git/blob_nogogit.go2
-rw-r--r--modules/git/commit.go19
-rw-r--r--modules/git/commit_convert_gogit.go4
-rw-r--r--modules/git/commit_info_gogit.go2
-rw-r--r--modules/git/commit_info_nogogit.go2
-rw-r--r--modules/git/commit_reader.go8
-rw-r--r--modules/git/commit_test.go6
-rw-r--r--modules/git/last_commit_cache.go10
-rw-r--r--modules/git/last_commit_cache_gogit.go3
-rw-r--r--modules/git/log_name_status.go13
-rw-r--r--modules/git/notes_gogit.go3
-rw-r--r--modules/git/object_format.go103
-rw-r--r--modules/git/object_id.go143
-rw-r--r--modules/git/object_id_gogit.go28
-rw-r--r--modules/git/object_id_test.go21
-rw-r--r--modules/git/parse_gogit.go16
-rw-r--r--modules/git/parse_gogit_test.go20
-rw-r--r--modules/git/parse_nogogit.go16
-rw-r--r--modules/git/parse_nogogit_test.go22
-rw-r--r--modules/git/pipeline/lfs.go14
-rw-r--r--modules/git/pipeline/lfs_nogogit.go39
-rw-r--r--modules/git/ref.go4
-rw-r--r--modules/git/repo.go31
-rw-r--r--modules/git/repo_base_gogit.go3
-rw-r--r--modules/git/repo_base_nogogit.go7
-rw-r--r--modules/git/repo_blob.go2
-rw-r--r--modules/git/repo_blob_gogit.go4
-rw-r--r--modules/git/repo_blob_nogogit.go2
-rw-r--r--modules/git/repo_blob_test.go2
-rw-r--r--modules/git/repo_commit.go35
-rw-r--r--modules/git/repo_commit_gogit.go35
-rw-r--r--modules/git/repo_commit_nogogit.go25
-rw-r--r--modules/git/repo_compare.go2
-rw-r--r--modules/git/repo_compare_test.go6
-rw-r--r--modules/git/repo_gpg.go2
-rw-r--r--modules/git/repo_index.go19
-rw-r--r--modules/git/repo_language_stats_nogogit.go2
-rw-r--r--modules/git/repo_object.go44
-rw-r--r--modules/git/repo_ref_gogit.go4
-rw-r--r--modules/git/repo_ref_nogogit.go2
-rw-r--r--modules/git/repo_tag.go14
-rw-r--r--modules/git/repo_tag_gogit.go12
-rw-r--r--modules/git/repo_tag_nogogit.go8
-rw-r--r--modules/git/repo_tag_test.go15
-rw-r--r--modules/git/repo_tree.go6
-rw-r--r--modules/git/repo_tree_gogit.go14
-rw-r--r--modules/git/repo_tree_nogogit.go10
-rw-r--r--modules/git/sha1.go72
-rw-r--r--modules/git/sha1_gogit.go19
-rw-r--r--modules/git/sha1_nogogit.go61
-rw-r--r--modules/git/sha1_test.go20
-rw-r--r--modules/git/tag.go10
-rw-r--r--modules/git/tag_test.go10
-rw-r--r--modules/git/tree.go2
-rw-r--r--modules/git/tree_blob_gogit.go2
-rw-r--r--modules/git/tree_entry_gogit.go4
-rw-r--r--modules/git/tree_entry_nogogit.go2
-rw-r--r--modules/git/tree_gogit.go10
-rw-r--r--modules/git/tree_nogogit.go10
-rw-r--r--modules/indexer/code/git.go17
-rw-r--r--modules/repository/commits_test.go7
-rw-r--r--modules/repository/generate.go6
-rw-r--r--modules/repository/init.go4
-rw-r--r--modules/repository/push.go6
70 files changed, 720 insertions, 448 deletions
diff --git a/modules/context/api.go b/modules/context/api.go
index ba35adf831..f41228ad76 100644
--- a/modules/context/api.go
+++ b/modules/context/api.go
@@ -308,6 +308,12 @@ func RepoRefForAPI(next http.Handler) http.Handler {
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 {
@@ -325,7 +331,6 @@ func RepoRefForAPI(next http.Handler) http.Handler {
return
}
- var err error
refName := getRefName(ctx.Base, ctx.Repo, RepoRefAny)
if ctx.Repo.GitRepo.IsBranchExist(refName) {
@@ -342,7 +347,7 @@ func RepoRefForAPI(next http.Handler) http.Handler {
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 {
diff --git a/modules/context/repo.go b/modules/context/repo.go
index a18dc873b6..882a406731 100644
--- a/modules/context/repo.go
+++ b/modules/context/repo.go
@@ -825,7 +825,9 @@ func getRefName(ctx *Base, repo *Repository, pathType RepoRefType) string {
}
// 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]
}
@@ -869,7 +871,9 @@ func getRefName(ctx *Base, repo *Repository, pathType RepoRefType) string {
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]
}
@@ -929,6 +933,12 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
}
}
+ 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
@@ -995,7 +1005,7 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
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
@@ -1005,7 +1015,7 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
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))))
}
diff --git a/modules/git/batch_reader.go b/modules/git/batch_reader.go
index 7a44e6295c..53a9393d5f 100644
--- a/modules/git/batch_reader.go
+++ b/modules/git/batch_reader.go
@@ -148,7 +148,7 @@ func CatFileBatch(ctx context.Context, repoPath string) (WriteCloserError, *bufi
// 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 {
@@ -251,20 +251,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]
@@ -278,10 +277,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
@@ -324,11 +323,12 @@ func ParseTreeLine(rd *bufio.Reader, modeBuf, fnameBuf, shaBuf []byte) (mode, fn
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
diff --git a/modules/git/blame.go b/modules/git/blame.go
index 93c7f184fa..64095a218a 100644
--- a/modules/git/blame.go
+++ b/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() (*BlamePart, error) {
}
}
+ const previousHeader = "previous "
var lineBytes []byte
var isPrefix bool
var err error
@@ -67,21 +65,22 @@ func (r *BlameReader) NextPart() (*BlamePart, error) {
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() (*BlamePart, error) {
}
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.Context, repoPath string, commit *Commit, fil
bufferedReader: bufferedReader,
done: done,
ignoreRevsFile: ignoreRevsFile,
+ objectFormat: objectFormat,
}, nil
}
diff --git a/modules/git/blame_test.go b/modules/git/blame_test.go
index 040f4e822d..0afc6d2a1f 100644
--- a/modules/git/blame_test.go
+++ b/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()
diff --git a/modules/git/blob_gogit.go b/modules/git/blob_gogit.go
index aa206409d0..8c79c067c1 100644
--- a/modules/git/blob_gogit.go
+++ b/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
diff --git a/modules/git/blob_nogogit.go b/modules/git/blob_nogogit.go
index 511332eb50..6e8a48b1db 100644
--- a/modules/git/blob_nogogit.go
+++ b/modules/git/blob_nogogit.go
@@ -16,7 +16,7 @@ import (
// Blob represents a Git object.
type Blob struct {
- ID SHA1
+ ID ObjectID
gotSize bool
size int64
diff --git a/modules/git/commit.go b/modules/git/commit.go
index 4ff8f6148f..a8b6c0e8f7 100644
--- a/modules/git/commit.go
+++ b/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() ([]*Commit, error) {
}
// 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(commitHash SHA1) (bool, error) {
// 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.Empty().String() {
return false, nil
}
+
oldCommit, err := c.repo.GetCommit(oldCommitID)
if err != nil {
return false, err
diff --git a/modules/git/commit_convert_gogit.go b/modules/git/commit_convert_gogit.go
index 669f1b15d5..819ea0d1db 100644
--- a/modules/git/commit_convert_gogit.go
+++ b/modules/git/commit_convert_gogit.go
@@ -59,11 +59,11 @@ func convertPGPSignature(c *object.Commit) *CommitGPGSignature {
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),
}
}
diff --git a/modules/git/commit_info_gogit.go b/modules/git/commit_info_gogit.go
index c61d27993c..31ffc9aec1 100644
--- a/modules/git/commit_info_gogit.go
+++ b/modules/git/commit_info_gogit.go
@@ -29,7 +29,7 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, commit *Commit, treePath
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
}
diff --git a/modules/git/commit_info_nogogit.go b/modules/git/commit_info_nogogit.go
index e469d2cab6..8cf8200c3f 100644
--- a/modules/git/commit_info_nogogit.go
+++ b/modules/git/commit_info_nogogit.go
@@ -153,7 +153,7 @@ func GetLastCommitForPaths(ctx context.Context, commit *Commit, treePath string,
if typ != "commit" {
return nil, fmt.Errorf("unexpected type: %s for commit id: %s", typ, commitID)
}
- c, err = CommitFromReader(commit.repo, MustIDFromString(commitID), io.LimitReader(batchReader, size))
+ c, err = CommitFromReader(commit.repo, commit.ID.Type().MustIDFromString(commitID), io.LimitReader(batchReader, size))
if err != nil {
return nil, err
}
diff --git a/modules/git/commit_reader.go b/modules/git/commit_reader.go
index 23607c43ab..08a529a132 100644
--- a/modules/git/commit_reader.go
+++ b/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{},
}
@@ -71,10 +71,10 @@ readLoop:
switch string(split[0]) {
case "tree":
- commit.Tree = *NewTree(gitRepo, MustIDFromString(string(data)))
+ commit.Tree = *NewTree(gitRepo, objectID.Type().MustIDFromString(string(data)))
_, _ = payloadSB.Write(line)
case "parent":
- commit.Parents = append(commit.Parents, MustIDFromString(string(data)))
+ commit.Parents = append(commit.Parents, objectID.Type().MustIDFromString(string(data)))
_, _ = payloadSB.Write(line)
case "author":
commit.Author = &Signature{}
diff --git a/modules/git/commit_test.go b/modules/git/commit_test.go
index ac586fdf09..dec67f6628 100644
--- a/modules/git/commit_test.go
+++ b/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)
@@ -135,8 +135,8 @@ func TestHasPreviousCommit(t *testing.T) {
commit, err := repo.GetCommit("8006ff9adbf0cb94da7dad9e537e53817f9fa5c0")
assert.NoError(t, err)
- parentSHA := MustIDFromString("8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2")
- notParentSHA := MustIDFromString("2839944139e0de9737a044f78b0e4b40d989a9e3")
+ parentSHA := repo.objectFormat.MustIDFromString("8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2")
+ notParentSHA := repo.objectFormat.MustIDFromString("2839944139e0de9737a044f78b0e4b40d989a9e3")
haz, err := commit.HasPreviousCommit(parentSHA)
assert.NoError(t, err)
diff --git a/modules/git/last_commit_cache.go b/modules/git/last_commit_cache.go
index 20bc796085..55585ac4ac 100644
--- a/modules/git/last_commit_cache.go
+++ b/modules/git/last_commit_cache.go
@@ -92,17 +92,21 @@ func (c *LastCommitCache) Get(ref, entryPath string) (*Commit, error) {
// 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)
+ objectFormat, err := c.repo.GetObjectFormat()
+ if err != nil {
+ return nil, err
+ }
+ sha, err := objectFormat.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
}
diff --git a/modules/git/last_commit_cache_gogit.go b/modules/git/last_commit_cache_gogit.go
index 90e609fc81..3afc213094 100644
--- a/modules/git/last_commit_cache_gogit.go
+++ b/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.Context) error {
}
commitNodeIndex, _ := c.repo.CommitNodeIndex()
- index, err := commitNodeIndex.Get(c.ID)
+ index, err := commitNodeIndex.Get(plumbing.Hash(c.ID.RawValue()))
if err != nil {
return err
}
diff --git a/modules/git/log_name_status.go b/modules/git/log_name_status.go
index 7519e32b90..26a0d28098 100644
--- a/modules/git/log_name_status.go
+++ b/modules/git/log_name_status.go
@@ -143,17 +143,20 @@ func (g *LogNameStatusRepoParser) Next(treepath string, paths2ids map[string]int
}
// 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
diff --git a/modules/git/notes_gogit.go b/modules/git/notes_gogit.go
index c2297d8970..f802443b00 100644
--- a/modules/git/notes_gogit.go
+++ b/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 *Repository, commitID string, note *Note)
defer commitGraphFile.Close()
}
- commitNode, err := commitNodeIndex.Get(notes.ID)
+ commitNode, err := commitNodeIndex.Get(plumbing.Hash(notes.ID.RawValue()))
if err != nil {
return err
}
diff --git a/modules/git/object_format.go b/modules/git/object_format.go
new file mode 100644
index 0000000000..7f5d09170c
--- /dev/null
+++ b/modules/git/object_format.go
@@ -0,0 +1,103 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package git
+
+import (
+ "crypto/sha1"
+ "fmt"
+ "regexp"
+ "strings"
+)
+
+type ObjectFormatID int
+
+const (
+ Sha1 ObjectFormatID = iota
+)
+
+// sha1Pattern can be used to determine if a string is an valid sha
+var sha1Pattern = regexp.MustCompile(`^[0-9a-f]{4,40}$`)
+
+type ObjectFormat interface {
+ ID() ObjectFormatID
+ String() string
+
+ // Empty is the hash of empty git
+ Empty() ObjectID
+ // EmptyTree is the hash of an empty tree
+ EmptyTree() ObjectID
+ // FullLength is the length of the hash's hex string
+ FullLength() int
+
+ IsValid(input string) bool
+ MustID(b []byte) ObjectID
+ MustIDFromString(s string) ObjectID
+ NewID(b []byte) (ObjectID, error)
+ NewIDFromString(s string) (ObjectID, error)
+ NewEmptyID() ObjectID
+
+ NewHasher() HasherInterface
+}
+
+/* SHA1 Type */
+type Sha1ObjectFormat struct{}
+
+func (*Sha1ObjectFormat) ID() ObjectFormatID { return Sha1 }
+func (*Sha1ObjectFormat) String() string { return "sha1" }
+func (*Sha1ObjectFormat) Empty() ObjectID { return &Sha1Hash{} }
+func (*Sha1ObjectFormat) EmptyTree() ObjectID {
+ return &Sha1Hash{
+ 0x4b, 0x82, 0x5d, 0xc6, 0x42, 0xcb, 0x6e, 0xb9, 0xa0, 0x60,
+ 0xe5, 0x4b, 0xf8, 0xd6, 0x92, 0x88, 0xfb, 0xee, 0x49, 0x04,
+ }
+}
+func (*Sha1ObjectFormat) FullLength() int { return 40 }
+func (*Sha1ObjectFormat) IsValid(input string) bool {
+ return sha1Pattern.MatchString(input)
+}
+
+func (*Sha1ObjectFormat) MustID(b []byte) ObjectID {
+ var id Sha1Hash
+ copy(id[0:20], b)
+ return &id
+}
+
+func (h *Sha1ObjectFormat) MustIDFromString(s string) ObjectID {
+ return MustIDFromString(h, s)
+}
+
+func (h *Sha1ObjectFormat) NewID(b []byte) (ObjectID, error) {
+ return IDFromRaw(h, b)
+}
+
+func (h *Sha1ObjectFormat) NewIDFromString(s string) (ObjectID, error) {
+ return genericIDFromString(h, s)
+}
+
+func (*Sha1ObjectFormat) NewEmptyID() ObjectID {
+ return NewSha1()
+}
+
+func (h *Sha1ObjectFormat) NewHasher() HasherInterface {
+ return &Sha1Hasher{sha1.New()}
+}
+
+// utils
+func ObjectFormatFromID(id ObjectFormatID) ObjectFormat {
+ switch id {
+ case Sha1:
+ return &Sha1ObjectFormat{}
+ }
+
+ return nil
+}
+
+func ObjectFormatFromString(hash string) (ObjectFormat, error) {
+ switch strings.ToLower(hash) {
+ case "sha1":
+ return &Sha1ObjectFormat{}, nil
+ }
+
+ return nil, fmt.Errorf("unknown hash type: %s", hash)
+}
diff --git a/modules/git/object_id.go b/modules/git/object_id.go
new file mode 100644
index 0000000000..3cba6d4f72
--- /dev/null
+++ b/modules/git/object_id.go
@@ -0,0 +1,143 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package git
+
+import (
+ "bytes"
+ "encoding/hex"
+ "errors"
+ "fmt"
+ "hash"
+ "strconv"
+ "strings"
+)
+
+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{} }
+
+func NewSha1() *Sha1Hash {
+ return &Sha1Hash{}
+}
+
+// generic implementations
+func NewHash(hash string) (ObjectID, error) {
+ hash = strings.ToLower(hash)
+ switch hash {
+ case "sha1":
+ return &Sha1Hash{}, nil
+ }
+
+ return nil, errors.New("unsupported hash type")
+}
+
+func IDFromRaw(h ObjectFormat, b []byte) (ObjectID, error) {
+ if len(b) != h.FullLength()/2 {
+ return h.Empty(), fmt.Errorf("length must be %d: %v", h.FullLength(), b)
+ }
+ return h.MustID(b), nil
+}
+
+func MustIDFromString(h ObjectFormat, s string) ObjectID {
+ b, _ := hex.DecodeString(s)
+ return h.MustID(b)
+}
+
+func genericIDFromString(h ObjectFormat, s string) (ObjectID, error) {
+ s = strings.TrimSpace(s)
+ if len(s) != h.FullLength() {
+ return h.Empty(), fmt.Errorf("length must be %d: %s", h.FullLength(), s)
+ }
+ b, err := hex.DecodeString(s)
+ if err != nil {
+ return h.Empty(), err
+ }
+ return h.NewID(b)
+}
+
+// utils
+func IDFromString(hexHash string) (ObjectID, error) {
+ switch len(hexHash) {
+ case 40:
+ hashType := Sha1ObjectFormat{}
+ h, err := hashType.NewIDFromString(hexHash)
+ if err != nil {
+ return nil, err
+ }
+ return h, nil
+ }
+
+ return nil, fmt.Errorf("invalid hash hex string: '%s' len: %d", hexHash, len(hexHash))
+}
+
+func IsEmptyCommitID(commitID string) bool {
+ if commitID == "" {
+ return true
+ }
+
+ id, err := IDFromString(commitID)
+ if err != nil {
+ return false
+ }
+
+ return id.IsZero()
+}
+
+// HashInterface is a struct that will generate a Hash
+type HasherInterface interface {
+ hash.Hash
+
+ HashSum() ObjectID
+}
+
+type Sha1Hasher struct {
+ hash.Hash
+}
+
+// ComputeBlobHash compute the hash for a given blob content
+func ComputeBlobHash(hashType ObjectFormat, content []byte) ObjectID {
+ return ComputeHash(hashType, ObjectBlob, content)
+}
+
+// ComputeHash compute the hash for a given ObjectType and content
+func ComputeHash(hashType ObjectFormat, t ObjectType, content []byte) ObjectID {
+ h := hashType.NewHasher()
+ _, _ = h.Write(t.Bytes())
+ _, _ = h.Write([]byte(" "))
+ _, _ = h.Write([]byte(strconv.FormatInt(int64(len(content)), 10)))
+ _, _ = h.Write([]byte{0})
+ return h.HashSum()
+}
+
+// Sum generates a SHA1 for the provided hash
+func (h *Sha1Hasher) HashSum() ObjectID {
+ var sha1 Sha1Hash
+ copy(sha1[:], h.Hash.Sum(nil))
+ return &sha1
+}
+
+type ErrInvalidSHA struct {
+ SHA string
+}
+
+func (err ErrInvalidSHA) Error() string {
+ return fmt.Sprintf("invalid sha: %s", err.SHA)
+}
diff --git a/modules/git/object_id_gogit.go b/modules/git/object_id_gogit.go
new file mode 100644
index 0000000000..50917f0552
--- /dev/null
+++ b/modules/git/object_id_gogit.go
@@ -0,0 +1,28 @@
+// 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 ObjectFormatFromID(Sha1).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
+}
diff --git a/modules/git/object_id_test.go b/modules/git/object_id_test.go
new file mode 100644
index 0000000000..c78a215755
--- /dev/null
+++ b/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 := NewSha1().Type()
+ 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"))
+}
diff --git a/modules/git/parse_gogit.go b/modules/git/parse_gogit.go
index 226ef5df73..6c22ea8da7 100644
--- a/modules/git/parse_gogit.go
+++ b/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 *Tree) ([]*TreeEntry, error) {
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 = IDFromString(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 *Tree) ([]*TreeEntry, error) {
// 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)
diff --git a/modules/git/parse_gogit_test.go b/modules/git/parse_gogit_test.go
index f6e32401e6..7ba50cbff9 100644
--- a/modules/git/parse_gogit_test.go
+++ b/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"
@@ -26,9 +28,9 @@ func TestParseTreeEntries(t *testing.T) {
Input: "100644 blob 61ab7345a1a3bbc590068ccae37b8515cfc5843c 1022\texample/file2.txt\n",
Expected: []*TreeEntry{
{
- ID: MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c"),
+ ID: ObjectFormatFromID(Sha1).MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c"),
gogitTreeEntry: &object.TreeEntry{
- Hash: MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c"),
+ Hash: plumbing.Hash(ObjectFormatFromID(Sha1).MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c").RawValue()),
Name: "example/file2.txt",
Mode: filemode.Regular,
},
@@ -42,9 +44,9 @@ func TestParseTreeEntries(t *testing.T) {
"040000 tree 1d01fb729fb0db5881daaa6030f9f2d3cd3d5ae8 -\texample\n",
Expected: []*TreeEntry{
{
- ID: MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c"),
+ ID: ObjectFormatFromID(Sha1).MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c"),
gogitTreeEntry: &object.TreeEntry{
- Hash: MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c"),
+ Hash: plumbing.Hash(ObjectFormatFromID(Sha1).MustIDFromString("61ab7345a1a3bbc590068ccae37b8515cfc5843c").RawValue()),
Name: "example/\n.txt",
Mode: filemode.Symlink,
},
@@ -52,10 +54,10 @@ func TestParseTreeEntries(t *testing.T) {
sized: true,
},
{
- ID: MustIDFromString("1d01fb729fb0db5881daaa6030f9f2d3cd3d5ae8"),
+ ID: ObjectFormatFromID(Sha1).MustIDFromString("1d01fb729fb0db5881daaa6030f9f2d3cd3d5ae8"),
sized: true,
gogitTreeEntry: &object.TreeEntry{
- Hash: MustIDFromString("1d01fb729fb0db5881daaa6030f9f2d3cd3d5ae8"),
+ Hash: plumbing.Hash(ObjectFormatFromID(Sha1).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(ObjectFormatFromID(Sha1), []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)
}
}
diff --git a/modules/git/parse_nogogit.go b/modules/git/parse_nogogit.go
index 8b94c69200..e35704eb34 100644
--- a/modules/git/parse_nogogit.go
+++ b/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); {
@@ -72,7 +72,7 @@ func parseTreeEntries(data []byte, ptree *Tree) ([]*TreeEntry, error) {
return nil, fmt.Errorf("unknown type: %v", string(entryMode))
}
- entry.ID, err = NewIDFromString(string(entryObjectID))
+ entry.ID, err = objectFormat.NewIDFromString(string(entryObjectID))
if err != nil {
return nil, fmt.Errorf("invalid ls-tree output (invalid object id): %q, err: %w", line, err)
}
@@ -92,15 +92,15 @@ func parseTreeEntries(data []byte, ptree *Tree) ([]*TreeEntry, error) {
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)
}
diff --git a/modules/git/parse_nogogit_test.go b/modules/git/parse_nogogit_test.go
index 23fddb014c..0b78c081cd 100644
--- a/modules/git/parse_nogogit_test.go
+++ b/modules/git/parse_nogogit_test.go
@@ -12,6 +12,8 @@ import (
)
func TestParseTreeEntriesLong(t *testing.T) {
+ objectFormat := ObjectFormatFromID(Sha1)
+
testCases := []struct {
Input string
Expected []*TreeEntry
@@ -24,28 +26,28 @@ func TestParseTreeEntriesLong(t *testing.T) {
`,
Expected: []*TreeEntry{
{
- ID: MustIDFromString("ea0d83c9081af9500ac9f804101b3fd0a5c293af"),
+ ID: objectFormat.MustIDFromString("ea0d83c9081af9500ac9f804101b3fd0a5c293af"),
name: "README.md",
entryMode: EntryModeBlob,
size: 8218,
sized: true,
},
{
- ID: MustIDFromString("037f27dc9d353ae4fd50f0474b2194c593914e35"),
+ ID: objectFormat.MustIDFromString("037f27dc9d353ae4fd50f0474b2194c593914e35"),
name: "README_ZH.md",
entryMode: EntryModeBlob,
size: 4681,
sized: true,
},
{
- ID: MustIDFromString("9846a94f7e8350a916632929d0fda38c90dd2ca8"),
+ ID: objectFormat.MustIDFromString("9846a94f7e8350a916632929d0fda38c90dd2ca8"),
name: "SECURITY.md",
entryMode: EntryModeBlob,
size: 429,
sized: true,
},
{
- ID: MustIDFromString("84b90550547016f73c5dd3f50dea662389e67b6d"),
+ ID: objectFormat.MustIDFromString("84b90550547016f73c5dd3f50dea662389e67b6d"),
name: "assets",
entryMode: EntryModeTree,
sized: true,
@@ -54,7 +56,7 @@ func TestParseTreeEntriesLong(t *testing.T) {
},
}
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.T) {
}
func TestParseTreeEntriesShort(t *testing.T) {
+ objectFormat := ObjectFormatFromID(Sha1)
+
testCases := []struct {
Input string
Expected []*TreeEntry
@@ -74,12 +78,12 @@ func TestParseTreeEntriesShort(t *testing.T) {
`,
Expected: []*TreeEntry{
{
- ID: MustIDFromString("ea0d83c9081af9500ac9f804101b3fd0a5c293af"),
+ ID: objectFormat.MustIDFromString("ea0d83c9081af9500ac9f804101b3fd0a5c293af"),
name: "README.md",
entryMode: EntryModeBlob,
},
{
- ID: MustIDFromString("84b90550547016f73c5dd3f50dea662389e67b6d"),
+ ID: objectFormat.MustIDFromString("84b90550547016f73c5dd3f50dea662389e67b6d"),
name: "assets",
entryMode: EntryModeTree,
},
@@ -87,7 +91,7 @@ func TestParseTreeEntriesShort(t *testing.T) {
},
}
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 *testing.T) {
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(ObjectFormatFromID(Sha1), []byte("100644 blob ea0d83c9081af9500ac9f804101b3fd0a5c293af"))
assert.Error(t, err)
assert.Len(t, entries, 0)
}
diff --git a/modules/git/pipeline/lfs.go b/modules/git/pipeline/lfs.go
index ee0505f29f..6dfca24f29 100644
--- a/modules/git/pipeline/lfs.go
+++ b/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) { a[i], a[j] = a[j], a[i] }
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, hash git.SHA1) ([]*LFSResult, error) {
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
}
diff --git a/modules/git/pipeline/lfs_nogogit.go b/modules/git/pipeline/lfs_nogogit.go
index 49390f7c00..89cbf740ff 100644
--- a/modules/git/pipeline/lfs_nogogit.go
+++ b/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) { a[i], a[j] = a[j], a[i] }
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, hash git.SHA1) ([]*LFSResult, error) {
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
@@ -115,7 +115,11 @@ func FindLFSFile(repo *git.Repository, hash git.SHA1) ([]*LFSResult, error) {
continue
case "commit":
// Read in the commit to get its tree and in case this is one of the last used commits
- curCommit, err = git.CommitFromReader(repo, git.MustIDFromString(string(commitID)), io.LimitReader(batchReader, size))
+ objectFormat, err := repo.GetObjectFormat()
+ if err != nil {
+ return nil, err
+ }
+ curCommit, err = git.CommitFromReader(repo, objectFormat.MustIDFromString(string(commitID)), io.LimitReader(batchReader, size))
if err != nil {
return nil, err
}
@@ -123,32 +127,31 @@ func FindLFSFile(repo *git.Repository, hash git.SHA1) ([]*LFSResult, error) {
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)+"/")
}
}
@@ -180,8 +183,8 @@ func FindLFSFile(repo *git.Repository, hash git.SHA1) ([]*LFSResult, error) {
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
}
}
diff --git a/modules/git/ref.go b/modules/git/ref.go
index ad251515e7..b96b4ababb 100644
--- a/modules/git/ref.go
+++ b/modules/git/ref.go
@@ -44,7 +44,7 @@ func SanitizeRefPattern(name string) string {
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 !ObjectFormatFromID(Sha1).IsValid(ref):
// assume they mean a branch
return repoURL + "/src/branch/" + refName
default:
diff --git a/modules/git/repo.go b/modules/git/repo.go
index 32f0e7007e..871d267a5b 100644
--- a/modules/git/repo.go
+++ b/modules/git/repo.go
@@ -7,6 +7,7 @@ package git
import (
"bytes"
"context"
+ "errors"
"fmt"
"io"
"net/url"
@@ -62,14 +63,40 @@ func IsRepoURLAccessible(ctx context.Context, url string) bool {
return err == nil
}
+// GetObjectFormatOfRepo returns the hash type of a 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 := IDFromString(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, objectFormat ObjectFormat) error {
err := os.MkdirAll(repoPath, os.ModePerm)
if err != nil {
return err
}
- cmd := NewCommand(ctx, "init")
+ cmd := NewCommand(ctx, "init", "--object-format").AddDynamicArguments(objectFormat.String())
if bare {
cmd.AddArguments("--bare")
}
diff --git a/modules/git/repo_base_gogit.go b/modules/git/repo_base_gogit.go
index ef59ead900..d0b8e79368 100644
--- a/modules/git/repo_base_gogit.go
+++ b/modules/git/repo_base_gogit.go
@@ -16,6 +16,7 @@ import (
"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"
)
@@ -32,6 +33,7 @@ type Repository struct {
Ctx context.Context
LastCommitCache *LastCommitCache
+ objectFormat ObjectFormat
}
// openRepositoryWithDefaultContext opens the repository at the given path with DefaultContext.
@@ -68,6 +70,7 @@ func OpenRepository(ctx context.Context, repoPath string) (*Repository, error) {
gogitStorage: storage,
tagCache: newObjectCache(),
Ctx: ctx,
+ objectFormat: ParseGogitHash(plumbing.ZeroHash).Type(),
}, nil
}
diff --git a/modules/git/repo_base_nogogit.go b/modules/git/repo_base_nogogit.go
index 414e4eb1a8..a783366cc1 100644
--- a/modules/git/repo_base_nogogit.go
+++ b/modules/git/repo_base_nogogit.go
@@ -33,6 +33,8 @@ type Repository struct {
Ctx context.Context
LastCommitCache *LastCommitCache
+
+ objectFormat ObjectFormat
}
// openRepositoryWithDefaultContext opens the repository at the given path with DefaultContext.
@@ -63,6 +65,11 @@ func OpenRepository(ctx context.Context, repoPath string) (*Repository, error) {
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
}
diff --git a/modules/git/repo_blob.go b/modules/git/repo_blob.go
index 698b6c7074..b5447b2bb1 100644
--- a/modules/git/repo_blob.go
+++ b/modules/git/repo_blob.go
@@ -5,7 +5,7 @@ package git
// GetBlob finds the blob object in the repository.
func (repo *Repository) GetBlob(idStr string) (*Blob, error) {
- id, err := NewIDFromString(idStr)
+ id, err := repo.objectFormat.NewIDFromString(idStr)
if err != nil {
return nil, err
}
diff --git a/modules/git/repo_blob_gogit.go b/modules/git/repo_blob_gogit.go
index 7f0892f6f5..66c8c2775c 100644
--- a/modules/git/repo_blob_gogit.go
+++ b/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(), ""}
}
diff --git a/modules/git/repo_blob_nogogit.go b/modules/git/repo_blob_nogogit.go
index 184a2bc9dd..04b0fb00ff 100644
--- a/modules/git/repo_blob_nogogit.go
+++ b/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(), ""}
}
diff --git a/modules/git/repo_blob_test.go b/modules/git/repo_blob_test.go
index 026c73a283..e122573954 100644
--- a/modules/git/repo_blob_test.go
+++ b/modules/git/repo_blob_test.go
@@ -61,7 +61,7 @@ func TestRepository_GetBlob_NoId(t *testing.T) {
defer r.Close()
testCase := ""
- testError := fmt.Errorf("Length must be 40: %s", testCase)
+ testError := fmt.Errorf("length must be 40: %s", testCase)
blob, err := r.GetBlob(testCase)
assert.Nil(t, blob)
diff --git a/modules/git/repo_commit.go b/modules/git/repo_commit.go
index 6b06fef656..58bbcf9303 100644
--- a/modules/git/repo_commit.go
+++ b/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(name string) (string, error) {
// 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(name string) (*Commit, error) {
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
@@ -65,7 +63,7 @@ func (repo *Repository) getCommitByPathWithID(id SHA1, relpath string) (*Commit,
return nil, runErr
}
- id, err := NewIDFromString(stdout)
+ id, err := repo.objectFormat.NewIDFromString(stdout)
if err != nil {
return nil, err
}
@@ -90,7 +88,7 @@ func (repo *Repository) GetCommitByPath(relpath string) (*Commit, error) {
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(id SHA1, page, pageSize int, not string)
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
@@ -164,7 +162,7 @@ func (repo *Repository) searchCommits(id SHA1, opts SearchCommitsOptions) ([]*Co
// then let's iterate over them
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
@@ -245,25 +243,22 @@ func (repo *Repository) CommitsByFileAndRange(opts CommitsByFileAndRangeOptions)
}
}()
+ 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 := repo.objectFormat.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
}
@@ -392,7 +387,7 @@ func (repo *Repository) CommitsCountBetween(start, end string) (int64, error) {
}
// 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)
@@ -426,11 +421,11 @@ func (repo *Repository) commitsBefore(id SHA1, limit int) ([]*Commit, error) {
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)
}
diff --git a/modules/git/repo_commit_gogit.go b/modules/git/repo_commit_gogit.go
index ce0af93614..893055bccd 100644
--- a/modules/git/repo_commit_gogit.go
+++ b/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,40 +39,46 @@ func (repo *Repository) RemoveReference(name string) error {
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 := objectFormat.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.Empty(), ErrNotExist{commitID, ""}
}
- return SHA1{}, err
+ return objectFormat.Empty(), err
}
- return NewIDFromString(actualCommitID)
+ return objectFormat.NewIDFromString(actualCommitID)
}
// 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 SHA1) (*Commit, error) {
return nil, err
}
- commit.Tree.ID = tree.Hash
+ commit.Tree.ID = ParseGogitHash(tree.Hash)
commit.Tree.gogitTree = tree
return commit, nil
diff --git a/modules/git/repo_commit_nogogit.go b/modules/git/repo_commit_nogogit.go
index d5eb723100..018e271c39 100644
--- a/modules/git/repo_commit_nogogit.go
+++ b/modules/git/repo_commit_nogogit.go
@@ -65,7 +65,7 @@ func (repo *Repository) IsCommitExist(name string) bool {
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 SHA1) (*Commit, error) {
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) getCommitFromBatchReader(rd *bufio.Reader, id SHA1) (*Co
if err != nil {
return nil, err
}
- tag, err := parseTagData(data)
+ tag, err := parseTagData(id.Type(), data)
if err != nil {
return nil, err
}
@@ -131,12 +131,13 @@ func (repo *Repository) getCommitFromBatchReader(rd *bufio.Reader, id SHA1) (*Co
}
}
-// 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 := repo.objectFormat.NewIDFromString(commitID)
if err == nil {
- return sha1, nil
+ return ID, nil
}
}
@@ -144,15 +145,15 @@ func (repo *Repository) ConvertToSHA1(commitID string) (SHA1, error) {
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
+ return repo.objectFormat.MustIDFromString(string(sha)), nil
}
diff --git a/modules/git/repo_compare.go b/modules/git/repo_compare.go
index aad725fa9d..8885df4f70 100644
--- a/modules/git/repo_compare.go
+++ b/modules/git/repo_compare.go
@@ -284,7 +284,7 @@ func (repo *Repository) GetPatch(base, head string, w io.Writer) error {
// 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.Empty().String() {
cmd.AddDynamicArguments(head)
} else {
cmd.AddDynamicArguments(base, head)
diff --git a/modules/git/repo_compare_test.go b/modules/git/repo_compare_test.go
index 603aabde42..9bfaa5c02a 100644
--- a/modules/git/repo_compare_test.go
+++ b/modules/git/repo_compare_test.go
@@ -131,12 +131,12 @@ func TestGetCommitFilesChanged(t *testing.T) {
files []string
}{
{
- EmptySHA,
+ repo.objectFormat.Empty().String(),
"95bb4d39648ee7e325106df01a621c530863a653",
[]string{"file1.txt"},
},
{
- EmptySHA,
+ repo.objectFormat.Empty().String(),
"8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2",
[]string{"file2.txt"},
},
@@ -146,7 +146,7 @@ func TestGetCommitFilesChanged(t *testing.T) {
[]string{"file2.txt"},
},
{
- EmptyTreeSHA,
+ repo.objectFormat.EmptyTree().String(),
"8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2",
[]string{"file1.txt", "file2.txt"},
},
diff --git a/modules/git/repo_gpg.go b/modules/git/repo_gpg.go
index 4803be5816..e2b45064fd 100644
--- a/modules/git/repo_gpg.go
+++ b/modules/git/repo_gpg.go
@@ -17,7 +17,7 @@ func (gpgSettings *GPGSettings) LoadPublicKeyContent() error {
"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
diff --git a/modules/git/repo_index.go b/modules/git/repo_index.go
index 34dd1e0129..6f43734655 100644
--- a/modules/git/repo_index.go
+++ b/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
@@ -25,14 +30,14 @@ func (repo *Repository) ReadTreeToIndex(treeish string, indexFilename ...string)
treeish = res[:len(res)-1]
}
}
- id, err := NewIDFromString(treeish)
+ id, err := objectFormat.NewIDFromString(treeish)
if err != nil {
return err
}
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) RemoveFilesFromIndex(filenames ...string) error {
buffer := new(bytes.Buffer)
for _, file := range filenames {
if file != "" {
- buffer.WriteString("0 0000000000000000000000000000000000000000\t")
+ buffer.WriteString("0 ")
+ buffer.WriteString(repo.objectFormat.Empty().String())
+ buffer.WriteByte('\t')
buffer.WriteString(file)
buffer.WriteByte('\000')
}
@@ -109,7 +116,7 @@ func (repo *Repository) RemoveFilesFromIndex(filenames ...string) error {
}
// 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
@@ -121,7 +128,7 @@ func (repo *Repository) WriteTree() (*Tree, error) {
if runErr != nil {
return nil, runErr
}
- id, err := NewIDFromString(strings.TrimSpace(stdout))
+ id, err := repo.objectFormat.NewIDFromString(strings.TrimSpace(stdout))
if err != nil {
return nil, err
}
diff --git a/modules/git/repo_language_stats_nogogit.go b/modules/git/repo_language_stats_nogogit.go
index 1d94ad6c00..b733c119f9 100644
--- a/modules/git/repo_language_stats_nogogit.go
+++ b/modules/git/repo_language_stats_nogogit.go
@@ -39,7 +39,7 @@ func (repo *Repository) GetLanguageStats(commitID string) (map[string]int64, err
return nil, ErrNotExist{commitID, ""}
}
- sha, err := NewIDFromString(string(shaBytes))
+ sha, err := repo.objectFormat.NewIDFromString(string(shaBytes))
if err != nil {
log.Debug("Unable to get commit for: %s. Err: %v", commitID, err)
return nil, ErrNotExist{commitID, ""}
diff --git a/modules/git/repo_object.go b/modules/git/repo_object.go
index 9edc201fea..220fdb3807 100644
--- a/modules/git/repo_object.go
+++ b/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 := IDFromString(str)
if err != nil {
- return SHA1{}, err
+ return nil, err
}
- return NewIDFromString(idStr)
+
+ repo.objectFormat = hash.Type()
+
+ return repo.objectFormat, nil
}
-func (repo *Repository) hashObject(reader io.Reader) (string, error) {
- cmd := NewCommand(repo.Ctx, "hash-object", "-w", "--stdin")
+// 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 repo.objectFormat.NewIDFromString(idStr)
+}
+
+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{
diff --git a/modules/git/repo_ref_gogit.go b/modules/git/repo_ref_gogit.go
index 8a68a4574f..fc43ce5545 100644
--- a/modules/git/repo_ref_gogit.go
+++ b/modules/git/repo_ref_gogit.go
@@ -30,13 +30,13 @@ func (repo *Repository) GetRefsFiltered(pattern string) ([]*Reference, error) {
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,
}
diff --git a/modules/git/repo_ref_nogogit.go b/modules/git/repo_ref_nogogit.go
index ac53d661b5..c1be60871c 100644
--- a/modules/git/repo_ref_nogogit.go
+++ b/modules/git/repo_ref_nogogit.go
@@ -75,7 +75,7 @@ func (repo *Repository) GetRefsFiltered(pattern string) ([]*Reference, error) {
if pattern == "" || strings.HasPrefix(refName, pattern) {
r := &Reference{
Name: refName,
- Object: MustIDFromString(sha),
+ Object: repo.objectFormat.MustIDFromString(sha),
Type: typ,
repo: repo,
}
diff --git a/modules/git/repo_tag.go b/modules/git/repo_tag.go
index ae877f0211..0b08e457cb 100644
--- a/modules/git/repo_tag.go
+++ b/modules/git/repo_tag.go
@@ -84,7 +84,7 @@ func (repo *Repository) GetTag(name string) (*Tag, error) {
return nil, err
}
- id, err := NewIDFromString(idStr)
+ id, err := repo.objectFormat.NewIDFromString(idStr)
if err != nil {
return nil, err
}
@@ -98,7 +98,7 @@ func (repo *Repository) GetTag(name string) (*Tag, error) {
// GetTagWithID returns a Git tag by given name and ID
func (repo *Repository) GetTagWithID(idStr, name string) (*Tag, error) {
- id, err := NewIDFromString(idStr)
+ id, err := repo.objectFormat.NewIDFromString(idStr)
if err != nil {
return nil, err
}
@@ -139,7 +139,7 @@ func (repo *Repository) GetTagInfos(page, pageSize int) ([]*Tag, int, error) {
break
}
- tag, err := parseTagRef(ref)
+ tag, err := parseTagRef(repo.objectFormat, ref)
if err != nil {
return nil, 0, fmt.Errorf("GetTagInfos: parse tag: %w", err)
}
@@ -159,13 +159,13 @@ func (repo *Repository) GetTagInfos(page, pageSize int) ([]*Tag, int, error) {
}
// 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:short"],
}
- tag.ID, err = NewIDFromString(ref["objectname"])
+ tag.ID, err = objectFormat.NewIDFromString(ref["objectname"])
if err != nil {
return nil, fmt.Errorf("parse objectname '%s': %w", ref["objectname"], err)
}
@@ -175,7 +175,7 @@ func parseTagRef(ref map[string]string) (tag *Tag, err error) {
tag.Object = tag.ID
} else {
// annotated tag
- tag.Object, err = NewIDFromString(ref["object"])
+ tag.Object, err = objectFormat.NewIDFromString(ref["object"])
if err != nil {
return nil, fmt.Errorf("parse object '%s': %w", ref["object"], err)
}
@@ -208,7 +208,7 @@ func parseTagRef(ref map[string]string) (tag *Tag, err error) {
// GetAnnotatedTag returns a Git tag by its SHA, must be an annotated tag
func (repo *Repository) GetAnnotatedTag(sha string) (*Tag, error) {
- id, err := NewIDFromString(sha)
+ id, err := repo.objectFormat.NewIDFromString(sha)
if err != nil {
return nil, err
}
diff --git a/modules/git/repo_tag_gogit.go b/modules/git/repo_tag_gogit.go
index 2bc75e7cf9..c3711ba5a0 100644
--- a/modules/git/repo_tag_gogit.go
+++ b/modules/git/repo_tag_gogit.go
@@ -55,9 +55,9 @@ func (repo *Repository) GetTags(skip, limit int) ([]string, error) {
}
// 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 SHA1) (string, error) {
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)
@@ -88,7 +88,7 @@ func (repo *Repository) getTag(tagID SHA1, name string) (*Tag, error) {
// every tag should have a commit ID so return all errors
return nil, err
}
- commitID, err := NewIDFromString(commitIDStr)
+ commitID, err := IDFromString(commitIDStr)
if err != nil {
return nil, err
}
@@ -112,7 +112,7 @@ func (repo *Repository) getTag(tagID SHA1, name string) (*Tag, error) {
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 SHA1, name string) (*Tag, error) {
tag := &Tag{
Name: name,
ID: tagID,
- Object: gogitTag.Target,
+ Object: commitID.Type().MustID(gogitTag.Target[:]),
Type: tp,
Tagger: &gogitTag.Tagger,
Message: gogitTag.Message,
diff --git a/modules/git/repo_tag_nogogit.go b/modules/git/repo_tag_nogogit.go
index 9080ffcfd7..3cea4894f1 100644
--- a/modules/git/repo_tag_nogogit.go
+++ b/modules/git/repo_tag_nogogit.go
@@ -30,7 +30,7 @@ func (repo *Repository) GetTags(skip, limit int) (tags []string, err error) {
}
// 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 SHA1) (string, error) {
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)
@@ -64,7 +64,7 @@ func (repo *Repository) getTag(tagID SHA1, name string) (*Tag, error) {
// every tag should have a commit ID so return all errors
return nil, err
}
- commitID, err := NewIDFromString(commitIDStr)
+ commitID, err := repo.objectFormat.NewIDFromString(commitIDStr)
if err != nil {
return nil, err
}
@@ -117,7 +117,7 @@ func (repo *Repository) getTag(tagID SHA1, name string) (*Tag, error) {
return nil, err
}
- tag, err := parseTagData(data)
+ tag, err := parseTagData(tagID.Type(), data)
if err != nil {
return nil, err
}
diff --git a/modules/git/repo_tag_test.go b/modules/git/repo_tag_test.go
index 4d94efd1ac..c7699f4a7d 100644
--- a/modules/git/repo_tag_test.go
+++ b/modules/git/repo_tag_test.go
@@ -194,6 +194,7 @@ func TestRepository_GetAnnotatedTag(t *testing.T) {
}
func TestRepository_parseTagRef(t *testing.T) {
+ sha1 := ObjectFormatFromID(Sha1)
tests := []struct {
name string
@@ -223,8 +224,8 @@ func TestRepository_parseTagRef(t *testing.T) {
want: &Tag{
Name: "v1.9.1",
- ID: MustIDFromString("ab23e4b7f4cd0caafe0174c0e7ef6d651ba72889"),
- Object: MustIDFromString("ab23e4b7f4cd0caafe0174c0e7ef6d651ba72889"),
+ ID: sha1.MustIDFromString("ab23e4b7f4cd0caafe0174c0e7ef6d651ba72889"),
+ Object: sha1.MustIDFromString("ab23e4b7f4cd0caafe0174c0e7ef6d651ba72889"),
Type: "commit",
Tagger: parseAuthorLine(t, "Foo Bar <foo@bar.com> 1565789218 +0300"),
Message: "Add changelog of v1.9.1 (#7859)\n\n* add changelog of v1.9.1\n* Update CHANGELOG.md\n",
@@ -252,8 +253,8 @@ func TestRepository_parseTagRef(t *testing.T) {
want: &Tag{
Name: "v0.0.1",
- ID: MustIDFromString("8c68a1f06fc59c655b7e3905b159d761e91c53c9"),
- Object: MustIDFromString("3325fd8a973321fd59455492976c042dde3fd1ca"),
+ ID: sha1.MustIDFromString("8c68a1f06fc59c655b7e3905b159d761e91c53c9"),
+ Object: sha1.MustIDFromString("3325fd8a973321fd59455492976c042dde3fd1ca"),
Type: "tag",
Tagger: parseAuthorLine(t, "Foo Bar <foo@bar.com> 1565789218 +0300"),
Message: "Add changelog of v1.9.1 (#7859)\n\n* add changelog of v1.9.1\n* Update CHANGELOG.md\n",
@@ -310,8 +311,8 @@ qbHDASXl
want: &Tag{
Name: "v0.0.1",
- ID: MustIDFromString("8c68a1f06fc59c655b7e3905b159d761e91c53c9"),
- Object: MustIDFromString("3325fd8a973321fd59455492976c042dde3fd1ca"),
+ ID: sha1.MustIDFromString("8c68a1f06fc59c655b7e3905b159d761e91c53c9"),
+ Object: sha1.MustIDFromString("3325fd8a973321fd59455492976c042dde3fd1ca"),
Type: "tag",
Tagger: parseAuthorLine(t, "Foo Bar <foo@bar.com> 1565789218 +0300"),
Message: "Add changelog of v1.9.1 (#7859)\n\n* add changelog of v1.9.1\n* Update CHANGELOG.md",
@@ -350,7 +351,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)
diff --git a/modules/git/repo_tree.go b/modules/git/repo_tree.go
index 63c33379bf..9ee80351f0 100644
--- a/modules/git/repo_tree.go
+++ b/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(author, committer *Signature, tree *Tree, opt
Stderr: stderr,
})
if err != nil {
- return SHA1{}, ConcatenateError(err, stderr.String())
+ return nil, ConcatenateError(err, stderr.String())
}
- return NewIDFromString(strings.TrimSpace(stdout.String()))
+ return repo.objectFormat.NewIDFromString(strings.TrimSpace(stdout.String()))
}
diff --git a/modules/git/repo_tree_gogit.go b/modules/git/repo_tree_gogit.go
index a7b1081b15..415572e65a 100644
--- a/modules/git/repo_tree_gogit.go
+++ b/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) (*Tree, error) {
// 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
@@ -28,14 +30,14 @@ func (repo *Repository) GetTree(idStr string) (*Tree, error) {
idStr = res[:len(res)-1]
}
}
- id, err := NewIDFromString(idStr)
+ id, err := repo.objectFormat.NewIDFromString(idStr)
if err != nil {
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 {
diff --git a/modules/git/repo_tree_nogogit.go b/modules/git/repo_tree_nogogit.go
index 4fd77df2b8..f502cc140b 100644
--- a/modules/git/repo_tree_nogogit.go
+++ b/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) (*Tree, error) {
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) (*Tree, error) {
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
}
@@ -66,7 +66,7 @@ func (repo *Repository) getTree(id SHA1) (*Tree, error) {
// 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
@@ -75,7 +75,7 @@ func (repo *Repository) GetTree(idStr string) (*Tree, error) {
idStr = res
}
}
- id, err := NewIDFromString(idStr)
+ id, err := repo.objectFormat.NewIDFromString(idStr)
if err != nil {
return nil, err
}
diff --git a/modules/git/sha1.go b/modules/git/sha1.go
deleted file mode 100644
index 8d6403e865..0000000000
--- a/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)
-}
diff --git a/modules/git/sha1_gogit.go b/modules/git/sha1_gogit.go
deleted file mode 100644
index 28f35d17a9..0000000000
--- a/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)
-}
diff --git a/modules/git/sha1_nogogit.go b/modules/git/sha1_nogogit.go
deleted file mode 100644
index d818d86a3a..0000000000
--- a/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
-}
diff --git a/modules/git/sha1_test.go b/modules/git/sha1_test.go
deleted file mode 100644
index db2944fc53..0000000000
--- a/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"))
-}
diff --git a/modules/git/tag.go b/modules/git/tag.go
index d0ddef64e0..27358d74f8 100644
--- a/modules/git/tag.go
+++ b/modules/git/tag.go
@@ -17,8 +17,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
@@ -33,8 +33,10 @@ func (tag *Tag) Commit(gitRepo *Repository) (*Commit, error) {
// 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.NewEmptyID()
+ tag.Object = objectFormat.NewEmptyID()
tag.Tagger = &Signature{}
// we now have the contents of the commit object. Let's investigate...
nextline := 0
@@ -48,7 +50,7 @@ l:
reftype := line[:spacepos]
switch string(reftype) {
case "object":
- id, err := NewIDFromString(string(line[spacepos+1:]))
+ id, err := objectFormat.NewIDFromString(string(line[spacepos+1:]))
if err != nil {
return nil, err
}
diff --git a/modules/git/tag_test.go b/modules/git/tag_test.go
index 2337e69c6a..129c1e3a02 100644
--- a/modules/git/tag_test.go
+++ b/modules/git/tag_test.go
@@ -22,8 +22,8 @@ tagger Lucas Michot <lucas@semalead.com> 1484491741 +0100
`), 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: NewSha1(),
+ 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: NewSha1(),
+ 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(ObjectFormatFromID(Sha1), test.data)
assert.NoError(t, err)
assert.EqualValues(t, test.tag.ID, tag.ID)
assert.EqualValues(t, test.tag.Object, tag.Object)
diff --git a/modules/git/tree.go b/modules/git/tree.go
index 856b8cef53..1da4a9fa5d 100644
--- a/modules/git/tree.go
+++ b/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,
diff --git a/modules/git/tree_blob_gogit.go b/modules/git/tree_blob_gogit.go
index f1afc5d0a6..92c25cb92c 100644
--- a/modules/git/tree_blob_gogit.go
+++ b/modules/git/tree_blob_gogit.go
@@ -24,7 +24,7 @@ func (t *Tree) GetTreeEntryByPath(relpath string) (*TreeEntry, error) {
gogitTreeEntry: &object.TreeEntry{
Name: "",
Mode: filemode.Dir,
- Hash: t.ID,
+ Hash: plumbing.Hash(t.ID.RawValue()),
},
}, nil
}
diff --git a/modules/git/tree_entry_gogit.go b/modules/git/tree_entry_gogit.go
index 194dd12f7d..eb9b012681 100644
--- a/modules/git/tree_entry_gogit.go
+++ b/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(),
}
diff --git a/modules/git/tree_entry_nogogit.go b/modules/git/tree_entry_nogogit.go
index cda755886a..89244e27ee 100644
--- a/modules/git/tree_entry_nogogit.go
+++ b/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
diff --git a/modules/git/tree_gogit.go b/modules/git/tree_gogit.go
index fa601e6533..421b0ecb0f 100644
--- a/modules/git/tree_gogit.go
+++ b/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, error) {
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) ListEntriesRecursiveWithSize() (Entries, error) {
}
convertedEntry := &TreeEntry{
- ID: entry.Hash,
+ ID: ParseGogitHash(entry.Hash),
gogitTreeEntry: &entry,
ptree: t,
fullName: fullName,
diff --git a/modules/git/tree_nogogit.go b/modules/git/tree_nogogit.go
index ef598d7e91..89d3aebbc0 100644
--- a/modules/git/tree_nogogit.go
+++ b/modules/git/tree_nogogit.go
@@ -13,8 +13,8 @@ import (
// Tree represents a flat directory listing.
type Tree struct {
- ID SHA1
- ResolvedID SHA1
+ ID ObjectID
+ ResolvedID ObjectID
repo *Repository
// parent tree
@@ -54,7 +54,7 @@ func (t *Tree) ListEntries() (Entries, error) {
}
}
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
}
@@ -90,7 +90,7 @@ func (t *Tree) ListEntries() (Entries, error) {
}
var err error
- t.entries, err = parseTreeEntries(stdout, t)
+ t.entries, err = parseTreeEntries(t.repo.objectFormat, stdout, t)
if err == nil {
t.entriesParsed = true
}
@@ -114,7 +114,7 @@ func (t *Tree) listEntriesRecursive(extraArgs TrustedCmdArgs) (Entries, error) {
}
var err error
- t.entriesRecursive, err = parseTreeEntries(stdout, t)
+ t.entriesRecursive, err = parseTreeEntries(t.repo.objectFormat, stdout, t)
if err == nil {
t.entriesRecursiveParsed = true
}
diff --git a/modules/indexer/code/git.go b/modules/indexer/code/git.go
index e4686fa01f..76cd78e11e 100644
--- a/modules/indexer/code/git.go
+++ b/modules/indexer/code/git.go
@@ -62,8 +62,8 @@ func isIndexable(entry *git.TreeEntry) bool {
}
// 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, repo *repo_model.Repository, revision s
}
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.Context, repo *repo_model.Repository, revisio
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
}
diff --git a/modules/repository/commits_test.go b/modules/repository/commits_test.go
index 827b2a9849..57f0c90fc6 100644
--- a/modules/repository/commits_test.go
+++ b/modules/repository/commits_test.go
@@ -144,7 +144,7 @@ func TestCommitToPushCommit(t *testing.T) {
When: now,
}
const hexString = "0123456789abcdef0123456789abcdef01234567"
- sha1, err := git.NewIDFromString(hexString)
+ sha1, err := git.IDFromString(hexString)
assert.NoError(t, err)
pushCommit := CommitToPushCommit(&git.Commit{
ID: sha1,
@@ -169,11 +169,12 @@ func TestListToPushCommits(t *testing.T) {
When: now,
}
+ hashType := git.ObjectFormatFromID(git.Sha1)
const hexString1 = "0123456789abcdef0123456789abcdef01234567"
- hash1, err := git.NewIDFromString(hexString1)
+ hash1, err := hashType.NewIDFromString(hexString1)
assert.NoError(t, err)
const hexString2 = "fedcba9876543210fedcba9876543210fedcba98"
- hash2, err := git.NewIDFromString(hexString2)
+ hash2, err := hashType.NewIDFromString(hexString2)
assert.NoError(t, err)
l := []*git.Commit{
diff --git a/modules/repository/generate.go b/modules/repository/generate.go
index 4055029d22..c143431b7c 100644
--- a/modules/repository/generate.go
+++ b/modules/repository/generate.go
@@ -223,7 +223,8 @@ func generateRepoCommit(ctx context.Context, repo, templateRepo, generateRepo *r
}
}
- if err := git.InitRepository(ctx, tmpDir, false); err != nil {
+ // FIXME: fix the hash
+ if err := git.InitRepository(ctx, tmpDir, false, git.ObjectFormatFromID(git.Sha1)); err != nil {
return err
}
@@ -356,7 +357,8 @@ func GenerateRepository(ctx context.Context, doer, owner *user_model.User, templ
}
}
- if err = CheckInitRepository(ctx, owner.Name, generateRepo.Name); err != nil {
+ // FIXME - fix the hash
+ if err = CheckInitRepository(ctx, owner.Name, generateRepo.Name, git.ObjectFormatFromID(git.Sha1)); err != nil {
return generateRepo, err
}
diff --git a/modules/repository/init.go b/modules/repository/init.go
index 6f791f742b..a9b5aab16a 100644
--- a/modules/repository/init.go
+++ b/modules/repository/init.go
@@ -188,7 +188,7 @@ func InitRepoCommit(ctx context.Context, tmpPath string, repo *repo_model.Reposi
return nil
}
-func CheckInitRepository(ctx context.Context, owner, name string) (err error) {
+func CheckInitRepository(ctx context.Context, owner, name string, objectFormat git.ObjectFormat) (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.Context, owner, name string) (err error) {
}
// Init git bare new repository.
- if err = git.InitRepository(ctx, repoPath, true); err != nil {
+ if err = git.InitRepository(ctx, repoPath, true, objectFormat); err != nil {
return fmt.Errorf("git.InitRepository: %w", err)
} else if err = CreateDelegateHooks(repoPath); err != nil {
return fmt.Errorf("createDelegateHooks: %w", err)
diff --git a/modules/repository/push.go b/modules/repository/push.go
index ea03f9e153..25695336a5 100644
--- a/modules/repository/push.go
+++ b/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.IDFromString(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.IDFromString(opts.NewCommitID)
+ return err == nil && commitID.IsZero()
}
// IsUpdateRef return true if it's an update operation