// UpdatePatch generates and saves a new patch. func (pr *PullRequest) UpdatePatch() error { if err := pr.GetHeadRepo(); err != nil { return fmt.Errorf("GetHeadRepo: %v", err) } else if pr.HeadRepo == nil { log.Trace("PullRequest[%d].UpdatePatch: ignored cruppted data", pr.ID) return nil } if err := pr.GetBaseRepo(); err != nil { return fmt.Errorf("GetBaseRepo: %v", err) } headRepoPath, err := pr.HeadRepo.RepoPath() if err != nil { return fmt.Errorf("HeadRepo.RepoPath: %v", err) } headGitRepo, err := git.OpenRepository(headRepoPath) if err != nil { return fmt.Errorf("OpenRepository: %v", err) } patch, err := headGitRepo.GetPatch(pr.MergeBase, pr.HeadBranch) if err != nil { return fmt.Errorf("GetPatch: %v", err) } if err = pr.BaseRepo.SavePatch(pr.Index, patch); err != nil { return fmt.Errorf("BaseRepo.SavePatch: %v", err) } return nil }
func RetrieveBaseRepo(ctx *Context, repo *models.Repository) { // Non-fork repository will not return error in this method. if err := repo.GetBaseRepo(); err != nil { if models.IsErrRepoNotExist(err) { repo.IsFork = false repo.ForkID = 0 return } ctx.Handle(500, "GetBaseRepo", err) return } else if err = repo.BaseRepo.GetOwner(); err != nil { ctx.Handle(500, "BaseRepo.GetOwner", err) return } bsaeRepo := repo.BaseRepo baseGitRepo, err := git.OpenRepository(models.RepoPath(bsaeRepo.Owner.Name, bsaeRepo.Name)) if err != nil { ctx.Handle(500, "OpenRepository", err) return } if len(bsaeRepo.DefaultBranch) > 0 && baseGitRepo.IsBranchExist(bsaeRepo.DefaultBranch) { ctx.Data["BaseDefaultBranch"] = bsaeRepo.DefaultBranch } else { baseBranches, err := baseGitRepo.GetBranches() if err != nil { ctx.Handle(500, "GetBranches", err) return } if len(baseBranches) > 0 { ctx.Data["BaseDefaultBranch"] = baseBranches[0] } } }
// MigrateRepository migrates a existing repository from other project hosting. func MigrateRepository(u *User, name, desc string, private, mirror bool, url string) (*Repository, error) { repo, err := CreateRepository(u, CreateRepoOptions{ Name: name, Description: desc, IsPrivate: private, IsMirror: mirror, }) if err != nil { return nil, err } // Clone to temprory path and do the init commit. tmpDir := filepath.Join(os.TempDir(), fmt.Sprintf("%d", time.Now().Nanosecond())) os.MkdirAll(tmpDir, os.ModePerm) repoPath := RepoPath(u.Name, name) if u.IsOrganization() { t, err := u.GetOwnerTeam() if err != nil { return nil, err } repo.NumWatches = t.NumMembers } else { repo.NumWatches = 1 } repo.IsBare = false if mirror { if err = MirrorRepository(repo.ID, u.Name, repo.Name, repoPath, url); err != nil { return repo, err } repo.IsMirror = true return repo, UpdateRepository(repo, false) } else { os.RemoveAll(repoPath) } // FIXME: this command could for both migrate and mirror _, stderr, err := process.ExecTimeout(10*time.Minute, fmt.Sprintf("MigrateRepository: %s", repoPath), "git", "clone", "--mirror", "--bare", "--quiet", url, repoPath) if err != nil { return repo, fmt.Errorf("git clone --mirror --bare --quiet: %v", stderr) } else if err = createUpdateHook(repoPath); err != nil { return repo, fmt.Errorf("create update hook: %v", err) } // Check if repository has master branch, if so set it to default branch. gitRepo, err := git.OpenRepository(repoPath) if err != nil { return repo, fmt.Errorf("open git repository: %v", err) } if gitRepo.IsBranchExist("master") { repo.DefaultBranch = "master" } return repo, UpdateRepository(repo, false) }
func CompareAndPullRequest(ctx *middleware.Context) { ctx.Data["Title"] = ctx.Tr("repo.pulls.compare_changes") ctx.Data["PageIsComparePull"] = true repo := ctx.Repo.Repository // Get compare branch information. infos := strings.Split(ctx.Params("*"), "...") if len(infos) != 2 { ctx.Handle(404, "CompareAndPullRequest", nil) return } baseBranch := infos[0] ctx.Data["BaseBranch"] = baseBranch headInfos := strings.Split(infos[1], ":") if len(headInfos) != 2 { ctx.Handle(404, "CompareAndPullRequest", nil) return } headUser := headInfos[0] headBranch := headInfos[1] ctx.Data["HeadBranch"] = headBranch // TODO: check if branches are valid. fmt.Println(baseBranch, headUser, headBranch) // TODO: add organization support // Check if current user has fork of repository. headRepo, has := models.HasForkedRepo(ctx.User.Id, repo.ID) if !has { ctx.Handle(404, "HasForkedRepo", nil) return } headGitRepo, err := git.OpenRepository(models.RepoPath(ctx.User.Name, headRepo.Name)) if err != nil { ctx.Handle(500, "OpenRepository", err) return } headBranches, err := headGitRepo.GetBranches() if err != nil { ctx.Handle(500, "GetBranches", err) return } ctx.Data["HeadBranches"] = headBranches // Setup information for new form. RetrieveRepoMetas(ctx, ctx.Repo.Repository) if ctx.Written() { return } // Get diff information. ctx.HTML(200, COMPARE_PULL) }
func GetDiffRange(repoPath, beforeCommitId string, afterCommitId string, maxlines int) (*Diff, error) { repo, err := git.OpenRepository(repoPath) if err != nil { return nil, err } commit, err := repo.GetCommit(afterCommitId) if err != nil { return nil, err } rd, wr := io.Pipe() var cmd *exec.Cmd // if "after" commit given if beforeCommitId == "" { // First commit of repository. if commit.ParentCount() == 0 { cmd = exec.Command("git", "show", afterCommitId) } else { c, _ := commit.Parent(0) cmd = exec.Command("git", "diff", c.Id.String(), afterCommitId) } } else { cmd = exec.Command("git", "diff", beforeCommitId, afterCommitId) } cmd.Dir = repoPath cmd.Stdout = wr cmd.Stdin = os.Stdin cmd.Stderr = os.Stderr done := make(chan error) go func() { cmd.Start() done <- cmd.Wait() wr.Close() }() defer rd.Close() desc := fmt.Sprintf("GetDiffRange(%s)", repoPath) pid := process.Add(desc, cmd) go func() { // In case process became zombie. select { case <-time.After(5 * time.Minute): if errKill := process.Kill(pid); errKill != nil { log.Error(4, "git_diff.ParsePatch(Kill): %v", err) } <-done // return "", ErrExecTimeout.Error(), ErrExecTimeout case err = <-done: process.Remove(pid) } }() return ParsePatch(pid, maxlines, cmd, rd) }
func GetRepoArchive(ctx *middleware.Context) { repoPath := models.RepoPath(ctx.Params(":username"), ctx.Params(":reponame")) gitRepo, err := git.OpenRepository(repoPath) if err != nil { ctx.Handle(500, "RepoAssignment Invalid repo: "+repoPath, err) return } ctx.Repo.GitRepo = gitRepo repo.Download(ctx) }
// https://github.com/gogits/go-gogs-client/wiki/Repositories-Contents#download-archive func GetRepoArchive(ctx *middleware.Context) { repoPath := models.RepoPath(ctx.Params(":username"), ctx.Params(":reponame")) gitRepo, err := git.OpenRepository(repoPath) if err != nil { ctx.APIError(500, "OpenRepository", err) return } ctx.Repo.GitRepo = gitRepo repo.Download(ctx) }
// UpdatePatch generates and saves a new patch. func (pr *PullRequest) UpdatePatch() (err error) { if err = pr.GetHeadRepo(); err != nil { return fmt.Errorf("GetHeadRepo: %v", err) } else if pr.HeadRepo == nil { log.Trace("PullRequest[%d].UpdatePatch: ignored cruppted data", pr.ID) return nil } if err = pr.GetBaseRepo(); err != nil { return fmt.Errorf("GetBaseRepo: %v", err) } else if err = pr.BaseRepo.GetOwner(); err != nil { return fmt.Errorf("GetOwner: %v", err) } headRepoPath, err := pr.HeadRepo.RepoPath() if err != nil { return fmt.Errorf("HeadRepo.RepoPath: %v", err) } headGitRepo, err := git.OpenRepository(headRepoPath) if err != nil { return fmt.Errorf("OpenRepository: %v", err) } // Add a temporary remote. tmpRemote := com.ToStr(time.Now().UnixNano()) if err = headGitRepo.AddRemote(tmpRemote, RepoPath(pr.BaseRepo.Owner.Name, pr.BaseRepo.Name)); err != nil { return fmt.Errorf("AddRemote: %v", err) } defer func() { headGitRepo.RemoveRemote(tmpRemote) }() remoteBranch := "remotes/" + tmpRemote + "/" + pr.BaseBranch pr.MergeBase, err = headGitRepo.GetMergeBase(remoteBranch, pr.HeadBranch) if err != nil { return fmt.Errorf("GetMergeBase: %v", err) } else if err = pr.Update(); err != nil { return fmt.Errorf("Update: %v", err) } patch, err := headGitRepo.GetPatch(pr.MergeBase, pr.HeadBranch) if err != nil { return fmt.Errorf("GetPatch: %v", err) } if err = pr.BaseRepo.SavePatch(pr.Index, patch); err != nil { return fmt.Errorf("BaseRepo.SavePatch: %v", err) } return nil }
func PrepareViewPullInfo(ctx *middleware.Context, pull *models.Issue) *git.PullRequestInfo { repo := ctx.Repo.Repository ctx.Data["HeadTarget"] = pull.HeadUserName + "/" + pull.HeadBranch ctx.Data["BaseTarget"] = ctx.Repo.Owner.Name + "/" + pull.BaseBranch var ( headGitRepo *git.Repository err error ) if err = pull.GetHeadRepo(); err != nil { ctx.Handle(500, "GetHeadRepo", err) return nil } if pull.HeadRepo != nil { headRepoPath, err := pull.HeadRepo.RepoPath() if err != nil { ctx.Handle(500, "HeadRepo.RepoPath", err) return nil } headGitRepo, err = git.OpenRepository(headRepoPath) if err != nil { ctx.Handle(500, "OpenRepository", err) return nil } } if pull.HeadRepo == nil || !headGitRepo.IsBranchExist(pull.HeadBranch) { ctx.Data["IsPullReuqestBroken"] = true ctx.Data["HeadTarget"] = "deleted" ctx.Data["NumCommits"] = 0 ctx.Data["NumFiles"] = 0 return nil } prInfo, err := headGitRepo.GetPullRequestInfo(models.RepoPath(repo.Owner.Name, repo.Name), pull.BaseBranch, pull.HeadBranch) if err != nil { ctx.Handle(500, "GetPullRequestInfo", err) return nil } ctx.Data["NumCommits"] = prInfo.Commits.Len() ctx.Data["NumFiles"] = prInfo.NumFiles return prInfo }
func CompareAndPullRequest(ctx *middleware.Context) { // Get compare information. infos := strings.Split(ctx.Params("*"), "...") if len(infos) != 2 { ctx.Handle(404, "CompareAndPullRequest", nil) return } baseBranch := infos[0] ctx.Data["BaseBranch"] = baseBranch headInfos := strings.Split(infos[1], ":") if len(headInfos) != 2 { ctx.Handle(404, "CompareAndPullRequest", nil) return } headUser := headInfos[0] headBranch := headInfos[1] ctx.Data["HeadBranch"] = headBranch // TODO: check if branches are valid. fmt.Println(baseBranch, headUser, headBranch) // TODO: add organization support // Check if current user has fork of repository. headRepo, has := models.HasForkedRepo(ctx.User.Id, ctx.Repo.Repository.ID) if !has { ctx.Handle(404, "HasForkedRepo", nil) return } headGitRepo, err := git.OpenRepository(models.RepoPath(ctx.User.Name, headRepo.Name)) if err != nil { ctx.Handle(500, "OpenRepository", err) return } headBranches, err := headGitRepo.GetBranches() if err != nil { ctx.Handle(500, "GetBranches", err) return } ctx.Data["HeadBranches"] = headBranches ctx.HTML(200, COMPARE_PULL) }
func ViewPullFiles(ctx *middleware.Context) { ctx.Data["PageIsPullFiles"] = true pull := checkPullInfo(ctx) if ctx.Written() { return } var ( diffRepoPath string startCommitID string endCommitID string gitRepo *git.Repository ) if pull.HasMerged { PrepareMergedViewPullInfo(ctx, pull) if ctx.Written() { return } diffRepoPath = ctx.Repo.GitRepo.Path startCommitID = pull.MergeBase endCommitID = pull.MergedCommitID gitRepo = ctx.Repo.GitRepo } else { prInfo := PrepareViewPullInfo(ctx, pull) if ctx.Written() { return } else if prInfo == nil { ctx.Handle(404, "ViewPullFiles", nil) return } headRepoPath := models.RepoPath(pull.HeadUserName, pull.HeadRepo.Name) headGitRepo, err := git.OpenRepository(headRepoPath) if err != nil { ctx.Handle(500, "OpenRepository", err) return } headCommitID, err := headGitRepo.GetCommitIdOfBranch(pull.HeadBranch) if err != nil { ctx.Handle(500, "GetCommitIdOfBranch", err) return } diffRepoPath = headRepoPath startCommitID = prInfo.MergeBase endCommitID = headCommitID gitRepo = headGitRepo } diff, err := models.GetDiffRange(diffRepoPath, startCommitID, endCommitID, setting.Git.MaxGitDiffLines) if err != nil { ctx.Handle(500, "GetDiffRange", err) return } ctx.Data["Diff"] = diff ctx.Data["DiffNotAvailable"] = diff.NumFiles() == 0 commit, err := gitRepo.GetCommit(endCommitID) if err != nil { ctx.Handle(500, "GetCommit", err) return } headTarget := path.Join(pull.HeadUserName, pull.HeadRepo.Name) ctx.Data["Username"] = pull.HeadUserName ctx.Data["Reponame"] = pull.HeadRepo.Name ctx.Data["IsImageFile"] = commit.IsImageFile ctx.Data["SourcePath"] = setting.AppSubUrl + "/" + path.Join(headTarget, "src", endCommitID) ctx.Data["BeforeSourcePath"] = setting.AppSubUrl + "/" + path.Join(headTarget, "src", startCommitID) ctx.Data["RawPath"] = setting.AppSubUrl + "/" + path.Join(headTarget, "raw", endCommitID) ctx.HTML(200, PULL_FILES) }
func ParseCompareInfo(ctx *middleware.Context) (*models.User, *models.Repository, *git.Repository, *git.PullRequestInfo, string, string) { // Get compare branch information. infos := strings.Split(ctx.Params("*"), "...") if len(infos) != 2 { ctx.Handle(404, "CompareAndPullRequest", nil) return nil, nil, nil, nil, "", "" } baseBranch := infos[0] ctx.Data["BaseBranch"] = baseBranch headInfos := strings.Split(infos[1], ":") if len(headInfos) != 2 { ctx.Handle(404, "CompareAndPullRequest", nil) return nil, nil, nil, nil, "", "" } headUsername := headInfos[0] headBranch := headInfos[1] ctx.Data["HeadBranch"] = headBranch headUser, err := models.GetUserByName(headUsername) if err != nil { if models.IsErrUserNotExist(err) { ctx.Handle(404, "GetUserByName", nil) } else { ctx.Handle(500, "GetUserByName", err) } return nil, nil, nil, nil, "", "" } repo := ctx.Repo.Repository // Check if base branch is valid. if !ctx.Repo.GitRepo.IsBranchExist(baseBranch) { ctx.Handle(404, "IsBranchExist", nil) return nil, nil, nil, nil, "", "" } // Check if current user has fork of repository. headRepo, has := models.HasForkedRepo(headUser.Id, repo.ID) if !has || (!ctx.User.IsAdminOfRepo(headRepo) && !ctx.User.IsAdmin) { ctx.Handle(404, "HasForkedRepo", nil) return nil, nil, nil, nil, "", "" } headGitRepo, err := git.OpenRepository(models.RepoPath(headUser.Name, headRepo.Name)) if err != nil { ctx.Handle(500, "OpenRepository", err) return nil, nil, nil, nil, "", "" } // Check if head branch is valid. if !headGitRepo.IsBranchExist(headBranch) { ctx.Handle(404, "IsBranchExist", nil) return nil, nil, nil, nil, "", "" } headBranches, err := headGitRepo.GetBranches() if err != nil { ctx.Handle(500, "GetBranches", err) return nil, nil, nil, nil, "", "" } ctx.Data["HeadBranches"] = headBranches prInfo, err := headGitRepo.GetPullRequestInfo(models.RepoPath(repo.Owner.Name, repo.Name), baseBranch, headBranch) if err != nil { ctx.Handle(500, "GetPullRequestInfo", err) return nil, nil, nil, nil, "", "" } ctx.Data["BeforeCommitID"] = prInfo.MergeBase return headUser, headRepo, headGitRepo, prInfo, baseBranch, headBranch }
func Update(refName, oldCommitId, newCommitId, userName, repoUserName, repoName string, userId int64) error { isNew := strings.HasPrefix(oldCommitId, "0000000") if isNew && strings.HasPrefix(newCommitId, "0000000") { return fmt.Errorf("old rev and new rev both 000000") } f := RepoPath(repoUserName, repoName) gitUpdate := exec.Command("git", "update-server-info") gitUpdate.Dir = f gitUpdate.Run() isDel := strings.HasPrefix(newCommitId, "0000000") if isDel { log.GitLogger.Info("del rev", refName, "from", userName+"/"+repoName+".git", "by", userId) return nil } repo, err := git.OpenRepository(f) if err != nil { return fmt.Errorf("runUpdate.Open repoId: %v", err) } ru, err := GetUserByName(repoUserName) if err != nil { return fmt.Errorf("runUpdate.GetUserByName: %v", err) } repos, err := GetRepositoryByName(ru.Id, repoName) if err != nil { return fmt.Errorf("runUpdate.GetRepositoryByName userId: %v", err) } // Push tags. if strings.HasPrefix(refName, "refs/tags/") { tagName := git.RefEndName(refName) tag, err := repo.GetTag(tagName) if err != nil { log.GitLogger.Fatal(4, "runUpdate.GetTag: %v", err) } var actEmail string if tag.Tagger != nil { actEmail = tag.Tagger.Email } else { cmt, err := tag.Commit() if err != nil { log.GitLogger.Fatal(4, "runUpdate.GetTag Commit: %v", err) } actEmail = cmt.Committer.Email } commit := &base.PushCommits{} if err = CommitRepoAction(userId, ru.Id, userName, actEmail, repos.ID, repoUserName, repoName, refName, commit, oldCommitId, newCommitId); err != nil { log.GitLogger.Fatal(4, "CommitRepoAction: %s/%s:%v", repoUserName, repoName, err) } return err } newCommit, err := repo.GetCommit(newCommitId) if err != nil { return fmt.Errorf("runUpdate GetCommit of newCommitId: %v", err) } // Push new branch. var l *list.List if isNew { l, err = newCommit.CommitsBefore() if err != nil { return fmt.Errorf("CommitsBefore: %v", err) } } else { l, err = newCommit.CommitsBeforeUntil(oldCommitId) if err != nil { return fmt.Errorf("CommitsBeforeUntil: %v", err) } } if err != nil { return fmt.Errorf("runUpdate.Commit repoId: %v", err) } // Push commits. commits := make([]*base.PushCommit, 0) var actEmail string for e := l.Front(); e != nil; e = e.Next() { commit := e.Value.(*git.Commit) if actEmail == "" { actEmail = commit.Committer.Email } commits = append(commits, &base.PushCommit{commit.ID.String(), commit.Message(), commit.Author.Email, commit.Author.Name, }) } if err = CommitRepoAction(userId, ru.Id, userName, actEmail, repos.ID, repoUserName, repoName, refName, &base.PushCommits{l.Len(), commits, ""}, oldCommitId, newCommitId); err != nil { return fmt.Errorf("runUpdate.models.CommitRepoAction: %s/%s:%v", repoUserName, repoName, err) } return nil }
// Merge merges pull request to base repository. func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository) (err error) { sess := x.NewSession() defer sessionRelease(sess) if err = sess.Begin(); err != nil { return err } if err = pr.Issue.changeStatus(sess, doer, true); err != nil { return fmt.Errorf("Pull.changeStatus: %v", err) } headRepoPath := RepoPath(pr.HeadUserName, pr.HeadRepo.Name) headGitRepo, err := git.OpenRepository(headRepoPath) if err != nil { return fmt.Errorf("OpenRepository: %v", err) } pr.MergedCommitID, err = headGitRepo.GetCommitIdOfBranch(pr.HeadBranch) if err != nil { return fmt.Errorf("GetCommitIdOfBranch: %v", err) } if err = mergePullRequestAction(sess, doer, pr.Issue.Repo, pr.Issue); err != nil { return fmt.Errorf("mergePullRequestAction: %v", err) } pr.HasMerged = true pr.Merged = time.Now() pr.MergerID = doer.Id if _, err = sess.Id(pr.ID).AllCols().Update(pr); err != nil { return fmt.Errorf("update pull request: %v", err) } // Clone base repo. tmpBasePath := path.Join("data/tmp/repos", com.ToStr(time.Now().Nanosecond())+".git") os.MkdirAll(path.Dir(tmpBasePath), os.ModePerm) defer os.RemoveAll(path.Dir(tmpBasePath)) var stderr string if _, stderr, err = process.ExecTimeout(5*time.Minute, fmt.Sprintf("PullRequest.Merge(git clone): %s", tmpBasePath), "git", "clone", baseGitRepo.Path, tmpBasePath); err != nil { return fmt.Errorf("git clone: %s", stderr) } // Check out base branch. if _, stderr, err = process.ExecDir(-1, tmpBasePath, fmt.Sprintf("PullRequest.Merge(git checkout): %s", tmpBasePath), "git", "checkout", pr.BaseBranch); err != nil { return fmt.Errorf("git checkout: %s", stderr) } // Pull commits. if _, stderr, err = process.ExecDir(-1, tmpBasePath, fmt.Sprintf("PullRequest.Merge(git pull): %s", tmpBasePath), "git", "pull", headRepoPath, pr.HeadBranch); err != nil { return fmt.Errorf("git pull[%s / %s -> %s]: %s", headRepoPath, pr.HeadBranch, tmpBasePath, stderr) } // Push back to upstream. if _, stderr, err = process.ExecDir(-1, tmpBasePath, fmt.Sprintf("PullRequest.Merge(git push): %s", tmpBasePath), "git", "push", baseGitRepo.Path, pr.BaseBranch); err != nil { return fmt.Errorf("git push: %s", stderr) } return sess.Commit() }
// RepoRef handles repository reference name including those contain `/`. func RepoRef() macaron.Handler { return func(ctx *Context) { var ( refName string err error ) // For API calls. if ctx.Repo.GitRepo == nil { repoPath := models.RepoPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name) gitRepo, err := git.OpenRepository(repoPath) if err != nil { ctx.Handle(500, "RepoRef Invalid repo "+repoPath, err) return } ctx.Repo.GitRepo = gitRepo } // Get default branch. if len(ctx.Params("*")) == 0 { refName = ctx.Repo.Repository.DefaultBranch if !ctx.Repo.GitRepo.IsBranchExist(refName) { brs, err := ctx.Repo.GitRepo.GetBranches() if err != nil { ctx.Handle(500, "GetBranches", err) return } refName = brs[0] } ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommitOfBranch(refName) if err != nil { ctx.Handle(500, "GetCommitOfBranch", err) return } ctx.Repo.CommitID = ctx.Repo.Commit.Id.String() ctx.Repo.IsBranch = true } else { hasMatched := false parts := strings.Split(ctx.Params("*"), "/") for i, part := range parts { refName = strings.TrimPrefix(refName+"/"+part, "/") if ctx.Repo.GitRepo.IsBranchExist(refName) || ctx.Repo.GitRepo.IsTagExist(refName) { if i < len(parts)-1 { ctx.Repo.TreeName = strings.Join(parts[i+1:], "/") } hasMatched = true break } } if !hasMatched && len(parts[0]) == 40 { refName = parts[0] ctx.Repo.TreeName = strings.Join(parts[1:], "/") } if ctx.Repo.GitRepo.IsBranchExist(refName) { ctx.Repo.IsBranch = true ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommitOfBranch(refName) if err != nil { ctx.Handle(500, "GetCommitOfBranch", err) return } ctx.Repo.CommitID = ctx.Repo.Commit.Id.String() } else if ctx.Repo.GitRepo.IsTagExist(refName) { ctx.Repo.IsTag = true ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommitOfTag(refName) if err != nil { ctx.Handle(500, "GetCommitOfTag", err) return } ctx.Repo.CommitID = ctx.Repo.Commit.Id.String() } else if len(refName) == 40 { ctx.Repo.IsCommit = true ctx.Repo.CommitID = refName ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommit(refName) if err != nil { ctx.Handle(404, "GetCommit", nil) return } } else { ctx.Handle(404, "RepoRef invalid repo", fmt.Errorf("branch or tag not exist: %s", refName)) return } } ctx.Repo.BranchName = refName ctx.Data["BranchName"] = ctx.Repo.BranchName ctx.Data["CommitID"] = ctx.Repo.CommitID ctx.Data["IsBranch"] = ctx.Repo.IsBranch ctx.Data["IsTag"] = ctx.Repo.IsTag ctx.Data["IsCommit"] = ctx.Repo.IsCommit ctx.Repo.CommitsCount, err = ctx.Repo.Commit.CommitsCount() if err != nil { ctx.Handle(500, "CommitsCount", err) return } ctx.Data["CommitsCount"] = ctx.Repo.CommitsCount } }
func RepoAssignment(redirect bool, args ...bool) macaron.Handler { return func(ctx *Context) { var ( displayBare bool // To display bare page if it is a bare repo. ) if len(args) >= 1 { displayBare = args[0] } var ( u *models.User err error ) userName := ctx.Params(":username") repoName := ctx.Params(":reponame") refName := ctx.Params(":branchname") if len(refName) == 0 { refName = ctx.Params(":path") } // Check if the user is the same as the repository owner if ctx.IsSigned && ctx.User.LowerName == strings.ToLower(userName) { u = ctx.User } else { u, err = models.GetUserByName(userName) if err != nil { if models.IsErrUserNotExist(err) { ctx.Handle(404, "GetUserByName", err) } else { ctx.Handle(500, "GetUserByName", err) } return } } ctx.Repo.Owner = u // Get repository. repo, err := models.GetRepositoryByName(u.Id, repoName) if err != nil { if models.IsErrRepoNotExist(err) { ctx.Handle(404, "GetRepositoryByName", err) } else { ctx.Handle(500, "GetRepositoryByName", err) } return } else if err = repo.GetOwner(); err != nil { ctx.Handle(500, "GetOwner", err) return } mode, err := models.AccessLevel(ctx.User, repo) if err != nil { ctx.Handle(500, "AccessLevel", err) return } ctx.Repo.AccessMode = mode // Check access. if ctx.Repo.AccessMode == models.ACCESS_MODE_NONE { ctx.Handle(404, "no access right", err) return } ctx.Data["HasAccess"] = true if repo.IsMirror { ctx.Repo.Mirror, err = models.GetMirror(repo.ID) if err != nil { ctx.Handle(500, "GetMirror", err) return } ctx.Data["MirrorInterval"] = ctx.Repo.Mirror.Interval } ctx.Repo.Repository = repo ctx.Data["IsBareRepo"] = ctx.Repo.Repository.IsBare gitRepo, err := git.OpenRepository(models.RepoPath(userName, repoName)) if err != nil { ctx.Handle(500, "RepoAssignment Invalid repo "+models.RepoPath(userName, repoName), err) return } ctx.Repo.GitRepo = gitRepo ctx.Repo.RepoLink, err = repo.RepoLink() if err != nil { ctx.Handle(500, "RepoLink", err) return } ctx.Data["RepoLink"] = ctx.Repo.RepoLink ctx.Data["RepoRelPath"] = ctx.Repo.Owner.Name + "/" + ctx.Repo.Repository.Name tags, err := ctx.Repo.GitRepo.GetTags() if err != nil { ctx.Handle(500, "GetTags", err) return } ctx.Data["Tags"] = tags ctx.Repo.Repository.NumTags = len(tags) if repo.IsFork { RetrieveBaseRepo(ctx, repo) if ctx.Written() { return } } ctx.Data["Title"] = u.Name + "/" + repo.Name ctx.Data["Repository"] = repo ctx.Data["Owner"] = ctx.Repo.Repository.Owner ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner() ctx.Data["IsRepositoryAdmin"] = ctx.Repo.IsAdmin() ctx.Data["DisableSSH"] = setting.DisableSSH ctx.Repo.CloneLink, err = repo.CloneLink() if err != nil { ctx.Handle(500, "CloneLink", err) return } ctx.Data["CloneLink"] = ctx.Repo.CloneLink if ctx.Query("go-get") == "1" { ctx.Data["GoGetImport"] = fmt.Sprintf("%s/%s/%s", setting.Domain, u.Name, repo.Name) } if ctx.IsSigned { ctx.Data["IsWatchingRepo"] = models.IsWatching(ctx.User.Id, repo.ID) ctx.Data["IsStaringRepo"] = models.IsStaring(ctx.User.Id, repo.ID) } // repo is bare and display enable if ctx.Repo.Repository.IsBare { log.Debug("Bare repository: %s", ctx.Repo.RepoLink) // NOTE: to prevent templating error ctx.Data["BranchName"] = "" if displayBare { if !ctx.Repo.IsAdmin() { ctx.Flash.Info(ctx.Tr("repo.repo_is_empty"), true) } ctx.HTML(200, "repo/bare") } return } ctx.Data["TagName"] = ctx.Repo.TagName brs, err := ctx.Repo.GitRepo.GetBranches() if err != nil { ctx.Handle(500, "GetBranches", err) return } ctx.Data["Branches"] = brs ctx.Data["BrancheCount"] = len(brs) // If not branch selected, try default one. // If default branch doesn't exists, fall back to some other branch. if len(ctx.Repo.BranchName) == 0 { if len(ctx.Repo.Repository.DefaultBranch) > 0 && gitRepo.IsBranchExist(ctx.Repo.Repository.DefaultBranch) { ctx.Repo.BranchName = ctx.Repo.Repository.DefaultBranch } else if len(brs) > 0 { ctx.Repo.BranchName = brs[0] } } ctx.Data["BranchName"] = ctx.Repo.BranchName ctx.Data["CommitID"] = ctx.Repo.CommitID userAgent := ctx.Req.Header.Get("User-Agent") ua := user_agent.New(userAgent) browserName, browserVer := ua.Browser() ctx.Data["BrowserSupportsCopy"] = (browserName == "Chrome" && version.Compare(browserVer, CHROME_COPY_SUPPORT, ">=")) || (browserName == "Firefox" && version.Compare(browserVer, FIREFOX_COPY_SUPPORT, ">=")) } }
func RepoAssignment(redirect bool, args ...bool) macaron.Handler { return func(ctx *Context) { var ( displayBare bool // To display bare page if it is a bare repo. ) if len(args) >= 1 { displayBare = args[0] } var ( owner *models.User err error ) userName := ctx.Params(":username") repoName := ctx.Params(":reponame") refName := ctx.Params(":branchname") if len(refName) == 0 { refName = ctx.Params(":path") } // Check if the user is the same as the repository owner if ctx.IsSigned && ctx.User.LowerName == strings.ToLower(userName) { owner = ctx.User } else { owner, err = models.GetUserByName(userName) if err != nil { if models.IsErrUserNotExist(err) { ctx.Handle(404, "GetUserByName", err) } else { ctx.Handle(500, "GetUserByName", err) } return } } ctx.Repo.Owner = owner // Get repository. repo, err := models.GetRepositoryByName(owner.Id, repoName) if err != nil { if models.IsErrRepoNotExist(err) { ctx.Handle(404, "GetRepositoryByName", err) } else { ctx.Handle(500, "GetRepositoryByName", err) } return } else if err = repo.GetOwner(); err != nil { ctx.Handle(500, "GetOwner", err) return } // Admin has super access. if ctx.IsSigned && ctx.User.IsAdmin { ctx.Repo.AccessMode = models.ACCESS_MODE_OWNER } else { mode, err := models.AccessLevel(ctx.User, repo) if err != nil { ctx.Handle(500, "AccessLevel", err) return } ctx.Repo.AccessMode = mode } // Check access. if ctx.Repo.AccessMode == models.ACCESS_MODE_NONE { ctx.Handle(404, "no access right", err) return } ctx.Data["HasAccess"] = true if repo.IsMirror { ctx.Repo.Mirror, err = models.GetMirror(repo.ID) if err != nil { ctx.Handle(500, "GetMirror", err) return } ctx.Data["MirrorInterval"] = ctx.Repo.Mirror.Interval } ctx.Repo.Repository = repo ctx.Data["IsBareRepo"] = ctx.Repo.Repository.IsBare gitRepo, err := git.OpenRepository(models.RepoPath(userName, repoName)) if err != nil { ctx.Handle(500, "RepoAssignment Invalid repo "+models.RepoPath(userName, repoName), err) return } ctx.Repo.GitRepo = gitRepo ctx.Repo.RepoLink, err = repo.RepoLink() if err != nil { ctx.Handle(500, "RepoLink", err) return } ctx.Data["RepoLink"] = ctx.Repo.RepoLink ctx.Data["RepoRelPath"] = ctx.Repo.Owner.Name + "/" + ctx.Repo.Repository.Name tags, err := ctx.Repo.GitRepo.GetTags() if err != nil { ctx.Handle(500, "GetTags", err) return } ctx.Data["Tags"] = tags ctx.Repo.Repository.NumTags = len(tags) if repo.IsFork { RetrieveBaseRepo(ctx, repo) if ctx.Written() { return } } ctx.Data["Title"] = owner.Name + "/" + repo.Name ctx.Data["Repository"] = repo ctx.Data["Owner"] = ctx.Repo.Repository.Owner ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner() ctx.Data["IsRepositoryAdmin"] = ctx.Repo.IsAdmin() ctx.Data["DisableSSH"] = setting.DisableSSH ctx.Repo.CloneLink, err = repo.CloneLink() if err != nil { ctx.Handle(500, "CloneLink", err) return } ctx.Data["CloneLink"] = ctx.Repo.CloneLink if ctx.IsSigned { ctx.Data["IsWatchingRepo"] = models.IsWatching(ctx.User.Id, repo.ID) ctx.Data["IsStaringRepo"] = models.IsStaring(ctx.User.Id, repo.ID) } // repo is bare and display enable if ctx.Repo.Repository.IsBare { log.Debug("Bare repository: %s", ctx.Repo.RepoLink) // NOTE: to prevent templating error ctx.Data["BranchName"] = "" if displayBare { if !ctx.Repo.IsAdmin() { ctx.Flash.Info(ctx.Tr("repo.repo_is_empty"), true) } ctx.HTML(200, "repo/bare") } return } ctx.Data["TagName"] = ctx.Repo.TagName brs, err := ctx.Repo.GitRepo.GetBranches() if err != nil { ctx.Handle(500, "GetBranches", err) return } ctx.Data["Branches"] = brs ctx.Data["BrancheCount"] = len(brs) // If not branch selected, try default one. // If default branch doesn't exists, fall back to some other branch. if len(ctx.Repo.BranchName) == 0 { if len(ctx.Repo.Repository.DefaultBranch) > 0 && gitRepo.IsBranchExist(ctx.Repo.Repository.DefaultBranch) { ctx.Repo.BranchName = ctx.Repo.Repository.DefaultBranch } else if len(brs) > 0 { ctx.Repo.BranchName = brs[0] } } ctx.Data["BranchName"] = ctx.Repo.BranchName ctx.Data["CommitID"] = ctx.Repo.CommitID if ctx.Query("go-get") == "1" { ctx.Data["GoGetImport"] = path.Join(setting.Domain, setting.AppSubUrl, owner.Name, repo.Name) prefix := path.Join(setting.AppUrl, owner.Name, repo.Name, "src", ctx.Repo.BranchName) ctx.Data["GoDocDirectory"] = prefix + "{/dir}" ctx.Data["GoDocFile"] = prefix + "{/dir}/{file}#L{line}" } } }
func RepoAssignment(redirect bool, args ...bool) macaron.Handler { return func(ctx *Context) { var ( validBranch bool // To valid brach name. displayBare bool // To display bare page if it is a bare repo. ) if len(args) >= 1 { validBranch = args[0] } if len(args) >= 2 { displayBare = args[1] } var ( u *models.User err error ) userName := ctx.Params(":username") repoName := ctx.Params(":reponame") refName := ctx.Params(":branchname") if len(refName) == 0 { refName = ctx.Params(":path") } // Collaborators who have write access can be seen as owners. if ctx.IsSigned { ctx.Repo.IsOwner, err = models.HasAccess(ctx.User.Name, userName+"/"+repoName, models.WRITABLE) if err != nil { ctx.Handle(500, "HasAccess", err) return } ctx.Repo.IsTrueOwner = ctx.User.LowerName == strings.ToLower(userName) } if !ctx.Repo.IsTrueOwner { u, err = models.GetUserByName(userName) if err != nil { if err == models.ErrUserNotExist { ctx.Handle(404, "GetUserByName", err) } else if redirect { log.Error(4, "GetUserByName", err) ctx.Redirect("/") } else { ctx.Handle(500, "GetUserByName", err) } return } } else { u = ctx.User } if u == nil { if redirect { ctx.Redirect("/") return } ctx.Handle(404, "RepoAssignment", errors.New("invliad user account for single repository")) return } ctx.Repo.Owner = u // Organization owner team members are true owners as well. if ctx.IsSigned && ctx.Repo.Owner.IsOrganization() && ctx.Repo.Owner.IsOrgOwner(ctx.User.Id) { ctx.Repo.IsTrueOwner = true } // Get repository. repo, err := models.GetRepositoryByName(u.Id, repoName) if err != nil { if err == models.ErrRepoNotExist { ctx.Handle(404, "GetRepositoryByName", err) return } else if redirect { ctx.Redirect("/") return } ctx.Handle(500, "GetRepositoryByName", err) return } else if err = repo.GetOwner(); err != nil { ctx.Handle(500, "GetOwner", err) return } // Check if the mirror repository owner(mirror repository doesn't have access). if ctx.IsSigned && !ctx.Repo.IsOwner { if repo.OwnerId == ctx.User.Id { ctx.Repo.IsOwner = true } // Check if current user has admin permission to repository. if u.IsOrganization() { auth, err := models.GetHighestAuthorize(u.Id, ctx.User.Id, 0, repo.Id) if err != nil { ctx.Handle(500, "GetHighestAuthorize", err) return } if auth == models.ORG_ADMIN { ctx.Repo.IsOwner = true ctx.Repo.IsAdmin = true } } } // Check access. if repo.IsPrivate && !ctx.Repo.IsOwner { if ctx.User == nil { ctx.Handle(404, "HasAccess", nil) return } hasAccess, err := models.HasAccess(ctx.User.Name, ctx.Repo.Owner.Name+"/"+repo.Name, models.READABLE) if err != nil { ctx.Handle(500, "HasAccess", err) return } else if !hasAccess { ctx.Handle(404, "HasAccess", nil) return } } ctx.Repo.HasAccess = true ctx.Data["HasAccess"] = true if repo.IsMirror { ctx.Repo.Mirror, err = models.GetMirror(repo.Id) if err != nil { ctx.Handle(500, "GetMirror", err) return } ctx.Data["MirrorInterval"] = ctx.Repo.Mirror.Interval } repo.NumOpenIssues = repo.NumIssues - repo.NumClosedIssues repo.NumOpenMilestones = repo.NumMilestones - repo.NumClosedMilestones ctx.Repo.Repository = repo ctx.Data["IsBareRepo"] = ctx.Repo.Repository.IsBare gitRepo, err := git.OpenRepository(models.RepoPath(userName, repoName)) if err != nil { ctx.Handle(500, "RepoAssignment Invalid repo "+models.RepoPath(userName, repoName), err) return } ctx.Repo.GitRepo = gitRepo ctx.Repo.RepoLink = "/" + u.Name + "/" + repo.Name ctx.Data["RepoLink"] = ctx.Repo.RepoLink tags, err := ctx.Repo.GitRepo.GetTags() if err != nil { ctx.Handle(500, "GetTags", err) return } ctx.Repo.Repository.NumTags = len(tags) ctx.Data["Title"] = u.Name + "/" + repo.Name ctx.Data["Repository"] = repo ctx.Data["Owner"] = ctx.Repo.Repository.Owner ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner ctx.Data["IsRepositoryTrueOwner"] = ctx.Repo.IsTrueOwner if setting.SshPort != 22 { ctx.Repo.CloneLink.SSH = fmt.Sprintf("ssh://%s@%s:%d/%s/%s.git", setting.RunUser, setting.Domain, setting.SshPort, u.LowerName, repo.LowerName) } else { ctx.Repo.CloneLink.SSH = fmt.Sprintf("%s@%s:%s/%s.git", setting.RunUser, setting.Domain, u.LowerName, repo.LowerName) } ctx.Repo.CloneLink.HTTPS = fmt.Sprintf("%s%s/%s.git", setting.AppUrl, u.LowerName, repo.LowerName) ctx.Data["CloneLink"] = ctx.Repo.CloneLink if ctx.Repo.Repository.IsGoget { ctx.Data["GoGetLink"] = fmt.Sprintf("%s%s/%s", setting.AppUrl, u.LowerName, repo.LowerName) ctx.Data["GoGetImport"] = fmt.Sprintf("%s/%s/%s", setting.Domain, u.LowerName, repo.LowerName) } // when repo is bare, not valid branch if !ctx.Repo.Repository.IsBare && validBranch { detect: if len(refName) > 0 { if gitRepo.IsBranchExist(refName) { ctx.Repo.IsBranch = true ctx.Repo.BranchName = refName ctx.Repo.Commit, err = gitRepo.GetCommitOfBranch(refName) if err != nil { ctx.Handle(404, "RepoAssignment invalid branch", nil) return } ctx.Repo.CommitId = ctx.Repo.Commit.Id.String() } else if gitRepo.IsTagExist(refName) { ctx.Repo.IsTag = true ctx.Repo.BranchName = refName ctx.Repo.Tag, err = gitRepo.GetTag(refName) if err != nil { ctx.Handle(404, "RepoAssignment invalid tag", nil) return } ctx.Repo.Commit, _ = ctx.Repo.Tag.Commit() ctx.Repo.CommitId = ctx.Repo.Commit.Id.String() } else if len(refName) == 40 { ctx.Repo.IsCommit = true ctx.Repo.CommitId = refName ctx.Repo.BranchName = refName ctx.Repo.Commit, err = gitRepo.GetCommit(refName) if err != nil { ctx.Handle(404, "RepoAssignment invalid commit", nil) return } } else { ctx.Handle(404, "RepoAssignment invalid repo", errors.New("branch or tag not exist")) return } } else { if len(refName) == 0 { if gitRepo.IsBranchExist(ctx.Repo.Repository.DefaultBranch) { refName = ctx.Repo.Repository.DefaultBranch } else { brs, err := gitRepo.GetBranches() if err != nil { ctx.Handle(500, "GetBranches", err) return } refName = brs[0] } } goto detect } ctx.Data["IsBranch"] = ctx.Repo.IsBranch ctx.Data["IsCommit"] = ctx.Repo.IsCommit ctx.Repo.CommitsCount, err = ctx.Repo.Commit.CommitsCount() if err != nil { ctx.Handle(500, "CommitsCount", err) return } ctx.Data["CommitsCount"] = ctx.Repo.CommitsCount } // repo is bare and display enable if ctx.Repo.Repository.IsBare { log.Debug("Bare repository: %s", ctx.Repo.RepoLink) if displayBare { ctx.HTML(200, "repo/bare") } return } if ctx.IsSigned { ctx.Data["IsWatchingRepo"] = models.IsWatching(ctx.User.Id, repo.Id) ctx.Data["IsStaringRepo"] = models.IsStaring(ctx.User.Id, repo.Id) } ctx.Data["TagName"] = ctx.Repo.TagName brs, err := ctx.Repo.GitRepo.GetBranches() if err != nil { log.Error(4, "GetBranches: %v", err) } ctx.Data["Branches"] = brs ctx.Data["BrancheCount"] = len(brs) // If not branch selected, try default one. // If default branch doesn't exists, fall back to some other branch. if ctx.Repo.BranchName == "" { if ctx.Repo.Repository.DefaultBranch != "" && gitRepo.IsBranchExist(ctx.Repo.Repository.DefaultBranch) { ctx.Repo.BranchName = ctx.Repo.Repository.DefaultBranch } else if len(brs) > 0 { ctx.Repo.BranchName = brs[0] } } ctx.Data["BranchName"] = ctx.Repo.BranchName ctx.Data["CommitId"] = ctx.Repo.CommitId } }
// Merge merges pull request to base repository. func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository) (err error) { sess := x.NewSession() defer sessionRelease(sess) if err = sess.Begin(); err != nil { return err } if err = pr.Issue.changeStatus(sess, doer, true); err != nil { return fmt.Errorf("Issue.changeStatus: %v", err) } if err = pr.getHeadRepo(sess); err != nil { return fmt.Errorf("getHeadRepo: %v", err) } headRepoPath := RepoPath(pr.HeadUserName, pr.HeadRepo.Name) headGitRepo, err := git.OpenRepository(headRepoPath) if err != nil { return fmt.Errorf("OpenRepository: %v", err) } pr.MergedCommitID, err = headGitRepo.GetCommitIdOfBranch(pr.HeadBranch) if err != nil { return fmt.Errorf("GetCommitIdOfBranch: %v", err) } if err = mergePullRequestAction(sess, doer, pr.Issue.Repo, pr.Issue); err != nil { return fmt.Errorf("mergePullRequestAction: %v", err) } pr.HasMerged = true pr.Merged = time.Now() pr.MergerID = doer.Id if _, err = sess.Id(pr.ID).AllCols().Update(pr); err != nil { return fmt.Errorf("update pull request: %v", err) } // Clone base repo. tmpBasePath := path.Join(setting.AppDataPath, "tmp/repos", com.ToStr(time.Now().Nanosecond())+".git") os.MkdirAll(path.Dir(tmpBasePath), os.ModePerm) defer os.RemoveAll(path.Dir(tmpBasePath)) var stderr string if _, stderr, err = process.ExecTimeout(5*time.Minute, fmt.Sprintf("PullRequest.Merge (git clone): %s", tmpBasePath), "git", "clone", baseGitRepo.Path, tmpBasePath); err != nil { return fmt.Errorf("git clone: %s", stderr) } // Check out base branch. if _, stderr, err = process.ExecDir(-1, tmpBasePath, fmt.Sprintf("PullRequest.Merge (git checkout): %s", tmpBasePath), "git", "checkout", pr.BaseBranch); err != nil { return fmt.Errorf("git checkout: %s", stderr) } // Add head repo remote. if _, stderr, err = process.ExecDir(-1, tmpBasePath, fmt.Sprintf("PullRequest.Merge (git remote add): %s", tmpBasePath), "git", "remote", "add", "head_repo", headRepoPath); err != nil { return fmt.Errorf("git remote add [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr) } // Merge commits. if _, stderr, err = process.ExecDir(-1, tmpBasePath, fmt.Sprintf("PullRequest.Merge (git fetch): %s", tmpBasePath), "git", "fetch", "head_repo"); err != nil { return fmt.Errorf("git fetch [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr) } if _, stderr, err = process.ExecDir(-1, tmpBasePath, fmt.Sprintf("PullRequest.Merge (git merge --no-ff --no-commit): %s", tmpBasePath), "git", "merge", "--no-ff", "--no-commit", "head_repo/"+pr.HeadBranch); err != nil { return fmt.Errorf("git merge --no-ff --no-commit [%s]: %v - %s", tmpBasePath, err, stderr) } sig := doer.NewGitSig() if _, stderr, err = process.ExecDir(-1, tmpBasePath, fmt.Sprintf("PullRequest.Merge (git merge): %s", tmpBasePath), "git", "commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email), "-m", fmt.Sprintf("Merge branch '%s' of %s/%s into %s", pr.HeadBranch, pr.HeadUserName, pr.HeadRepo.Name, pr.BaseBranch)); err != nil { return fmt.Errorf("git commit [%s]: %v - %s", tmpBasePath, err, stderr) } // Push back to upstream. if _, stderr, err = process.ExecDir(-1, tmpBasePath, fmt.Sprintf("PullRequest.Merge (git push): %s", tmpBasePath), "git", "push", baseGitRepo.Path, pr.BaseBranch); err != nil { return fmt.Errorf("git push: %s", stderr) } return sess.Commit() }