]> source.dussan.org Git - gitea.git/commitdiff
Speed up conflict checking in pull request creation (#276)
authortypeless <typeless@users.noreply.github.com>
Thu, 29 Dec 2016 14:59:52 +0000 (22:59 +0800)
committerLunny Xiao <xiaolunwen@gmail.com>
Thu, 29 Dec 2016 14:59:52 +0000 (22:59 +0800)
* Speed up conflict checking in pull request creation

In order to check conflicts of a PR, we set up a working tree by
cloning the base branch, which is quite time-consuming when the repository is huge.
Instead, this PR uses `git read-tree` and `git apply --check --cached` to check conflicts.

For #258

* Use $GIT_INDEX_FILE instead of --index-output to avoid lockfile problem

The lockfile gets renamed to the final destination after the operation
finishes. But it must be located in the same filesystem, which prevents
us from using /tmp.

* Temporary file names should not prefixed with '-'

models/pull.go

index 9aec3596d430ad8000cc9d8fe94a85a2fa0d69e5..36194d8660b886677f5cb03c26bf6de0df44774e 100644 (file)
@@ -8,6 +8,8 @@ import (
        "fmt"
        "os"
        "path"
+       "path/filepath"
+       "strconv"
        "strings"
        "time"
 
@@ -428,17 +430,22 @@ func (pr *PullRequest) testPatch() (err error) {
 
        log.Trace("PullRequest[%d].testPatch (patchPath): %s", pr.ID, patchPath)
 
-       // Delete old temp local copy before we create a new temp local copy
-       RemoveAllWithNotice("Deleting old local copy", pr.BaseRepo.LocalCopyPath())
+       pr.Status = PullRequestStatusChecking
+
+       indexTmpPath := filepath.Join(os.TempDir(), "gitea-"+pr.BaseRepo.Name+"-"+strconv.Itoa(time.Now().Nanosecond()))
+       defer os.Remove(indexTmpPath)
 
-       if err := pr.BaseRepo.UpdateLocalCopyBranch(pr.BaseBranch); err != nil {
-               return fmt.Errorf("UpdateLocalCopy: %v", err)
+       var stderr string
+       _, stderr, err = process.ExecDirEnv(-1, "", fmt.Sprintf("testPatch (git read-tree): %d", pr.BaseRepo.ID),
+               []string{"GIT_DIR=" + pr.BaseRepo.RepoPath(), "GIT_INDEX_FILE=" + indexTmpPath},
+               "git", "read-tree", pr.BaseBranch)
+       if err != nil {
+               return fmt.Errorf("git read-tree --index-output=%s %s: %v - %s", indexTmpPath, pr.BaseBranch, err, stderr)
        }
 
-       pr.Status = PullRequestStatusChecking
-       _, stderr, err := process.ExecDir(-1, pr.BaseRepo.LocalCopyPath(),
-               fmt.Sprintf("testPatch (git apply --check): %d", pr.BaseRepo.ID),
-               "git", "apply", "--check", patchPath)
+       _, stderr, err = process.ExecDirEnv(-1, "", fmt.Sprintf("testPatch (git apply --check): %d", pr.BaseRepo.ID),
+               []string{"GIT_INDEX_FILE=" + indexTmpPath, "GIT_DIR=" + pr.BaseRepo.RepoPath()},
+               "git", "apply", "--check", "--cached", patchPath)
        if err != nil {
                for i := range patchConflicts {
                        if strings.Contains(stderr, patchConflicts[i]) {