diff --git a/modules/git/commit.go b/modules/git/commit.go
index ce82c2f582..027642720d 100644
--- a/modules/git/commit.go
+++ b/modules/git/commit.go
@@ -9,6 +9,7 @@ import (
 	"bufio"
 	"bytes"
 	"container/list"
+	"errors"
 	"fmt"
 	"image"
 	"image/color"
@@ -17,6 +18,7 @@ import (
 	_ "image/png"  // for processing png images
 	"io"
 	"net/http"
+	"os/exec"
 	"strconv"
 	"strings"
 )
@@ -264,23 +266,33 @@ func (c *Commit) CommitsBefore() (*list.List, error) {
 
 // HasPreviousCommit returns true if a given commitHash is contained in commit's parents
 func (c *Commit) HasPreviousCommit(commitHash SHA1) (bool, error) {
-	for i := 0; i < c.ParentCount(); i++ {
-		commit, err := c.Parent(i)
-		if err != nil {
-			return false, err
-		}
-		if commit.ID == commitHash {
-			return true, nil
-		}
-		commitInParentCommit, err := commit.HasPreviousCommit(commitHash)
-		if err != nil {
-			return false, err
-		}
-		if commitInParentCommit {
-			return true, nil
-		}
+	this := c.ID.String()
+	that := commitHash.String()
+
+	if this == that {
+		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
diff --git a/modules/git/commit_test.go b/modules/git/commit_test.go
index 9b5fc8f660..0925a6ce6a 100644
--- a/modules/git/commit_test.go
+++ b/modules/git/commit_test.go
@@ -105,3 +105,28 @@ empty commit`, commitFromReader.Signature.Payload)
 	commitFromReader.Signature.Payload += "\n\n"
 	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)
+}