mirror of
				https://github.com/go-gitea/gitea
				synced 2025-10-30 19:08:37 +00:00 
			
		
		
		
	Partially fix #32018 `git config` and `git remote` write operations create a temporary file named `config.lock`. Since these operations are not atomic, they must not be run in parallel. If two requests attempt to modify the same repository concurrently—such as during a compare operation—one may fail due to the presence of an existing `config.lock` file. In cases where `config.lock` is left behind due to an unexpected program exit, a global lock mechanism could allow us to safely remove the stale lock file when a related error is detected. While this behavior is not yet implemented in this PR, it is planned for a future enhancement. --------- Signed-off-by: wxiaoguang <wxiaoguang@gmail.com> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
		
			
				
	
	
		
			96 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			96 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2025 The Gitea Authors. All rights reserved.
 | |
| // SPDX-License-Identifier: MIT
 | |
| 
 | |
| package pull
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"fmt"
 | |
| 	"strconv"
 | |
| 	"time"
 | |
| 
 | |
| 	repo_model "code.gitea.io/gitea/models/repo"
 | |
| 	"code.gitea.io/gitea/modules/git"
 | |
| 	"code.gitea.io/gitea/modules/gitrepo"
 | |
| 	"code.gitea.io/gitea/modules/graceful"
 | |
| 	logger "code.gitea.io/gitea/modules/log"
 | |
| )
 | |
| 
 | |
| // CompareInfo represents needed information for comparing references.
 | |
| type CompareInfo struct {
 | |
| 	MergeBase    string
 | |
| 	BaseCommitID string
 | |
| 	HeadCommitID string
 | |
| 	Commits      []*git.Commit
 | |
| 	NumFiles     int
 | |
| }
 | |
| 
 | |
| // GetCompareInfo generates and returns compare information between base and head branches of repositories.
 | |
| func GetCompareInfo(ctx context.Context, baseRepo, headRepo *repo_model.Repository, headGitRepo *git.Repository, baseBranch, headBranch string, directComparison, fileOnly bool) (_ *CompareInfo, err error) {
 | |
| 	var (
 | |
| 		remoteBranch string
 | |
| 		tmpRemote    string
 | |
| 	)
 | |
| 
 | |
| 	// We don't need a temporary remote for same repository.
 | |
| 	if headGitRepo.Path != baseRepo.RepoPath() {
 | |
| 		// Add a temporary remote
 | |
| 		tmpRemote = strconv.FormatInt(time.Now().UnixNano(), 10)
 | |
| 		if err = gitrepo.GitRemoteAdd(ctx, headRepo, tmpRemote, baseRepo.RepoPath()); err != nil {
 | |
| 			return nil, fmt.Errorf("GitRemoteAdd: %w", err)
 | |
| 		}
 | |
| 		defer func() {
 | |
| 			if err := gitrepo.GitRemoteRemove(graceful.GetManager().ShutdownContext(), headRepo, tmpRemote); err != nil {
 | |
| 				logger.Error("GetPullRequestInfo: GitRemoteRemove: %v", err)
 | |
| 			}
 | |
| 		}()
 | |
| 	}
 | |
| 
 | |
| 	compareInfo := new(CompareInfo)
 | |
| 
 | |
| 	compareInfo.HeadCommitID, err = git.GetFullCommitID(ctx, headGitRepo.Path, headBranch)
 | |
| 	if err != nil {
 | |
| 		compareInfo.HeadCommitID = headBranch
 | |
| 	}
 | |
| 
 | |
| 	compareInfo.MergeBase, remoteBranch, err = headGitRepo.GetMergeBase(tmpRemote, baseBranch, headBranch)
 | |
| 	if err == nil {
 | |
| 		compareInfo.BaseCommitID, err = git.GetFullCommitID(ctx, headGitRepo.Path, remoteBranch)
 | |
| 		if err != nil {
 | |
| 			compareInfo.BaseCommitID = remoteBranch
 | |
| 		}
 | |
| 		separator := "..."
 | |
| 		baseCommitID := compareInfo.MergeBase
 | |
| 		if directComparison {
 | |
| 			separator = ".."
 | |
| 			baseCommitID = compareInfo.BaseCommitID
 | |
| 		}
 | |
| 
 | |
| 		// We have a common base - therefore we know that ... should work
 | |
| 		if !fileOnly {
 | |
| 			compareInfo.Commits, err = headGitRepo.ShowPrettyFormatLogToList(ctx, baseCommitID+separator+headBranch)
 | |
| 			if err != nil {
 | |
| 				return nil, fmt.Errorf("ShowPrettyFormatLogToList: %w", err)
 | |
| 			}
 | |
| 		} else {
 | |
| 			compareInfo.Commits = []*git.Commit{}
 | |
| 		}
 | |
| 	} else {
 | |
| 		compareInfo.Commits = []*git.Commit{}
 | |
| 		compareInfo.MergeBase, err = git.GetFullCommitID(ctx, headGitRepo.Path, remoteBranch)
 | |
| 		if err != nil {
 | |
| 			compareInfo.MergeBase = remoteBranch
 | |
| 		}
 | |
| 		compareInfo.BaseCommitID = compareInfo.MergeBase
 | |
| 	}
 | |
| 
 | |
| 	// Count number of changed files.
 | |
| 	// This probably should be removed as we need to use shortstat elsewhere
 | |
| 	// Now there is git diff --shortstat but this appears to be slower than simply iterating with --nameonly
 | |
| 	compareInfo.NumFiles, err = headGitRepo.GetDiffNumChangedFiles(remoteBranch, headBranch, directComparison)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	return compareInfo, nil
 | |
| }
 |