0
0
mirror of https://github.com/go-gitea/gitea.git synced 2026-01-20 20:05:19 +01:00

Fix parally problem

This commit is contained in:
Lunny Xiao 2026-01-13 17:20:30 -08:00
parent b34b0e5add
commit 791bd4325e
No known key found for this signature in database
GPG Key ID: C3B7C91B632F738A
4 changed files with 30 additions and 9 deletions

View File

@ -7,6 +7,7 @@ import (
"context"
"code.gitea.io/gitea/modules/git/gitcmd"
"code.gitea.io/gitea/modules/globallock"
)
// FetchRemoteCommit fetches a specific commit and its related objects from a remote
@ -19,7 +20,9 @@ import (
// This behavior is sufficient for temporary operations, such as determining the
// merge base between commits.
func FetchRemoteCommit(ctx context.Context, repo, remoteRepo Repository, commitID string) error {
return RunCmd(ctx, repo, gitcmd.NewCommand("fetch", "--no-tags").
AddDynamicArguments(repoPath(remoteRepo)).
AddDynamicArguments(commitID))
return globallock.LockAndDo(ctx, getRepoWriteLockKey(repo.RelativePath()), func(ctx context.Context) error {
return RunCmd(ctx, repo, gitcmd.NewCommand("fetch", "--no-tags").
AddDynamicArguments(repoPath(remoteRepo)).
AddDynamicArguments(commitID))
})
}

View File

@ -7,6 +7,7 @@ import (
"context"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/globallock"
)
// PushToExternal pushes a managed repository to an external remote.
@ -16,12 +17,16 @@ func PushToExternal(ctx context.Context, repo Repository, opts git.PushOptions)
// Push pushes from one managed repository to another managed repository.
func Push(ctx context.Context, fromRepo, toRepo Repository, opts git.PushOptions) error {
opts.Remote = repoPath(toRepo)
return git.Push(ctx, repoPath(fromRepo), opts)
return globallock.LockAndDo(ctx, getRepoWriteLockKey(toRepo.RelativePath()), func(ctx context.Context) error {
opts.Remote = repoPath(toRepo)
return git.Push(ctx, repoPath(fromRepo), opts)
})
}
// PushFromLocal pushes from a local path to a managed repository.
func PushFromLocal(ctx context.Context, fromLocalPath string, toRepo Repository, opts git.PushOptions) error {
opts.Remote = repoPath(toRepo)
return git.Push(ctx, fromLocalPath, opts)
return globallock.LockAndDo(ctx, getRepoWriteLockKey(toRepo.RelativePath()), func(ctx context.Context) error {
opts.Remote = repoPath(toRepo)
return git.Push(ctx, fromLocalPath, opts)
})
}

View File

@ -0,0 +1,10 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package gitrepo
// getRepoWriteLockKey returns the global lock key for write operations on the repository.
// Parallel write operations on the same git repository should be avoided to prevent data corruption.
func getRepoWriteLockKey(repoStoragePath string) string {
return "repo-write:" + repoStoragePath
}

View File

@ -65,8 +65,11 @@ func GetCompareInfo(ctx context.Context, baseRepo, headRepo *repo_model.Reposito
// if they are not the same repository, then we need to fetch the base commit into the head repository
// because we will use headGitRepo in the following code
if baseRepo.ID != headRepo.ID {
if err := gitrepo.FetchRemoteCommit(ctx, headRepo, baseRepo, compareInfo.BaseCommitID); err != nil {
return nil, fmt.Errorf("FetchRemoteCommit: %w", err)
exist := headGitRepo.IsCommitExist(compareInfo.BaseCommitID)
if !exist {
if err := gitrepo.FetchRemoteCommit(ctx, headRepo, baseRepo, compareInfo.BaseCommitID); err != nil {
return nil, fmt.Errorf("FetchRemoteCommit: %w", err)
}
}
}