diff --git a/models/issue_comment.go b/models/issue_comment.go index 452afc79f0..94fca493e0 100644 --- a/models/issue_comment.go +++ b/models/issue_comment.go @@ -1157,12 +1157,11 @@ func getCommitIDsFromRepo(repo *Repository, oldCommitID, newCommitID, baseBranch return nil, false, err } - oldCommitBranch, err := oldCommit.GetBranchName() - if err != nil { + if err = oldCommit.LoadBranchName(); err != nil { return nil, false, err } - if oldCommitBranch == "" { + if len(oldCommit.Branch) == 0 { commitIDs = make([]string, 2) commitIDs[0] = oldCommitID commitIDs[1] = newCommitID @@ -1175,25 +1174,102 @@ func getCommitIDsFromRepo(repo *Repository, oldCommitID, newCommitID, baseBranch return nil, false, err } - var commits *list.List + var ( + commits *list.List + commitChecks map[string]commitBranchCheckItem + ) commits, err = newCommit.CommitsBeforeUntil(oldCommitID) if err != nil { return nil, false, err } commitIDs = make([]string, 0, commits.Len()) + commitChecks = make(map[string]commitBranchCheckItem) + + for e := commits.Front(); e != nil; e = e.Next() { + commitChecks[e.Value.(*git.Commit).ID.String()] = commitBranchCheckItem{ + Commit: e.Value.(*git.Commit), + Checked: false, + } + } + + if err = commitBranchCheck(gitRepo, newCommit, oldCommitID, baseBranch, commitChecks); err != nil { + return + } for e := commits.Back(); e != nil; e = e.Prev() { - commit := e.Value.(*git.Commit) - commitBranch, err := commit.GetBranchName() - if err != nil { - return nil, false, err - } - - if commitBranch != baseBranch { - commitIDs = append(commitIDs, commit.ID.String()) + commitID := e.Value.(*git.Commit).ID.String() + if item, ok := commitChecks[commitID]; ok && item.Checked { + commitIDs = append(commitIDs, commitID) } } return } + +type commitBranchCheckItem struct { + Commit *git.Commit + Checked bool +} + +func commitBranchCheck(gitRepo *git.Repository, startCommit *git.Commit, endCommitID, baseBranch string, commitList map[string]commitBranchCheckItem) (err error) { + var ( + item commitBranchCheckItem + ok bool + listItem *list.Element + tmp string + ) + + if startCommit.ID.String() == endCommitID { + return + } + + checkStack := list.New() + checkStack.PushBack(startCommit.ID.String()) + listItem = checkStack.Back() + + for listItem != nil { + tmp = listItem.Value.(string) + checkStack.Remove(listItem) + + if item, ok = commitList[tmp]; !ok { + listItem = checkStack.Back() + continue + } + + if item.Commit.ID.String() == endCommitID { + listItem = checkStack.Back() + continue + } + + if err = item.Commit.LoadBranchName(); err != nil { + return + } + + if item.Commit.Branch == baseBranch { + listItem = checkStack.Back() + continue + } + + if item.Checked { + listItem = checkStack.Back() + continue + } + + item.Checked = true + commitList[tmp] = item + + parentNum := item.Commit.ParentCount() + for i := 0; i < parentNum; i++ { + var parentCommit *git.Commit + parentCommit, err = item.Commit.Parent(i) + if err != nil { + return + } + checkStack.PushBack(parentCommit.ID.String()) + } + + listItem = checkStack.Back() + } + return nil +} diff --git a/modules/git/commit.go b/modules/git/commit.go index c06eabfbd4..b8ff99cdb6 100644 --- a/modules/git/commit.go +++ b/modules/git/commit.go @@ -482,6 +482,16 @@ func (c *Commit) GetBranchName() (string, error) { return strings.SplitN(strings.TrimSpace(data), "~", 2)[0], nil } +// LoadBranchName load branch name for commit +func (c *Commit) LoadBranchName() (err error) { + if len(c.Branch) != 0 { + return + } + + c.Branch, err = c.GetBranchName() + return +} + // GetTagName gets the current tag name for given commit func (c *Commit) GetTagName() (string, error) { data, err := NewCommand("describe", "--exact-match", "--tags", "--always", c.ID.String()).RunInDir(c.repo.Path)