mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 08:30:25 +08:00 
			
		
		
		
	Handle push rejection in branch and upload (#10854)
* Handle push rejections and push out-of-date in branch creation and file upload. * Remove the duplicated sanitize from services/pull/merge * Move the errors Err(Merge)PushOutOfDate and ErrPushRejected to modules/git * Handle errors better in the upload file dialogs Fix #10460 Signed-off-by: Andrew Thornton <art27@cantab.net> Co-authored-by: guillep2k <18600385+guillep2k@users.noreply.github.com>
This commit is contained in:
		@@ -7,7 +7,6 @@ package models
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"strings"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/modules/git"
 | 
						"code.gitea.io/gitea/modules/git"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -1388,71 +1387,6 @@ func (err ErrMergeUnrelatedHistories) Error() string {
 | 
				
			|||||||
	return fmt.Sprintf("Merge UnrelatedHistories Error: %v: %s\n%s", err.Err, err.StdErr, err.StdOut)
 | 
						return fmt.Sprintf("Merge UnrelatedHistories Error: %v: %s\n%s", err.Err, err.StdErr, err.StdOut)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ErrMergePushOutOfDate represents an error if merging fails due to unrelated histories
 | 
					 | 
				
			||||||
type ErrMergePushOutOfDate struct {
 | 
					 | 
				
			||||||
	Style  MergeStyle
 | 
					 | 
				
			||||||
	StdOut string
 | 
					 | 
				
			||||||
	StdErr string
 | 
					 | 
				
			||||||
	Err    error
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// IsErrMergePushOutOfDate checks if an error is a ErrMergePushOutOfDate.
 | 
					 | 
				
			||||||
func IsErrMergePushOutOfDate(err error) bool {
 | 
					 | 
				
			||||||
	_, ok := err.(ErrMergePushOutOfDate)
 | 
					 | 
				
			||||||
	return ok
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (err ErrMergePushOutOfDate) Error() string {
 | 
					 | 
				
			||||||
	return fmt.Sprintf("Merge PushOutOfDate Error: %v: %s\n%s", err.Err, err.StdErr, err.StdOut)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// ErrPushRejected represents an error if merging fails due to rejection from a hook
 | 
					 | 
				
			||||||
type ErrPushRejected struct {
 | 
					 | 
				
			||||||
	Style   MergeStyle
 | 
					 | 
				
			||||||
	Message string
 | 
					 | 
				
			||||||
	StdOut  string
 | 
					 | 
				
			||||||
	StdErr  string
 | 
					 | 
				
			||||||
	Err     error
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// IsErrPushRejected checks if an error is a ErrPushRejected.
 | 
					 | 
				
			||||||
func IsErrPushRejected(err error) bool {
 | 
					 | 
				
			||||||
	_, ok := err.(ErrPushRejected)
 | 
					 | 
				
			||||||
	return ok
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (err ErrPushRejected) Error() string {
 | 
					 | 
				
			||||||
	return fmt.Sprintf("Merge PushRejected Error: %v: %s\n%s", err.Err, err.StdErr, err.StdOut)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// GenerateMessage generates the remote message from the stderr
 | 
					 | 
				
			||||||
func (err *ErrPushRejected) GenerateMessage() {
 | 
					 | 
				
			||||||
	messageBuilder := &strings.Builder{}
 | 
					 | 
				
			||||||
	i := strings.Index(err.StdErr, "remote: ")
 | 
					 | 
				
			||||||
	if i < 0 {
 | 
					 | 
				
			||||||
		err.Message = ""
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	for {
 | 
					 | 
				
			||||||
		if len(err.StdErr) <= i+8 {
 | 
					 | 
				
			||||||
			break
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if err.StdErr[i:i+8] != "remote: " {
 | 
					 | 
				
			||||||
			break
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		i += 8
 | 
					 | 
				
			||||||
		nl := strings.IndexByte(err.StdErr[i:], '\n')
 | 
					 | 
				
			||||||
		if nl >= 0 {
 | 
					 | 
				
			||||||
			messageBuilder.WriteString(err.StdErr[i : i+nl+1])
 | 
					 | 
				
			||||||
			i = i + nl + 1
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			messageBuilder.WriteString(err.StdErr[i:])
 | 
					 | 
				
			||||||
			i = len(err.StdErr)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	err.Message = strings.TrimSpace(messageBuilder.String())
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// ErrRebaseConflicts represents an error if rebase fails with a conflict
 | 
					// ErrRebaseConflicts represents an error if rebase fails with a conflict
 | 
				
			||||||
type ErrRebaseConflicts struct {
 | 
					type ErrRebaseConflicts struct {
 | 
				
			||||||
	Style     MergeStyle
 | 
						Style     MergeStyle
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@ package git
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -85,3 +86,76 @@ func IsErrBranchNotExist(err error) bool {
 | 
				
			|||||||
func (err ErrBranchNotExist) Error() string {
 | 
					func (err ErrBranchNotExist) Error() string {
 | 
				
			||||||
	return fmt.Sprintf("branch does not exist [name: %s]", err.Name)
 | 
						return fmt.Sprintf("branch does not exist [name: %s]", err.Name)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ErrPushOutOfDate represents an error if merging fails due to unrelated histories
 | 
				
			||||||
 | 
					type ErrPushOutOfDate struct {
 | 
				
			||||||
 | 
						StdOut string
 | 
				
			||||||
 | 
						StdErr string
 | 
				
			||||||
 | 
						Err    error
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// IsErrPushOutOfDate checks if an error is a ErrPushOutOfDate.
 | 
				
			||||||
 | 
					func IsErrPushOutOfDate(err error) bool {
 | 
				
			||||||
 | 
						_, ok := err.(*ErrPushOutOfDate)
 | 
				
			||||||
 | 
						return ok
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (err *ErrPushOutOfDate) Error() string {
 | 
				
			||||||
 | 
						return fmt.Sprintf("PushOutOfDate Error: %v: %s\n%s", err.Err, err.StdErr, err.StdOut)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Unwrap unwraps the underlying error
 | 
				
			||||||
 | 
					func (err *ErrPushOutOfDate) Unwrap() error {
 | 
				
			||||||
 | 
						return fmt.Errorf("%v - %s", err.Err, err.StdErr)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ErrPushRejected represents an error if merging fails due to rejection from a hook
 | 
				
			||||||
 | 
					type ErrPushRejected struct {
 | 
				
			||||||
 | 
						Message string
 | 
				
			||||||
 | 
						StdOut  string
 | 
				
			||||||
 | 
						StdErr  string
 | 
				
			||||||
 | 
						Err     error
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// IsErrPushRejected checks if an error is a ErrPushRejected.
 | 
				
			||||||
 | 
					func IsErrPushRejected(err error) bool {
 | 
				
			||||||
 | 
						_, ok := err.(*ErrPushRejected)
 | 
				
			||||||
 | 
						return ok
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (err *ErrPushRejected) Error() string {
 | 
				
			||||||
 | 
						return fmt.Sprintf("PushRejected Error: %v: %s\n%s", err.Err, err.StdErr, err.StdOut)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Unwrap unwraps the underlying error
 | 
				
			||||||
 | 
					func (err *ErrPushRejected) Unwrap() error {
 | 
				
			||||||
 | 
						return fmt.Errorf("%v - %s", err.Err, err.StdErr)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GenerateMessage generates the remote message from the stderr
 | 
				
			||||||
 | 
					func (err *ErrPushRejected) GenerateMessage() {
 | 
				
			||||||
 | 
						messageBuilder := &strings.Builder{}
 | 
				
			||||||
 | 
						i := strings.Index(err.StdErr, "remote: ")
 | 
				
			||||||
 | 
						if i < 0 {
 | 
				
			||||||
 | 
							err.Message = ""
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for {
 | 
				
			||||||
 | 
							if len(err.StdErr) <= i+8 {
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if err.StdErr[i:i+8] != "remote: " {
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							i += 8
 | 
				
			||||||
 | 
							nl := strings.IndexByte(err.StdErr[i:], '\n')
 | 
				
			||||||
 | 
							if nl >= 0 {
 | 
				
			||||||
 | 
								messageBuilder.WriteString(err.StdErr[i : i+nl+1])
 | 
				
			||||||
 | 
								i = i + nl + 1
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								messageBuilder.WriteString(err.StdErr[i:])
 | 
				
			||||||
 | 
								i = len(err.StdErr)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err.Message = strings.TrimSpace(messageBuilder.String())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -255,7 +255,31 @@ func Push(repoPath string, opts PushOptions) error {
 | 
				
			|||||||
		cmd.AddArguments("-f")
 | 
							cmd.AddArguments("-f")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	cmd.AddArguments("--", opts.Remote, opts.Branch)
 | 
						cmd.AddArguments("--", opts.Remote, opts.Branch)
 | 
				
			||||||
	_, err := cmd.RunInDirWithEnv(repoPath, opts.Env)
 | 
						var outbuf, errbuf strings.Builder
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err := cmd.RunInDirTimeoutEnvPipeline(opts.Env, -1, repoPath, &outbuf, &errbuf)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							if strings.Contains(errbuf.String(), "non-fast-forward") {
 | 
				
			||||||
 | 
								return &ErrPushOutOfDate{
 | 
				
			||||||
 | 
									StdOut: outbuf.String(),
 | 
				
			||||||
 | 
									StdErr: errbuf.String(),
 | 
				
			||||||
 | 
									Err:    err,
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else if strings.Contains(errbuf.String(), "! [remote rejected]") {
 | 
				
			||||||
 | 
								err := &ErrPushRejected{
 | 
				
			||||||
 | 
									StdOut: outbuf.String(),
 | 
				
			||||||
 | 
									StdErr: errbuf.String(),
 | 
				
			||||||
 | 
									Err:    err,
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								err.GenerateMessage()
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if errbuf.Len() > 0 && err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("%v - %s", err, errbuf.String())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return err
 | 
						return err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -242,30 +242,21 @@ func (t *TemporaryUploadRepository) CommitTreeWithDate(author, committer *models
 | 
				
			|||||||
func (t *TemporaryUploadRepository) Push(doer *models.User, commitHash string, branch string) error {
 | 
					func (t *TemporaryUploadRepository) Push(doer *models.User, commitHash string, branch string) error {
 | 
				
			||||||
	// Because calls hooks we need to pass in the environment
 | 
						// Because calls hooks we need to pass in the environment
 | 
				
			||||||
	env := models.PushingEnvironment(doer, t.repo)
 | 
						env := models.PushingEnvironment(doer, t.repo)
 | 
				
			||||||
	stdout := &strings.Builder{}
 | 
						if err := git.Push(t.basePath, git.PushOptions{
 | 
				
			||||||
	stderr := &strings.Builder{}
 | 
							Remote: t.repo.RepoPath(),
 | 
				
			||||||
 | 
							Branch: strings.TrimSpace(commitHash) + ":refs/heads/" + strings.TrimSpace(branch),
 | 
				
			||||||
	if err := git.NewCommand("push", t.repo.RepoPath(), strings.TrimSpace(commitHash)+":refs/heads/"+strings.TrimSpace(branch)).RunInDirTimeoutEnvPipeline(env, -1, t.basePath, stdout, stderr); err != nil {
 | 
							Env:    env,
 | 
				
			||||||
		errString := stderr.String()
 | 
						}); err != nil {
 | 
				
			||||||
		if strings.Contains(errString, "non-fast-forward") {
 | 
							if git.IsErrPushOutOfDate(err) {
 | 
				
			||||||
			return models.ErrMergePushOutOfDate{
 | 
								return err
 | 
				
			||||||
				StdOut: stdout.String(),
 | 
							} else if git.IsErrPushRejected(err) {
 | 
				
			||||||
				StdErr: errString,
 | 
								rejectErr := err.(*git.ErrPushRejected)
 | 
				
			||||||
				Err:    err,
 | 
								log.Info("Unable to push back to repo from temporary repo due to rejection: %s (%s)\nStdout: %s\nStderr: %s\nError: %v",
 | 
				
			||||||
			}
 | 
									t.repo.FullName(), t.basePath, rejectErr.StdOut, rejectErr.StdErr, rejectErr.Err)
 | 
				
			||||||
		} else if strings.Contains(errString, "! [remote rejected]") {
 | 
					 | 
				
			||||||
			log.Error("Unable to push back to repo from temporary repo due to rejection: %s (%s)\nStdout: %s\nStderr: %s\nError: %v",
 | 
					 | 
				
			||||||
				t.repo.FullName(), t.basePath, stdout, errString, err)
 | 
					 | 
				
			||||||
			err := models.ErrPushRejected{
 | 
					 | 
				
			||||||
				StdOut: stdout.String(),
 | 
					 | 
				
			||||||
				StdErr: errString,
 | 
					 | 
				
			||||||
				Err:    err,
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			err.GenerateMessage()
 | 
					 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		log.Error("Unable to push back to repo from temporary repo: %s (%s)\nStdout: %s\nError: %v",
 | 
							log.Error("Unable to push back to repo from temporary repo: %s (%s)\nError: %v",
 | 
				
			||||||
			t.repo.FullName(), t.basePath, stdout, err)
 | 
								t.repo.FullName(), t.basePath, err)
 | 
				
			||||||
		return fmt.Errorf("Unable to push back to repo from temporary repo: %s (%s) Error: %v",
 | 
							return fmt.Errorf("Unable to push back to repo from temporary repo: %s (%s) Error: %v",
 | 
				
			||||||
			t.repo.FullName(), t.basePath, err)
 | 
								t.repo.FullName(), t.basePath, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -446,6 +446,7 @@ func CreateOrUpdateRepoFile(repo *models.Repository, doer *models.User, opts *Up
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// Then push this tree to NewBranch
 | 
						// Then push this tree to NewBranch
 | 
				
			||||||
	if err := t.Push(doer, commitHash, opts.NewBranch); err != nil {
 | 
						if err := t.Push(doer, commitHash, opts.NewBranch); err != nil {
 | 
				
			||||||
 | 
							log.Error("%T %v", err, err)
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -109,6 +109,9 @@ func CreateNewBranch(doer *models.User, repo *models.Repository, oldBranchName,
 | 
				
			|||||||
		Branch: branchName,
 | 
							Branch: branchName,
 | 
				
			||||||
		Env:    models.PushingEnvironment(doer, repo),
 | 
							Env:    models.PushingEnvironment(doer, repo),
 | 
				
			||||||
	}); err != nil {
 | 
						}); err != nil {
 | 
				
			||||||
 | 
							if git.IsErrPushOutOfDate(err) || git.IsErrPushRejected(err) {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		return fmt.Errorf("Push: %v", err)
 | 
							return fmt.Errorf("Push: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -156,6 +159,9 @@ func CreateNewBranchFromCommit(doer *models.User, repo *models.Repository, commi
 | 
				
			|||||||
		Branch: branchName,
 | 
							Branch: branchName,
 | 
				
			||||||
		Env:    models.PushingEnvironment(doer, repo),
 | 
							Env:    models.PushingEnvironment(doer, repo),
 | 
				
			||||||
	}); err != nil {
 | 
						}); err != nil {
 | 
				
			||||||
 | 
							if git.IsErrPushOutOfDate(err) || git.IsErrPushRejected(err) {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		return fmt.Errorf("Push: %v", err)
 | 
							return fmt.Errorf("Push: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -678,11 +678,11 @@ func MergePullRequest(ctx *context.APIContext, form auth.MergePullRequestForm) {
 | 
				
			|||||||
		} else if models.IsErrMergeUnrelatedHistories(err) {
 | 
							} else if models.IsErrMergeUnrelatedHistories(err) {
 | 
				
			||||||
			conflictError := err.(models.ErrMergeUnrelatedHistories)
 | 
								conflictError := err.(models.ErrMergeUnrelatedHistories)
 | 
				
			||||||
			ctx.JSON(http.StatusConflict, conflictError)
 | 
								ctx.JSON(http.StatusConflict, conflictError)
 | 
				
			||||||
		} else if models.IsErrMergePushOutOfDate(err) {
 | 
							} else if git.IsErrPushOutOfDate(err) {
 | 
				
			||||||
			ctx.Error(http.StatusConflict, "Merge", "merge push out of date")
 | 
								ctx.Error(http.StatusConflict, "Merge", "merge push out of date")
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		} else if models.IsErrPushRejected(err) {
 | 
							} else if git.IsErrPushRejected(err) {
 | 
				
			||||||
			errPushRej := err.(models.ErrPushRejected)
 | 
								errPushRej := err.(*git.ErrPushRejected)
 | 
				
			||||||
			if len(errPushRej.Message) == 0 {
 | 
								if len(errPushRej.Message) == 0 {
 | 
				
			||||||
				ctx.Error(http.StatusConflict, "Merge", "PushRejected without remote error message")
 | 
									ctx.Error(http.StatusConflict, "Merge", "PushRejected without remote error message")
 | 
				
			||||||
				return
 | 
									return
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,6 +17,7 @@ import (
 | 
				
			|||||||
	"code.gitea.io/gitea/modules/repofiles"
 | 
						"code.gitea.io/gitea/modules/repofiles"
 | 
				
			||||||
	repo_module "code.gitea.io/gitea/modules/repository"
 | 
						repo_module "code.gitea.io/gitea/modules/repository"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/util"
 | 
						"code.gitea.io/gitea/modules/util"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/routers/utils"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
@@ -335,9 +336,8 @@ func CreateBranch(ctx *context.Context, form auth.NewBranchForm) {
 | 
				
			|||||||
			ctx.Redirect(ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL())
 | 
								ctx.Redirect(ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL())
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if models.IsErrBranchAlreadyExists(err) {
 | 
							if models.IsErrBranchAlreadyExists(err) || git.IsErrPushOutOfDate(err) {
 | 
				
			||||||
			e := err.(models.ErrBranchAlreadyExists)
 | 
								ctx.Flash.Error(ctx.Tr("repo.branch.branch_already_exists", form.NewBranchName))
 | 
				
			||||||
			ctx.Flash.Error(ctx.Tr("repo.branch.branch_already_exists", e.BranchName))
 | 
					 | 
				
			||||||
			ctx.Redirect(ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL())
 | 
								ctx.Redirect(ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL())
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -347,6 +347,16 @@ func CreateBranch(ctx *context.Context, form auth.NewBranchForm) {
 | 
				
			|||||||
			ctx.Redirect(ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL())
 | 
								ctx.Redirect(ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL())
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							if git.IsErrPushRejected(err) {
 | 
				
			||||||
 | 
								e := err.(*git.ErrPushRejected)
 | 
				
			||||||
 | 
								if len(e.Message) == 0 {
 | 
				
			||||||
 | 
									ctx.Flash.Error(ctx.Tr("repo.editor.push_rejected_no_message"))
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									ctx.Flash.Error(ctx.Tr("repo.editor.push_rejected", utils.SanitizeFlashErrorString(e.Message)))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								ctx.Redirect(ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL())
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ctx.ServerError("CreateNewBranch", err)
 | 
							ctx.ServerError("CreateNewBranch", err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -228,6 +228,9 @@ func editFilePost(ctx *context.Context, form auth.EditRepoFileForm, isNewFile bo
 | 
				
			|||||||
		// This is where we handle all the errors thrown by repofiles.CreateOrUpdateRepoFile
 | 
							// This is where we handle all the errors thrown by repofiles.CreateOrUpdateRepoFile
 | 
				
			||||||
		if git.IsErrNotExist(err) {
 | 
							if git.IsErrNotExist(err) {
 | 
				
			||||||
			ctx.RenderWithErr(ctx.Tr("repo.editor.file_editing_no_longer_exists", ctx.Repo.TreePath), tplEditFile, &form)
 | 
								ctx.RenderWithErr(ctx.Tr("repo.editor.file_editing_no_longer_exists", ctx.Repo.TreePath), tplEditFile, &form)
 | 
				
			||||||
 | 
							} else if models.IsErrLFSFileLocked(err) {
 | 
				
			||||||
 | 
								ctx.Data["Err_TreePath"] = true
 | 
				
			||||||
 | 
								ctx.RenderWithErr(ctx.Tr("repo.editor.upload_file_is_locked", err.(models.ErrLFSFileLocked).Path, err.(models.ErrLFSFileLocked).UserName), tplEditFile, &form)
 | 
				
			||||||
		} else if models.IsErrFilenameInvalid(err) {
 | 
							} else if models.IsErrFilenameInvalid(err) {
 | 
				
			||||||
			ctx.Data["Err_TreePath"] = true
 | 
								ctx.Data["Err_TreePath"] = true
 | 
				
			||||||
			ctx.RenderWithErr(ctx.Tr("repo.editor.filename_is_invalid", form.TreePath), tplEditFile, &form)
 | 
								ctx.RenderWithErr(ctx.Tr("repo.editor.filename_is_invalid", form.TreePath), tplEditFile, &form)
 | 
				
			||||||
@@ -265,10 +268,12 @@ func editFilePost(ctx *context.Context, form auth.EditRepoFileForm, isNewFile bo
 | 
				
			|||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				ctx.Error(500, err.Error())
 | 
									ctx.Error(500, err.Error())
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else if models.IsErrCommitIDDoesNotMatch(err) || models.IsErrMergePushOutOfDate(err) {
 | 
							} else if models.IsErrCommitIDDoesNotMatch(err) {
 | 
				
			||||||
			ctx.RenderWithErr(ctx.Tr("repo.editor.file_changed_while_editing", ctx.Repo.RepoLink+"/compare/"+form.LastCommit+"..."+ctx.Repo.CommitID), tplEditFile, &form)
 | 
								ctx.RenderWithErr(ctx.Tr("repo.editor.file_changed_while_editing", ctx.Repo.RepoLink+"/compare/"+form.LastCommit+"..."+ctx.Repo.CommitID), tplEditFile, &form)
 | 
				
			||||||
		} else if models.IsErrPushRejected(err) {
 | 
							} else if git.IsErrPushOutOfDate(err) {
 | 
				
			||||||
			errPushRej := err.(models.ErrPushRejected)
 | 
								ctx.RenderWithErr(ctx.Tr("repo.editor.file_changed_while_editing", ctx.Repo.RepoLink+"/compare/"+form.LastCommit+"..."+form.NewBranchName), tplEditFile, &form)
 | 
				
			||||||
 | 
							} else if git.IsErrPushRejected(err) {
 | 
				
			||||||
 | 
								errPushRej := err.(*git.ErrPushRejected)
 | 
				
			||||||
			if len(errPushRej.Message) == 0 {
 | 
								if len(errPushRej.Message) == 0 {
 | 
				
			||||||
				ctx.RenderWithErr(ctx.Tr("repo.editor.push_rejected_no_message"), tplEditFile, &form)
 | 
									ctx.RenderWithErr(ctx.Tr("repo.editor.push_rejected_no_message"), tplEditFile, &form)
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
@@ -436,10 +441,10 @@ func DeleteFilePost(ctx *context.Context, form auth.DeleteRepoFileForm) {
 | 
				
			|||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				ctx.Error(500, err.Error())
 | 
									ctx.Error(500, err.Error())
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else if models.IsErrCommitIDDoesNotMatch(err) || models.IsErrMergePushOutOfDate(err) {
 | 
							} else if models.IsErrCommitIDDoesNotMatch(err) || git.IsErrPushOutOfDate(err) {
 | 
				
			||||||
			ctx.RenderWithErr(ctx.Tr("repo.editor.file_changed_while_deleting", ctx.Repo.RepoLink+"/compare/"+form.LastCommit+"..."+ctx.Repo.CommitID), tplDeleteFile, &form)
 | 
								ctx.RenderWithErr(ctx.Tr("repo.editor.file_changed_while_deleting", ctx.Repo.RepoLink+"/compare/"+form.LastCommit+"..."+ctx.Repo.CommitID), tplDeleteFile, &form)
 | 
				
			||||||
		} else if models.IsErrPushRejected(err) {
 | 
							} else if git.IsErrPushRejected(err) {
 | 
				
			||||||
			errPushRej := err.(models.ErrPushRejected)
 | 
								errPushRej := err.(*git.ErrPushRejected)
 | 
				
			||||||
			if len(errPushRej.Message) == 0 {
 | 
								if len(errPushRej.Message) == 0 {
 | 
				
			||||||
				ctx.RenderWithErr(ctx.Tr("repo.editor.push_rejected_no_message"), tplDeleteFile, &form)
 | 
									ctx.RenderWithErr(ctx.Tr("repo.editor.push_rejected_no_message"), tplDeleteFile, &form)
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
@@ -602,10 +607,48 @@ func UploadFilePost(ctx *context.Context, form auth.UploadRepoFileForm) {
 | 
				
			|||||||
		Message:      message,
 | 
							Message:      message,
 | 
				
			||||||
		Files:        form.Files,
 | 
							Files:        form.Files,
 | 
				
			||||||
	}); err != nil {
 | 
						}); err != nil {
 | 
				
			||||||
		ctx.Data["Err_TreePath"] = true
 | 
					 | 
				
			||||||
		if models.IsErrLFSFileLocked(err) {
 | 
							if models.IsErrLFSFileLocked(err) {
 | 
				
			||||||
 | 
								ctx.Data["Err_TreePath"] = true
 | 
				
			||||||
			ctx.RenderWithErr(ctx.Tr("repo.editor.upload_file_is_locked", err.(models.ErrLFSFileLocked).Path, err.(models.ErrLFSFileLocked).UserName), tplUploadFile, &form)
 | 
								ctx.RenderWithErr(ctx.Tr("repo.editor.upload_file_is_locked", err.(models.ErrLFSFileLocked).Path, err.(models.ErrLFSFileLocked).UserName), tplUploadFile, &form)
 | 
				
			||||||
 | 
							} else if models.IsErrFilenameInvalid(err) {
 | 
				
			||||||
 | 
								ctx.Data["Err_TreePath"] = true
 | 
				
			||||||
 | 
								ctx.RenderWithErr(ctx.Tr("repo.editor.filename_is_invalid", form.TreePath), tplUploadFile, &form)
 | 
				
			||||||
 | 
							} else if models.IsErrFilePathInvalid(err) {
 | 
				
			||||||
 | 
								ctx.Data["Err_TreePath"] = true
 | 
				
			||||||
 | 
								fileErr := err.(models.ErrFilePathInvalid)
 | 
				
			||||||
 | 
								switch fileErr.Type {
 | 
				
			||||||
 | 
								case git.EntryModeSymlink:
 | 
				
			||||||
 | 
									ctx.RenderWithErr(ctx.Tr("repo.editor.file_is_a_symlink", fileErr.Path), tplUploadFile, &form)
 | 
				
			||||||
 | 
								case git.EntryModeTree:
 | 
				
			||||||
 | 
									ctx.RenderWithErr(ctx.Tr("repo.editor.filename_is_a_directory", fileErr.Path), tplUploadFile, &form)
 | 
				
			||||||
 | 
								case git.EntryModeBlob:
 | 
				
			||||||
 | 
									ctx.RenderWithErr(ctx.Tr("repo.editor.directory_is_a_file", fileErr.Path), tplUploadFile, &form)
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									ctx.Error(500, err.Error())
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else if models.IsErrRepoFileAlreadyExists(err) {
 | 
				
			||||||
 | 
								ctx.Data["Err_TreePath"] = true
 | 
				
			||||||
 | 
								ctx.RenderWithErr(ctx.Tr("repo.editor.file_already_exists", form.TreePath), tplUploadFile, &form)
 | 
				
			||||||
 | 
							} else if git.IsErrBranchNotExist(err) {
 | 
				
			||||||
 | 
								branchErr := err.(git.ErrBranchNotExist)
 | 
				
			||||||
 | 
								ctx.RenderWithErr(ctx.Tr("repo.editor.branch_does_not_exist", branchErr.Name), tplUploadFile, &form)
 | 
				
			||||||
 | 
							} else if models.IsErrBranchAlreadyExists(err) {
 | 
				
			||||||
 | 
								// For when a user specifies a new branch that already exists
 | 
				
			||||||
 | 
								ctx.Data["Err_NewBranchName"] = true
 | 
				
			||||||
 | 
								branchErr := err.(models.ErrBranchAlreadyExists)
 | 
				
			||||||
 | 
								ctx.RenderWithErr(ctx.Tr("repo.editor.branch_already_exists", branchErr.BranchName), tplUploadFile, &form)
 | 
				
			||||||
 | 
							} else if git.IsErrPushOutOfDate(err) {
 | 
				
			||||||
 | 
								ctx.RenderWithErr(ctx.Tr("repo.editor.file_changed_while_editing", ctx.Repo.RepoLink+"/compare/"+ctx.Repo.CommitID+"..."+form.NewBranchName), tplUploadFile, &form)
 | 
				
			||||||
 | 
							} else if git.IsErrPushRejected(err) {
 | 
				
			||||||
 | 
								errPushRej := err.(*git.ErrPushRejected)
 | 
				
			||||||
 | 
								if len(errPushRej.Message) == 0 {
 | 
				
			||||||
 | 
									ctx.RenderWithErr(ctx.Tr("repo.editor.push_rejected_no_message"), tplUploadFile, &form)
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									ctx.RenderWithErr(ctx.Tr("repo.editor.push_rejected", utils.SanitizeFlashErrorString(errPushRej.Message)), tplUploadFile, &form)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
 | 
								// os.ErrNotExist - upload file missing in the intervening time?!
 | 
				
			||||||
 | 
								log.Error("Error during upload to repo: %-v to filepath: %s on %s from %s: %v", ctx.Repo.Repository, form.TreePath, oldBranchName, form.NewBranchName, err)
 | 
				
			||||||
			ctx.RenderWithErr(ctx.Tr("repo.editor.unable_to_upload_files", form.TreePath, err), tplUploadFile, &form)
 | 
								ctx.RenderWithErr(ctx.Tr("repo.editor.unable_to_upload_files", form.TreePath, err), tplUploadFile, &form)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,7 +10,6 @@ import (
 | 
				
			|||||||
	"container/list"
 | 
						"container/list"
 | 
				
			||||||
	"crypto/subtle"
 | 
						"crypto/subtle"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"html"
 | 
					 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"path"
 | 
						"path"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
@@ -668,18 +667,9 @@ func UpdatePullRequest(ctx *context.Context) {
 | 
				
			|||||||
	message := fmt.Sprintf("Merge branch '%s' into %s", issue.PullRequest.BaseBranch, issue.PullRequest.HeadBranch)
 | 
						message := fmt.Sprintf("Merge branch '%s' into %s", issue.PullRequest.BaseBranch, issue.PullRequest.HeadBranch)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err = pull_service.Update(issue.PullRequest, ctx.User, message); err != nil {
 | 
						if err = pull_service.Update(issue.PullRequest, ctx.User, message); err != nil {
 | 
				
			||||||
		sanitize := func(x string) string {
 | 
					 | 
				
			||||||
			runes := []rune(x)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if len(runes) > 512 {
 | 
					 | 
				
			||||||
				x = "..." + string(runes[len(runes)-512:])
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			return strings.Replace(html.EscapeString(x), "\n", "<br>", -1)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if models.IsErrMergeConflicts(err) {
 | 
							if models.IsErrMergeConflicts(err) {
 | 
				
			||||||
			conflictError := err.(models.ErrMergeConflicts)
 | 
								conflictError := err.(models.ErrMergeConflicts)
 | 
				
			||||||
			ctx.Flash.Error(ctx.Tr("repo.pulls.merge_conflict", sanitize(conflictError.StdErr), sanitize(conflictError.StdOut)))
 | 
								ctx.Flash.Error(ctx.Tr("repo.pulls.merge_conflict", utils.SanitizeFlashErrorString(conflictError.StdErr), utils.SanitizeFlashErrorString(conflictError.StdOut)))
 | 
				
			||||||
			ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + com.ToStr(issue.Index))
 | 
								ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + com.ToStr(issue.Index))
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -814,14 +804,14 @@ func MergePullRequest(ctx *context.Context, form auth.MergePullRequestForm) {
 | 
				
			|||||||
			ctx.Flash.Error(ctx.Tr("repo.pulls.unrelated_histories"))
 | 
								ctx.Flash.Error(ctx.Tr("repo.pulls.unrelated_histories"))
 | 
				
			||||||
			ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + com.ToStr(pr.Index))
 | 
								ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + com.ToStr(pr.Index))
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		} else if models.IsErrMergePushOutOfDate(err) {
 | 
							} else if git.IsErrPushOutOfDate(err) {
 | 
				
			||||||
			log.Debug("MergePushOutOfDate error: %v", err)
 | 
								log.Debug("MergePushOutOfDate error: %v", err)
 | 
				
			||||||
			ctx.Flash.Error(ctx.Tr("repo.pulls.merge_out_of_date"))
 | 
								ctx.Flash.Error(ctx.Tr("repo.pulls.merge_out_of_date"))
 | 
				
			||||||
			ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + com.ToStr(pr.Index))
 | 
								ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + com.ToStr(pr.Index))
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		} else if models.IsErrPushRejected(err) {
 | 
							} else if git.IsErrPushRejected(err) {
 | 
				
			||||||
			log.Debug("MergePushRejected error: %v", err)
 | 
								log.Debug("MergePushRejected error: %v", err)
 | 
				
			||||||
			pushrejErr := err.(models.ErrPushRejected)
 | 
								pushrejErr := err.(*git.ErrPushRejected)
 | 
				
			||||||
			message := pushrejErr.Message
 | 
								message := pushrejErr.Message
 | 
				
			||||||
			if len(message) == 0 {
 | 
								if len(message) == 0 {
 | 
				
			||||||
				ctx.Flash.Error(ctx.Tr("repo.pulls.push_rejected_no_message"))
 | 
									ctx.Flash.Error(ctx.Tr("repo.pulls.push_rejected_no_message"))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -385,15 +385,13 @@ func rawMerge(pr *models.PullRequest, doer *models.User, mergeStyle models.Merge
 | 
				
			|||||||
	// Push back to upstream.
 | 
						// Push back to upstream.
 | 
				
			||||||
	if err := git.NewCommand("push", "origin", baseBranch+":"+pr.BaseBranch).RunInDirTimeoutEnvPipeline(env, -1, tmpBasePath, &outbuf, &errbuf); err != nil {
 | 
						if err := git.NewCommand("push", "origin", baseBranch+":"+pr.BaseBranch).RunInDirTimeoutEnvPipeline(env, -1, tmpBasePath, &outbuf, &errbuf); err != nil {
 | 
				
			||||||
		if strings.Contains(errbuf.String(), "non-fast-forward") {
 | 
							if strings.Contains(errbuf.String(), "non-fast-forward") {
 | 
				
			||||||
			return "", models.ErrMergePushOutOfDate{
 | 
								return "", &git.ErrPushOutOfDate{
 | 
				
			||||||
				Style:  mergeStyle,
 | 
					 | 
				
			||||||
				StdOut: outbuf.String(),
 | 
									StdOut: outbuf.String(),
 | 
				
			||||||
				StdErr: errbuf.String(),
 | 
									StdErr: errbuf.String(),
 | 
				
			||||||
				Err:    err,
 | 
									Err:    err,
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else if strings.Contains(errbuf.String(), "! [remote rejected]") {
 | 
							} else if strings.Contains(errbuf.String(), "! [remote rejected]") {
 | 
				
			||||||
			err := models.ErrPushRejected{
 | 
								err := &git.ErrPushRejected{
 | 
				
			||||||
				Style:  mergeStyle,
 | 
					 | 
				
			||||||
				StdOut: outbuf.String(),
 | 
									StdOut: outbuf.String(),
 | 
				
			||||||
				StdErr: errbuf.String(),
 | 
									StdErr: errbuf.String(),
 | 
				
			||||||
				Err:    err,
 | 
									Err:    err,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -212,6 +212,9 @@ func updateWikiPage(doer *models.User, repo *models.Repository, oldWikiName, new
 | 
				
			|||||||
		),
 | 
							),
 | 
				
			||||||
	}); err != nil {
 | 
						}); err != nil {
 | 
				
			||||||
		log.Error("%v", err)
 | 
							log.Error("%v", err)
 | 
				
			||||||
 | 
							if git.IsErrPushOutOfDate(err) || git.IsErrPushRejected(err) {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		return fmt.Errorf("Push: %v", err)
 | 
							return fmt.Errorf("Push: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -316,6 +319,9 @@ func DeleteWikiPage(doer *models.User, repo *models.Repository, wikiName string)
 | 
				
			|||||||
		Branch: fmt.Sprintf("%s:%s%s", commitHash.String(), git.BranchPrefix, "master"),
 | 
							Branch: fmt.Sprintf("%s:%s%s", commitHash.String(), git.BranchPrefix, "master"),
 | 
				
			||||||
		Env:    models.PushingEnvironment(doer, repo),
 | 
							Env:    models.PushingEnvironment(doer, repo),
 | 
				
			||||||
	}); err != nil {
 | 
						}); err != nil {
 | 
				
			||||||
 | 
							if git.IsErrPushOutOfDate(err) || git.IsErrPushRejected(err) {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		return fmt.Errorf("Push: %v", err)
 | 
							return fmt.Errorf("Push: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user