Skip to content

Commit 4b8684b

Browse files
committed
Fix pull request update showing too many commits with multiple branches
When the base repository contains multiple branches with the same commits as the base branch, pull requests can show a long list of commits already in the base branch as having been added. What this is supposed to do is exclude commits already in the base branch. But the mechanism to do so assumed a commit only exists in a single branch. Now use `git rev-list A B --not branchName` instead of filtering commits afterwards. The logic to detect if there was a force push also was wrong for multiple branches. If the old commit existed in any branch in the base repository it would assume there was no force push. Instead check if the old commit is an ancestor of the new commit.
1 parent 1cb8d14 commit 4b8684b

File tree

2 files changed

+34
-77
lines changed

2 files changed

+34
-77
lines changed

modules/git/repo_commit.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,28 @@ func (repo *Repository) CommitsBetweenLimit(last, before *Commit, limit, skip in
323323
return repo.parsePrettyFormatLogToList(bytes.TrimSpace(stdout))
324324
}
325325

326+
// CommitsBetween returns a list that contains commits between [before, last),
327+
// excluding commits in baseBranch.
328+
// If before is detached (removed by reset + push) it is not included.
329+
func (repo *Repository) CommitsBetweenSkipBase(last, before *Commit, baseBranch string) ([]*Commit, error) {
330+
var stdout []byte
331+
var err error
332+
if before == nil {
333+
stdout, _, err = NewCommand(repo.Ctx, "rev-list").AddDynamicArguments(last.ID.String()).AddArguments("--not").AddDynamicArguments(baseBranch).RunStdBytes(&RunOpts{Dir: repo.Path})
334+
} else {
335+
stdout, _, err = NewCommand(repo.Ctx, "rev-list").AddDynamicArguments(before.ID.String() + ".." + last.ID.String()).AddArguments("--not").AddDynamicArguments(baseBranch).RunStdBytes(&RunOpts{Dir: repo.Path})
336+
if err != nil && strings.Contains(err.Error(), "no merge base") {
337+
// future versions of git >= 2.28 are likely to return an error if before and last have become unrelated.
338+
// previously it would return the results of git rev-list before last so let's try that...
339+
stdout, _, err = NewCommand(repo.Ctx, "rev-list").AddDynamicArguments(before.ID.String(), last.ID.String()).AddArguments("--not").AddDynamicArguments(baseBranch).RunStdBytes(&RunOpts{Dir: repo.Path})
340+
}
341+
}
342+
if err != nil {
343+
return nil, err
344+
}
345+
return repo.parsePrettyFormatLogToList(bytes.TrimSpace(stdout))
346+
}
347+
326348
// CommitsBetweenIDs return commits between twoe commits
327349
func (repo *Repository) CommitsBetweenIDs(last, before string) ([]*Commit, error) {
328350
lastCommit, err := repo.GetCommit(last)

services/pull/comment.go

Lines changed: 12 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -14,58 +14,6 @@ import (
1414
issue_service "code.gitea.io/gitea/services/issue"
1515
)
1616

17-
type commitBranchCheckItem struct {
18-
Commit *git.Commit
19-
Checked bool
20-
}
21-
22-
func commitBranchCheck(gitRepo *git.Repository, startCommit *git.Commit, endCommitID, baseBranch string, commitList map[string]*commitBranchCheckItem) error {
23-
if startCommit.ID.String() == endCommitID {
24-
return nil
25-
}
26-
27-
checkStack := make([]string, 0, 10)
28-
checkStack = append(checkStack, startCommit.ID.String())
29-
30-
for len(checkStack) > 0 {
31-
commitID := checkStack[0]
32-
checkStack = checkStack[1:]
33-
34-
item, ok := commitList[commitID]
35-
if !ok {
36-
continue
37-
}
38-
39-
if item.Commit.ID.String() == endCommitID {
40-
continue
41-
}
42-
43-
if err := item.Commit.LoadBranchName(); err != nil {
44-
return err
45-
}
46-
47-
if item.Commit.Branch == baseBranch {
48-
continue
49-
}
50-
51-
if item.Checked {
52-
continue
53-
}
54-
55-
item.Checked = true
56-
57-
parentNum := item.Commit.ParentCount()
58-
for i := 0; i < parentNum; i++ {
59-
parentCommit, err := item.Commit.Parent(i)
60-
if err != nil {
61-
return err
62-
}
63-
checkStack = append(checkStack, parentCommit.ID.String())
64-
}
65-
}
66-
return nil
67-
}
68-
6917
// getCommitIDsFromRepo get commit IDs from repo in between oldCommitID and newCommitID
7018
// isForcePush will be true if oldCommit isn't on the branch
7119
// Commit on baseBranch will skip
@@ -82,47 +30,34 @@ func getCommitIDsFromRepo(ctx context.Context, repo *repo_model.Repository, oldC
8230
return nil, false, err
8331
}
8432

85-
if err = oldCommit.LoadBranchName(); err != nil {
33+
newCommit, err := gitRepo.GetCommit(newCommitID)
34+
if err != nil {
35+
return nil, false, err
36+
}
37+
38+
// If old commit is not an ancestor of new commits, it's a force push
39+
isAncestor, err := newCommit.HasPreviousCommit(oldCommit.ID)
40+
if err != nil {
8641
return nil, false, err
8742
}
8843

89-
if len(oldCommit.Branch) == 0 {
44+
if !isAncestor {
9045
commitIDs = make([]string, 2)
9146
commitIDs[0] = oldCommitID
9247
commitIDs[1] = newCommitID
9348

9449
return commitIDs, true, err
9550
}
9651

97-
newCommit, err := gitRepo.GetCommit(newCommitID)
98-
if err != nil {
99-
return nil, false, err
100-
}
101-
102-
commits, err := newCommit.CommitsBeforeUntil(oldCommitID)
52+
// Find commits between new and old commit exclusing base branch commits
53+
commits, err := gitRepo.CommitsBetweenSkipBase(newCommit, oldCommit, baseBranch)
10354
if err != nil {
10455
return nil, false, err
10556
}
10657

10758
commitIDs = make([]string, 0, len(commits))
108-
commitChecks := make(map[string]*commitBranchCheckItem)
109-
110-
for _, commit := range commits {
111-
commitChecks[commit.ID.String()] = &commitBranchCheckItem{
112-
Commit: commit,
113-
Checked: false,
114-
}
115-
}
116-
117-
if err = commitBranchCheck(gitRepo, newCommit, oldCommitID, baseBranch, commitChecks); err != nil {
118-
return
119-
}
120-
12159
for i := len(commits) - 1; i >= 0; i-- {
122-
commitID := commits[i].ID.String()
123-
if item, ok := commitChecks[commitID]; ok && item.Checked {
124-
commitIDs = append(commitIDs, commitID)
125-
}
60+
commitIDs = append(commitIDs, commits[i].ID.String())
12661
}
12762

12863
return commitIDs, isForcePush, err

0 commit comments

Comments
 (0)