HasPreviousCommit causes recursive load of commits unnecessarily (#14598)
This PR improves HasPreviousCommit to prevent the automatic and recursive loading of previous commits using git merge-base --is-ancestor and git rev-list Fix #13684 Signed-off-by: Andrew Thornton <art27@cantab.net>
This commit is contained in:
parent
c0c59a4c99
commit
f9abf94bd9
2 changed files with 53 additions and 16 deletions
|
@ -9,6 +9,7 @@ import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"container/list"
|
"container/list"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"image"
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
|
@ -17,6 +18,7 @@ import (
|
||||||
_ "image/png" // for processing png images
|
_ "image/png" // for processing png images
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os/exec"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
@ -264,25 +266,35 @@ func (c *Commit) CommitsBefore() (*list.List, error) {
|
||||||
|
|
||||||
// HasPreviousCommit returns true if a given commitHash is contained in commit's parents
|
// HasPreviousCommit returns true if a given commitHash is contained in commit's parents
|
||||||
func (c *Commit) HasPreviousCommit(commitHash SHA1) (bool, error) {
|
func (c *Commit) HasPreviousCommit(commitHash SHA1) (bool, error) {
|
||||||
for i := 0; i < c.ParentCount(); i++ {
|
this := c.ID.String()
|
||||||
commit, err := c.Parent(i)
|
that := commitHash.String()
|
||||||
if err != nil {
|
|
||||||
return false, err
|
if this == that {
|
||||||
}
|
|
||||||
if commit.ID == commitHash {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
commitInParentCommit, err := commit.HasPreviousCommit(commitHash)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
if commitInParentCommit {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := CheckGitVersionAtLeast("1.8"); err == nil {
|
||||||
|
_, err := NewCommand("merge-base", "--is-ancestor", that, this).RunInDir(c.repo.Path)
|
||||||
|
if err == nil {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
var exitError *exec.ExitError
|
||||||
|
if errors.As(err, &exitError) {
|
||||||
|
if exitError.ProcessState.ExitCode() == 1 && len(exitError.Stderr) == 0 {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := NewCommand("rev-list", "--ancestry-path", "-n1", that+".."+this, "--").RunInDir(c.repo.Path)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return len(strings.TrimSpace(result)) > 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
// CommitsBeforeLimit returns num commits before current revision
|
// CommitsBeforeLimit returns num commits before current revision
|
||||||
func (c *Commit) CommitsBeforeLimit(num int) (*list.List, error) {
|
func (c *Commit) CommitsBeforeLimit(num int) (*list.List, error) {
|
||||||
return c.repo.getCommitsBeforeLimit(c.ID, num)
|
return c.repo.getCommitsBeforeLimit(c.ID, num)
|
||||||
|
|
|
@ -105,3 +105,28 @@ empty commit`, commitFromReader.Signature.Payload)
|
||||||
commitFromReader.Signature.Payload += "\n\n"
|
commitFromReader.Signature.Payload += "\n\n"
|
||||||
assert.EqualValues(t, commitFromReader, commitFromReader2)
|
assert.EqualValues(t, commitFromReader, commitFromReader2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHasPreviousCommit(t *testing.T) {
|
||||||
|
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare")
|
||||||
|
|
||||||
|
repo, err := OpenRepository(bareRepo1Path)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
commit, err := repo.GetCommit("8006ff9adbf0cb94da7dad9e537e53817f9fa5c0")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
parentSHA := MustIDFromString("8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2")
|
||||||
|
notParentSHA := MustIDFromString("2839944139e0de9737a044f78b0e4b40d989a9e3")
|
||||||
|
|
||||||
|
haz, err := commit.HasPreviousCommit(parentSHA)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, haz)
|
||||||
|
|
||||||
|
hazNot, err := commit.HasPreviousCommit(notParentSHA)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.False(t, hazNot)
|
||||||
|
|
||||||
|
selfNot, err := commit.HasPreviousCommit(commit.ID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.False(t, selfNot)
|
||||||
|
}
|
||||||
|
|
Reference in a new issue