diff --git a/modules/git/error.go b/modules/git/error.go index dc10d451b3bbf..eda8d479c0e2e 100644 --- a/modules/git/error.go +++ b/modules/git/error.go @@ -46,6 +46,22 @@ func (err ErrNotExist) Unwrap() error { return util.ErrNotExist } +// ErrWrongType git object with wrong type +type ErrWrongType struct { + ID string + Type string +} + +// IsErrWrongType if some error is ErrWrongType +func IsErrWrongType(err error) bool { + _, ok := err.(ErrWrongType) + return ok +} + +func (err ErrWrongType) Error() string { + return fmt.Sprintf("git object type is invalid [id: %s, type: %s]", err.ID, err.Type) +} + // ErrBadLink entry.FollowLink error type ErrBadLink struct { Name string diff --git a/modules/git/repo_commit_gogit.go b/modules/git/repo_commit_gogit.go index ce0af936140db..2a9a547fe0e93 100644 --- a/modules/git/repo_commit_gogit.go +++ b/modules/git/repo_commit_gogit.go @@ -9,6 +9,8 @@ package git import ( "strings" + "code.gitea.io/gitea/modules/log" + "github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing/object" ) @@ -66,26 +68,57 @@ func (repo *Repository) IsCommitExist(name string) bool { return err == nil } -func (repo *Repository) getCommit(id SHA1) (*Commit, error) { - var tagObject *object.Tag - - gogitCommit, err := repo.gogitRepo.CommitObject(id) - if err == plumbing.ErrObjectNotFound { - tagObject, err = repo.gogitRepo.TagObject(id) - if err == plumbing.ErrObjectNotFound { - return nil, ErrNotExist{ - ID: id.String(), - } - } - if err == nil { - gogitCommit, err = repo.gogitRepo.CommitObject(tagObject.Target) +func (repo *Repository) getGoGitTagDeepestObject(tag *object.Tag) (object.Object, error) { + obj, err := tag.Object() + if err != nil { + return nil, err + } + if subTag, ok := obj.(*object.Tag); ok { + obj, err = repo.getGoGitTagDeepestObject(subTag) + if err != nil { + return nil, err } - // if we get a plumbing.ErrObjectNotFound here then the repository is broken and it should be 500 } + return obj, nil +} + +func (repo *Repository) getCommit(id SHA1) (*Commit, error) { + var gogitCommit *object.Commit + + obj, err := repo.gogitRepo.Object(plumbing.AnyObject, id) if err != nil { return nil, err } + switch o := obj.(type) { + case *object.Commit: + gogitCommit = o + case *object.Tag: + var ok bool + + obj, err := repo.getGoGitTagDeepestObject(o) + if err != nil { + return nil, err + } + if gogitCommit, ok = obj.(*object.Commit); !ok { + return nil, ErrWrongType{ + ID: obj.ID().String(), + Type: obj.Type().String(), + } + } + + case *object.Blob, *object.Tree: + return nil, ErrWrongType{ + ID: id.String(), + Type: o.Type().String(), + } + default: + log.Debug("Unknown typ: %s", o.Type()) + return nil, ErrNotExist{ + ID: id.String(), + } + } + commit := convertCommit(gogitCommit) commit.repo = repo diff --git a/modules/git/repo_commit_nogogit.go b/modules/git/repo_commit_nogogit.go index d5eb723100a73..fe6951b1b800f 100644 --- a/modules/git/repo_commit_nogogit.go +++ b/modules/git/repo_commit_nogogit.go @@ -119,6 +119,15 @@ func (repo *Repository) getCommitFromBatchReader(rd *bufio.Reader, id SHA1) (*Co } return commit, nil + case "blob", "tree": + _, err = rd.Discard(int(size) + 1) + if err != nil { + return nil, err + } + return nil, ErrWrongType{ + ID: id.String(), + Type: typ, + } default: log.Debug("Unknown typ: %s", typ) _, err = rd.Discard(int(size) + 1) diff --git a/services/repository/push.go b/services/repository/push.go index 355c2878113fd..f818c86a0bfed 100644 --- a/services/repository/push.go +++ b/services/repository/push.go @@ -135,6 +135,10 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error { } else { // is new tag newCommit, err := gitRepo.GetCommit(opts.NewCommitID) if err != nil { + if git.IsErrWrongType(err) { + log.Info("ignore special ref push update: %v", err) + continue + } return fmt.Errorf("gitRepo.GetCommit(%s) in %s/%s[%d]: %w", opts.NewCommitID, repo.OwnerName, repo.Name, repo.ID, err) }