Skip to content

Conversation

lunny
Copy link
Member

@lunny lunny commented Jul 24, 2025

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.

…lve possible conflict when updating repository git config file
@lunny lunny added the type/bug label Jul 24, 2025
@GiteaBot GiteaBot added the lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. label Jul 24, 2025
@github-actions github-actions bot added modifies/api This PR adds API routes or modifies them modifies/go Pull requests that update Go code labels Jul 24, 2025
@wxiaoguang
Copy link
Contributor

No, it doesn't fix #32018

Copy link
Contributor

@wxiaoguang wxiaoguang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't see why it is worth or right to do so, and don't see why it fixes that issue

@GiteaBot GiteaBot added lgtm/blocked A maintainer has reservations with the PR and thus it cannot be merged and removed lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. labels Jul 24, 2025
@lunny
Copy link
Member Author

lunny commented Jul 24, 2025

Don't see why it is worth or right to do so, and don't see why it fixes that issue

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.

@wxiaoguang
Copy link
Contributor

wxiaoguang commented Jul 25, 2025

So it is an improvement but doesn't "Fix #32018", right?

But does it really need the "global lock"? Is it possible that git already uses "*.lock" files by flock for global lock? Then Gitea shouldn't do anything more?

@lunny
Copy link
Member Author

lunny commented Jul 25, 2025

So it is an improvement but doesn't "Fix #32018", right?

But does it really need the "global lock"? Is it possible that git already uses "*.lock" files by flock for global lock? Then Gitea shouldn't do anything more?

The Git command-line interface is primarily designed for human interaction. When a git config write operation is initiated and a config.lock file is created, any subsequent git config write operation will immediately fail instead of waiting for the first one to complete.

While I couldn’t find official documentation confirming this behavior, the implementation can be found in the Git source code here:
https://github.com/git/git/blob/97e14d99f6def189b0f786ac6207b792ca3197b1/config.c#L3199

Based on this, it appears that Git does not implement a locking mechanism that causes subsequent operations to wait—it simply fails fast.

I believe this change partially addresses #32018, as there are three possible causes for the issue:

  • Concurrent requests attempting to compare between the same base and forked repositories.
  • A Git command exits unexpectedly, leaving behind a config.lock file. I plan to implement automatic cleanup of stale config.lock files in another PR, which would help resolve this case.
  • An administrator manually runs Git commands on the Gitea server. This scenario is outside the scope of this PR, and I don’t believe it’s something we can reliably handle within the application.

@wxiaoguang
Copy link
Contributor

wxiaoguang commented Jul 25, 2025

Git already does a file-based "global lock"

https://github.com/git/git/blob/master/lockfile.c#L104 (config.c hold_lock_file_for_update -> lockfile.c lock_file_timeout )

I do not think this PR is worth or right.


Update: git passes timeout=0, so it only locks "once"

@wxiaoguang wxiaoguang dismissed their stale review July 25, 2025 02:28

dismiss

@GiteaBot GiteaBot added lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. and removed lgtm/blocked A maintainer has reservations with the PR and thus it cannot be merged labels Jul 25, 2025
@wxiaoguang wxiaoguang marked this pull request as draft July 25, 2025 03:15
@lunny lunny marked this pull request as ready for review July 26, 2025 18:06
@lunny lunny requested a review from wxiaoguang July 26, 2025 18:06
@lunny
Copy link
Member Author

lunny commented Aug 19, 2025

last call @go-gitea/technical-oversight-committee

Copy link
Member

@6543 6543 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looking forward to some abstraction layer to better scale

@GiteaBot GiteaBot added lgtm/done This PR has enough approvals to get merged. There are no important open reservations anymore. and removed lgtm/need 1 This PR needs approval from one additional maintainer to be merged. labels Aug 28, 2025
return giturl.ParseGitURL(addr)
}

func SetRemoteURL(ctx context.Context, repo Repository, remoteName, remoteURL string) error {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be named as GitRemoteSetURL to match other functions and the command itself git remote set-url

}

// GitRemoteUpdatePrune updates the remote branches and prunes the ones that no longer exist in the remote repository.
// No lock is needed because the remote remoteName will be checked before invoking this function.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is the "remoteName will be checked"?

}

// GitRemotePrune prunes the remote branches that no longer exist in the remote repository.
// No lock is needed because the remote remoteName will be checked before invoking this function.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is the "remoteName will be checked"?

return "", err
}
if len(result) > 0 {
result = result[:len(result)-1] // remove trailing newline
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it also true for Windows? \r\n or only \n?

_, err := git.GetRemoteAddress(ctx, m.Repo.WikiPath(), m.RemoteName)
if err == nil {
u, err := gitrepo.GitRemoteGetURL(ctx, m.Repo.WikiStorageRepo(), m.RemoteName)
if err == nil && u != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if err is nil, then u isn't nil

}
defer func() {
if err := repo.RemoveRemote(tmpRemote); err != nil {
log.Error("getMergeBase: RemoveRemote: %v", err)
if err := gitrepo.GitRemoteRemove(ctx, repo, tmpRemote); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it can use ctx here. In this defer, the ctx might have been canceled.

return nil, fmt.Errorf("GitRemoteAdd: %w", err)
}
defer func() {
if err := gitrepo.GitRemoteRemove(ctx, headRepo, tmpRemote); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above, it can't use ctx

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
lgtm/done This PR has enough approvals to get merged. There are no important open reservations anymore. modifies/api This PR adds API routes or modifies them modifies/go Pull requests that update Go code type/bug
Projects
None yet
Development

Successfully merging this pull request may close these issues.

GetCompareInfo, AddRemote: exit status 128 - error: could not lock config file config: File exists
5 participants