mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-26 12:27:06 +00:00 
			
		
		
		
	Allow compare page to look up base, head, own-fork, forkbase-of-head (#11327)
* Allow compare page to look up base, head, own-fork, forkbase-of-head Signed-off-by: Andrew Thornton <art27@cantab.net> * as per @guillep2k Signed-off-by: Andrew Thornton <art27@cantab.net> * Update routers/repo/compare.go * as per @guillep2k Signed-off-by: Andrew Thornton <art27@cantab.net> * Rationalise the names a little Signed-off-by: Andrew Thornton <art27@cantab.net> * Rationalise the names a little (2) Signed-off-by: Andrew Thornton <art27@cantab.net> * Fix 500 with fork of fork Signed-off-by: Andrew Thornton <art27@cantab.net> * Prevent 500 on compare different trees Signed-off-by: Andrew Thornton <art27@cantab.net> * dotdotdot is perfectly valid in both usernames and repo names Signed-off-by: Andrew Thornton <art27@cantab.net> * ensure we can set the head and base repos too Signed-off-by: Andrew Thornton <art27@cantab.net> * ensure we can set the head and base repos too (2) Signed-off-by: Andrew Thornton <art27@cantab.net> * fix lint Signed-off-by: Andrew Thornton <art27@cantab.net> * only set headRepo == baseRepo if isSameRepo Signed-off-by: Andrew Thornton <art27@cantab.net>
This commit is contained in:
		| @@ -529,10 +529,6 @@ func GetCommitFileStatus(repoPath, commitID string) (*CommitFileStatus, error) { | |||||||
|  |  | ||||||
| // GetFullCommitID returns full length (40) of commit ID by given short SHA in a repository. | // GetFullCommitID returns full length (40) of commit ID by given short SHA in a repository. | ||||||
| func GetFullCommitID(repoPath, shortID string) (string, error) { | func GetFullCommitID(repoPath, shortID string) (string, error) { | ||||||
| 	if len(shortID) >= 40 { |  | ||||||
| 		return shortID, nil |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	commitID, err := NewCommand("rev-parse", shortID).RunInDir(repoPath) | 	commitID, err := NewCommand("rev-parse", shortID).RunInDir(repoPath) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		if strings.Contains(err.Error(), "exit status 128") { | 		if strings.Contains(err.Error(), "exit status 128") { | ||||||
|   | |||||||
| @@ -89,7 +89,6 @@ func (repo *Repository) GetCompareInfo(basePath, baseBranch, headBranch string) | |||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 	compareInfo.NumFiles = len(strings.Split(stdout, "\n")) - 1 | 	compareInfo.NumFiles = len(strings.Split(stdout, "\n")) - 1 | ||||||
|  |  | ||||||
| 	return compareInfo, nil | 	return compareInfo, nil | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -71,25 +71,45 @@ func ParseCompareInfo(ctx *context.Context) (*models.User, *models.Repository, * | |||||||
| 	baseRepo := ctx.Repo.Repository | 	baseRepo := ctx.Repo.Repository | ||||||
|  |  | ||||||
| 	// Get compared branches information | 	// Get compared branches information | ||||||
|  | 	// A full compare url is of the form: | ||||||
|  | 	// | ||||||
|  | 	// 1. /{:baseOwner}/{:baseRepoName}/compare/{:baseBranch}...{:headBranch} | ||||||
|  | 	// 2. /{:baseOwner}/{:baseRepoName}/compare/{:baseBranch}...{:headOwner}:{:headBranch} | ||||||
|  | 	// 3. /{:baseOwner}/{:baseRepoName}/compare/{:baseBranch}...{:headOwner}/{:headRepoName}:{:headBranch} | ||||||
|  | 	// | ||||||
|  | 	// Here we obtain the infoPath "{:baseBranch}...[{:headOwner}/{:headRepoName}:]{:headBranch}" as ctx.Params("*") | ||||||
|  | 	// with the :baseRepo in ctx.Repo. | ||||||
|  | 	// | ||||||
|  | 	// Note: Generally :headRepoName is not provided here - we are only passed :headOwner. | ||||||
|  | 	// | ||||||
|  | 	// How do we determine the :headRepo? | ||||||
|  | 	// | ||||||
|  | 	// 1. If :headOwner is not set then the :headRepo = :baseRepo | ||||||
|  | 	// 2. If :headOwner is set - then look for the fork of :baseRepo owned by :headOwner | ||||||
|  | 	// 3. But... :baseRepo could be a fork of :headOwner's repo - so check that | ||||||
|  | 	// 4. Now, :baseRepo and :headRepos could be forks of the same repo - so check that | ||||||
|  | 	// | ||||||
| 	// format: <base branch>...[<head repo>:]<head branch> | 	// format: <base branch>...[<head repo>:]<head branch> | ||||||
| 	// base<-head: master...head:feature | 	// base<-head: master...head:feature | ||||||
| 	// same repo: master...feature | 	// same repo: master...feature | ||||||
|  |  | ||||||
| 	var ( | 	var ( | ||||||
| 		headUser   *models.User | 		headUser   *models.User | ||||||
|  | 		headRepo   *models.Repository | ||||||
| 		headBranch string | 		headBranch string | ||||||
| 		isSameRepo bool | 		isSameRepo bool | ||||||
| 		infoPath   string | 		infoPath   string | ||||||
| 		err        error | 		err        error | ||||||
| 	) | 	) | ||||||
| 	infoPath = ctx.Params("*") | 	infoPath = ctx.Params("*") | ||||||
| 	infos := strings.Split(infoPath, "...") | 	infos := strings.SplitN(infoPath, "...", 2) | ||||||
| 	if len(infos) != 2 { | 	if len(infos) != 2 { | ||||||
| 		log.Trace("ParseCompareInfo[%d]: not enough compared branches information %s", baseRepo.ID, infos) | 		log.Trace("ParseCompareInfo[%d]: not enough compared branches information %s", baseRepo.ID, infos) | ||||||
| 		ctx.NotFound("CompareAndPullRequest", nil) | 		ctx.NotFound("CompareAndPullRequest", nil) | ||||||
| 		return nil, nil, nil, nil, "", "" | 		return nil, nil, nil, nil, "", "" | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	ctx.Data["BaseName"] = baseRepo.OwnerName | ||||||
| 	baseBranch := infos[0] | 	baseBranch := infos[0] | ||||||
| 	ctx.Data["BaseBranch"] = baseBranch | 	ctx.Data["BaseBranch"] = baseBranch | ||||||
|  |  | ||||||
| @@ -101,17 +121,44 @@ func ParseCompareInfo(ctx *context.Context) (*models.User, *models.Repository, * | |||||||
| 		headBranch = headInfos[0] | 		headBranch = headInfos[0] | ||||||
|  |  | ||||||
| 	} else if len(headInfos) == 2 { | 	} else if len(headInfos) == 2 { | ||||||
| 		headUser, err = models.GetUserByName(headInfos[0]) | 		headInfosSplit := strings.Split(headInfos[0], "/") | ||||||
| 		if err != nil { | 		if len(headInfosSplit) == 1 { | ||||||
| 			if models.IsErrUserNotExist(err) { | 			headUser, err = models.GetUserByName(headInfos[0]) | ||||||
| 				ctx.NotFound("GetUserByName", nil) | 			if err != nil { | ||||||
| 			} else { | 				if models.IsErrUserNotExist(err) { | ||||||
| 				ctx.ServerError("GetUserByName", err) | 					ctx.NotFound("GetUserByName", nil) | ||||||
|  | 				} else { | ||||||
|  | 					ctx.ServerError("GetUserByName", err) | ||||||
|  | 				} | ||||||
|  | 				return nil, nil, nil, nil, "", "" | ||||||
| 			} | 			} | ||||||
| 			return nil, nil, nil, nil, "", "" | 			headBranch = headInfos[1] | ||||||
|  | 			isSameRepo = headUser.ID == ctx.Repo.Owner.ID | ||||||
|  | 			if isSameRepo { | ||||||
|  | 				headRepo = baseRepo | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			headRepo, err = models.GetRepositoryByOwnerAndName(headInfosSplit[0], headInfosSplit[1]) | ||||||
|  | 			if err != nil { | ||||||
|  | 				if models.IsErrRepoNotExist(err) { | ||||||
|  | 					ctx.NotFound("GetRepositoryByOwnerAndName", nil) | ||||||
|  | 				} else { | ||||||
|  | 					ctx.ServerError("GetRepositoryByOwnerAndName", err) | ||||||
|  | 				} | ||||||
|  | 				return nil, nil, nil, nil, "", "" | ||||||
|  | 			} | ||||||
|  | 			if err := headRepo.GetOwner(); err != nil { | ||||||
|  | 				if models.IsErrUserNotExist(err) { | ||||||
|  | 					ctx.NotFound("GetUserByName", nil) | ||||||
|  | 				} else { | ||||||
|  | 					ctx.ServerError("GetUserByName", err) | ||||||
|  | 				} | ||||||
|  | 				return nil, nil, nil, nil, "", "" | ||||||
|  | 			} | ||||||
|  | 			headBranch = headInfos[1] | ||||||
|  | 			headUser = headRepo.Owner | ||||||
|  | 			isSameRepo = headRepo.ID == ctx.Repo.Repository.ID | ||||||
| 		} | 		} | ||||||
| 		headBranch = headInfos[1] |  | ||||||
| 		isSameRepo = headUser.ID == ctx.Repo.Owner.ID |  | ||||||
| 	} else { | 	} else { | ||||||
| 		ctx.NotFound("CompareAndPullRequest", nil) | 		ctx.NotFound("CompareAndPullRequest", nil) | ||||||
| 		return nil, nil, nil, nil, "", "" | 		return nil, nil, nil, nil, "", "" | ||||||
| @@ -139,20 +186,80 @@ func ParseCompareInfo(ctx *context.Context) (*models.User, *models.Repository, * | |||||||
| 	ctx.Data["BaseIsBranch"] = baseIsBranch | 	ctx.Data["BaseIsBranch"] = baseIsBranch | ||||||
| 	ctx.Data["BaseIsTag"] = baseIsTag | 	ctx.Data["BaseIsTag"] = baseIsTag | ||||||
|  |  | ||||||
| 	// Check if current user has fork of repository or in the same repository. | 	// Now we have the repository that represents the base | ||||||
| 	headRepo, has := models.HasForkedRepo(headUser.ID, baseRepo.ID) |  | ||||||
| 	if !has && !isSameRepo { | 	// The current base and head repositories and branches may not | ||||||
|  | 	// actually be the intended branches that the user wants to | ||||||
|  | 	// create a pull-request from - but also determining the head | ||||||
|  | 	// repo is difficult. | ||||||
|  |  | ||||||
|  | 	// We will want therefore to offer a few repositories to set as | ||||||
|  | 	// our base and head | ||||||
|  |  | ||||||
|  | 	// 1. First if the baseRepo is a fork get the "RootRepo" it was | ||||||
|  | 	// forked from | ||||||
|  | 	var rootRepo *models.Repository | ||||||
|  | 	if baseRepo.IsFork { | ||||||
|  | 		err = baseRepo.GetBaseRepo() | ||||||
|  | 		if err != nil { | ||||||
|  | 			if !models.IsErrRepoNotExist(err) { | ||||||
|  | 				ctx.ServerError("Unable to find root repo", err) | ||||||
|  | 				return nil, nil, nil, nil, "", "" | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			rootRepo = baseRepo.BaseRepo | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// 2. Now if the current user is not the owner of the baseRepo, | ||||||
|  | 	// check if they have a fork of the base repo and offer that as | ||||||
|  | 	// "OwnForkRepo" | ||||||
|  | 	var ownForkRepo *models.Repository | ||||||
|  | 	if baseRepo.OwnerID != ctx.User.ID { | ||||||
|  | 		repo, has := models.HasForkedRepo(ctx.User.ID, baseRepo.ID) | ||||||
|  | 		if has { | ||||||
|  | 			ownForkRepo = repo | ||||||
|  | 			ctx.Data["OwnForkRepo"] = ownForkRepo | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	has := headRepo != nil | ||||||
|  | 	// 3. If the base is a forked from "RootRepo" and the owner of | ||||||
|  | 	// the "RootRepo" is the :headUser - set headRepo to that | ||||||
|  | 	if !has && rootRepo != nil && rootRepo.OwnerID == headUser.ID { | ||||||
|  | 		headRepo = rootRepo | ||||||
|  | 		has = true | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// 4. If the ctx.User has their own fork of the baseRepo and the headUser is the ctx.User | ||||||
|  | 	// set the headRepo to the ownFork | ||||||
|  | 	if !has && ownForkRepo != nil && ownForkRepo.OwnerID == headUser.ID { | ||||||
|  | 		headRepo = ownForkRepo | ||||||
|  | 		has = true | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// 5. If the headOwner has a fork of the baseRepo - use that | ||||||
|  | 	if !has { | ||||||
|  | 		headRepo, has = models.HasForkedRepo(headUser.ID, baseRepo.ID) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// 6. If the baseRepo is a fork and the headUser has a fork of that use that | ||||||
|  | 	if !has && baseRepo.IsFork { | ||||||
|  | 		headRepo, has = models.HasForkedRepo(headUser.ID, baseRepo.ForkID) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// 7. Otherwise if we're not the same repo and haven't found a repo give up | ||||||
|  | 	if !isSameRepo && !has { | ||||||
| 		ctx.Data["PageIsComparePull"] = false | 		ctx.Data["PageIsComparePull"] = false | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	// 8. Finally open the git repo | ||||||
| 	var headGitRepo *git.Repository | 	var headGitRepo *git.Repository | ||||||
| 	if isSameRepo { | 	if isSameRepo { | ||||||
| 		headRepo = ctx.Repo.Repository | 		headRepo = ctx.Repo.Repository | ||||||
| 		headGitRepo = ctx.Repo.GitRepo | 		headGitRepo = ctx.Repo.GitRepo | ||||||
| 		ctx.Data["BaseName"] = headUser.Name | 	} else if has { | ||||||
| 	} else { | 		headGitRepo, err = git.OpenRepository(headRepo.RepoPath()) | ||||||
| 		headGitRepo, err = git.OpenRepository(models.RepoPath(headUser.Name, headRepo.Name)) |  | ||||||
| 		ctx.Data["BaseName"] = baseRepo.OwnerName |  | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			ctx.ServerError("OpenRepository", err) | 			ctx.ServerError("OpenRepository", err) | ||||||
| 			return nil, nil, nil, nil, "", "" | 			return nil, nil, nil, nil, "", "" | ||||||
| @@ -160,7 +267,11 @@ func ParseCompareInfo(ctx *context.Context) (*models.User, *models.Repository, * | |||||||
| 		defer headGitRepo.Close() | 		defer headGitRepo.Close() | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// user should have permission to read baseRepo's codes and pulls, NOT headRepo's | 	ctx.Data["HeadRepo"] = headRepo | ||||||
|  |  | ||||||
|  | 	// Now we need to assert that the ctx.User has permission to read | ||||||
|  | 	// the baseRepo's code and pulls | ||||||
|  | 	// (NOT headRepo's) | ||||||
| 	permBase, err := models.GetUserRepoPermission(baseRepo, ctx.User) | 	permBase, err := models.GetUserRepoPermission(baseRepo, ctx.User) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		ctx.ServerError("GetUserRepoPermission", err) | 		ctx.ServerError("GetUserRepoPermission", err) | ||||||
| @@ -177,8 +288,9 @@ func ParseCompareInfo(ctx *context.Context) (*models.User, *models.Repository, * | |||||||
| 		return nil, nil, nil, nil, "", "" | 		return nil, nil, nil, nil, "", "" | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	// If we're not merging from the same repo: | ||||||
| 	if !isSameRepo { | 	if !isSameRepo { | ||||||
| 		// user should have permission to read headrepo's codes | 		// Assert ctx.User has permission to read headRepo's codes | ||||||
| 		permHead, err := models.GetUserRepoPermission(headRepo, ctx.User) | 		permHead, err := models.GetUserRepoPermission(headRepo, ctx.User) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			ctx.ServerError("GetUserRepoPermission", err) | 			ctx.ServerError("GetUserRepoPermission", err) | ||||||
| @@ -196,6 +308,44 @@ func ParseCompareInfo(ctx *context.Context) (*models.User, *models.Repository, * | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	// If we have a rootRepo and it's different from: | ||||||
|  | 	// 1. the computed base | ||||||
|  | 	// 2. the computed head | ||||||
|  | 	// then get the branches of it | ||||||
|  | 	if rootRepo != nil && | ||||||
|  | 		rootRepo.ID != headRepo.ID && | ||||||
|  | 		rootRepo.ID != baseRepo.ID { | ||||||
|  | 		perm, branches, err := getBranchesForRepo(ctx.User, rootRepo) | ||||||
|  | 		if err != nil { | ||||||
|  | 			ctx.ServerError("GetBranchesForRepo", err) | ||||||
|  | 			return nil, nil, nil, nil, "", "" | ||||||
|  | 		} | ||||||
|  | 		if perm { | ||||||
|  | 			ctx.Data["RootRepo"] = rootRepo | ||||||
|  | 			ctx.Data["RootRepoBranches"] = branches | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// If we have a ownForkRepo and it's different from: | ||||||
|  | 	// 1. The computed base | ||||||
|  | 	// 2. The computed hea | ||||||
|  | 	// 3. The rootRepo (if we have one) | ||||||
|  | 	// then get the branches from it. | ||||||
|  | 	if ownForkRepo != nil && | ||||||
|  | 		ownForkRepo.ID != headRepo.ID && | ||||||
|  | 		ownForkRepo.ID != baseRepo.ID && | ||||||
|  | 		(rootRepo == nil || ownForkRepo.ID != rootRepo.ID) { | ||||||
|  | 		perm, branches, err := getBranchesForRepo(ctx.User, ownForkRepo) | ||||||
|  | 		if err != nil { | ||||||
|  | 			ctx.ServerError("GetBranchesForRepo", err) | ||||||
|  | 			return nil, nil, nil, nil, "", "" | ||||||
|  | 		} | ||||||
|  | 		if perm { | ||||||
|  | 			ctx.Data["OwnForkRepo"] = ownForkRepo | ||||||
|  | 			ctx.Data["OwnForkRepoBranches"] = branches | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	// Check if head branch is valid. | 	// Check if head branch is valid. | ||||||
| 	headIsCommit := headGitRepo.IsCommitExist(headBranch) | 	headIsCommit := headGitRepo.IsCommitExist(headBranch) | ||||||
| 	headIsBranch := headGitRepo.IsBranchExist(headBranch) | 	headIsBranch := headGitRepo.IsBranchExist(headBranch) | ||||||
| @@ -343,28 +493,25 @@ func PrepareCompareDiff( | |||||||
| 	return false | 	return false | ||||||
| } | } | ||||||
|  |  | ||||||
| // parseBaseRepoInfo parse base repository if current repo is forked. | func getBranchesForRepo(user *models.User, repo *models.Repository) (bool, []string, error) { | ||||||
| // The "base" here means the repository where current repo forks from, | 	perm, err := models.GetUserRepoPermission(repo, user) | ||||||
| // not the repository fetch from current URL. |  | ||||||
| func parseBaseRepoInfo(ctx *context.Context, repo *models.Repository) error { |  | ||||||
| 	if !repo.IsFork { |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
| 	if err := repo.GetBaseRepo(); err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	baseGitRepo, err := git.OpenRepository(repo.BaseRepo.RepoPath()) |  | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return false, nil, err | ||||||
| 	} | 	} | ||||||
| 	defer baseGitRepo.Close() | 	if !perm.CanRead(models.UnitTypeCode) { | ||||||
|  | 		return false, nil, nil | ||||||
| 	ctx.Data["BaseRepoBranches"], err = baseGitRepo.GetBranches() | 	} | ||||||
|  | 	gitRepo, err := git.OpenRepository(repo.RepoPath()) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return false, nil, err | ||||||
| 	} | 	} | ||||||
| 	return nil | 	defer gitRepo.Close() | ||||||
|  |  | ||||||
|  | 	branches, err := gitRepo.GetBranches() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return false, nil, err | ||||||
|  | 	} | ||||||
|  | 	return true, branches, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| // CompareDiff show different from one commit to another commit | // CompareDiff show different from one commit to another commit | ||||||
| @@ -375,12 +522,6 @@ func CompareDiff(ctx *context.Context) { | |||||||
| 	} | 	} | ||||||
| 	defer headGitRepo.Close() | 	defer headGitRepo.Close() | ||||||
|  |  | ||||||
| 	var err error |  | ||||||
| 	if err = parseBaseRepoInfo(ctx, headRepo); err != nil { |  | ||||||
| 		ctx.ServerError("parseBaseRepoInfo", err) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	nothingToCompare := PrepareCompareDiff(ctx, headUser, headRepo, headGitRepo, compareInfo, baseBranch, headBranch) | 	nothingToCompare := PrepareCompareDiff(ctx, headUser, headRepo, headGitRepo, compareInfo, baseBranch, headBranch) | ||||||
| 	if ctx.Written() { | 	if ctx.Written() { | ||||||
| 		return | 		return | ||||||
|   | |||||||
| @@ -26,11 +26,21 @@ | |||||||
| 					</div> | 					</div> | ||||||
| 					<div class="scrolling menu"> | 					<div class="scrolling menu"> | ||||||
| 						{{range .Branches}} | 						{{range .Branches}} | ||||||
| 							<div class="item {{if eq $.BaseBranch .}}selected{{end}}" data-url="{{$.RepoLink}}/compare/{{EscapePound .}}...{{if not $.PullRequestCtx.SameRepo}}{{$.HeadUser.Name}}:{{end}}{{EscapePound $.HeadBranch}}">{{$.BaseName}}:{{.}}</div> | 							<div class="item {{if eq $.BaseBranch .}}selected{{end}}" data-url="{{$.RepoLink}}/compare/{{EscapePound .}}...{{if not $.PullRequestCtx.SameRepo}}{{$.HeadUser.Name}}/{{$.HeadRepo.Name}}:{{end}}{{EscapePound $.HeadBranch}}">{{$.BaseName}}:{{.}}</div> | ||||||
| 						{{end}} | 						{{end}} | ||||||
| 						{{if .Repository.IsFork}} | 						{{if not .PullRequestCtx.SameRepo}} | ||||||
| 							{{range .BaseRepoBranches}} | 							{{range .HeadBranches}} | ||||||
| 							<div class="item" data-url="{{$.PullRequestCtx.BaseRepo.Link}}/compare/{{EscapePound .}}...{{$.HeadUser.Name}}:{{EscapePound $.HeadBranch}}">{{$.PullRequestCtx.BaseRepo.OwnerName}}:{{.}}</div> | 								<div class="item" data-url="{{$.HeadRepo.Link}}/compare/{{EscapePound .}}...{{$.HeadUser.Name}}/{{$.HeadRepo.Name}}:{{EscapePound $.HeadBranch}}">{{$.HeadUser.Name}}:{{.}}</div> | ||||||
|  | 							{{end}} | ||||||
|  | 						{{end}} | ||||||
|  | 						{{if .OwnForkRepo}} | ||||||
|  | 							{{range .OwnForkRepoBranches}} | ||||||
|  | 								<div class="item" data-url="{{$.OwnForkRepo.Link}}/compare/{{EscapePound .}}...{{$.HeadUser.Name}}/{{$.HeadRepo.Name}}:{{EscapePound $.HeadBranch}}">{{$.OwnForkRepo.OwnerName}}:{{.}}</div> | ||||||
|  | 							{{end}} | ||||||
|  | 						{{end}} | ||||||
|  | 						{{if .RootRepo}} | ||||||
|  | 							{{range .RootRepoBranches}} | ||||||
|  | 								<div class="item" data-url="{{$.RootRepo.Link}}/compare/{{EscapePound .}}...{{$.HeadUser.Name}}/{{$.HeadRepo.Name}}:{{EscapePound $.HeadBranch}}">{{$.RootRepo.OwnerName}}:{{.}}</div> | ||||||
| 							{{end}} | 							{{end}} | ||||||
| 						{{end}} | 						{{end}} | ||||||
| 					</div> | 					</div> | ||||||
| @@ -49,7 +59,22 @@ | |||||||
| 					</div> | 					</div> | ||||||
| 					<div class="scrolling menu"> | 					<div class="scrolling menu"> | ||||||
| 						{{range .HeadBranches}} | 						{{range .HeadBranches}} | ||||||
| 							<div class="{{if eq $.HeadBranch .}}selected{{end}} item" data-url="{{$.RepoLink}}/compare/{{EscapePound $.BaseBranch}}...{{if not $.PullRequestCtx.SameRepo}}{{$.HeadUser.Name}}:{{end}}{{EscapePound .}}">{{$.HeadUser.Name}}:{{.}}</div> | 							<div class="{{if eq $.HeadBranch .}}selected{{end}} item" data-url="{{$.RepoLink}}/compare/{{EscapePound $.BaseBranch}}...{{if not $.PullRequestCtx.SameRepo}}{{$.HeadUser.Name}}/{{$.HeadRepo.Name}}:{{end}}{{EscapePound .}}">{{$.HeadUser.Name}}:{{.}}</div> | ||||||
|  | 						{{end}} | ||||||
|  | 						{{if not .PullRequestCtx.SameRepo}} | ||||||
|  | 							{{range .Branches}} | ||||||
|  | 								<div class="item" data-url="{{$.RepoLink}}/compare/{{EscapePound $.BaseBranch}}...{{$.BaseName}}/{{$.Repository.Name}}:{{EscapePound .}}">{{$.BaseName}}:{{.}}</div> | ||||||
|  | 							{{end}} | ||||||
|  | 						{{end}} | ||||||
|  | 						{{if .OwnForkRepo}} | ||||||
|  | 							{{range .OwnForkRepoBranches}} | ||||||
|  | 								<div class="item" data-url="{{$.RepoLink}}/compare/{{EscapePound $.BaseBranch}}...{{$.OwnForkRepo.OwnerName}}/{{$.OwnForkRepo.Name}}:{{EscapePound .}}">{{$.OwnForkRepo.OwnerName}}:{{.}}</div> | ||||||
|  | 							{{end}} | ||||||
|  | 						{{end}} | ||||||
|  | 						{{if .RootRepo}} | ||||||
|  | 							{{range .RootRepoBranches}} | ||||||
|  | 								<div class="item" data-url="{{$.RepoLink}}/compare/{{EscapePound $.BaseBranch}}...{{$.RootRepo.OwnerName}}/{{$.RootRepo.Name}}:{{EscapePound .}}">{{$.RootRepo.OwnerName}}:{{.}}</div> | ||||||
|  | 							{{end}} | ||||||
| 						{{end}} | 						{{end}} | ||||||
| 					</div> | 					</div> | ||||||
| 				</div> | 				</div> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 zeripath
					zeripath