diff --git a/integrations/api_repo_git_commits_test.go b/integrations/api_repo_git_commits_test.go
index 1e138eb9152f..2099d568f769 100644
--- a/integrations/api_repo_git_commits_test.go
+++ b/integrations/api_repo_git_commits_test.go
@@ -132,3 +132,21 @@ func TestDownloadCommitDiffOrPatch(t *testing.T) {
 		resp.Body.String())
 
 }
+
+func TestGetFileHistory(t *testing.T) {
+	defer prepareTestEnv(t)()
+	user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
+	// Login as User2.
+	session := loginUser(t, user.Name)
+	token := getTokenForLoggedInUser(t, session)
+
+	req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo16/commits?path=readme.md&token="+token+"&sha=good-sign", user.Name)
+	resp := session.MakeRequest(t, req, http.StatusOK)
+
+	var apiData []api.Commit
+	DecodeJSON(t, resp, &apiData)
+
+	assert.Len(t, apiData, 1)
+	assert.Equal(t, "f27c2b2b03dcab38beaf89b0ab4ff61f6de63441", apiData[0].CommitMeta.SHA)
+	compareCommitFiles(t, []string{"readme.md"}, apiData[0].Files)
+}
diff --git a/routers/api/v1/repo/commits.go b/routers/api/v1/repo/commits.go
index 6845ccb3635c..a2b42986020b 100644
--- a/routers/api/v1/repo/commits.go
+++ b/routers/api/v1/repo/commits.go
@@ -108,13 +108,17 @@ func GetAllCommits(ctx *context.APIContext) {
 	//   in: query
 	//   description: SHA or branch to start listing commits from (usually 'master')
 	//   type: string
+	// - name: path
+	//   in: query
+	//   description: filepath of a file/dir
+	//   type: string
 	// - name: page
 	//   in: query
 	//   description: page number of results to return (1-based)
 	//   type: integer
 	// - name: limit
 	//   in: query
-	//   description: page size of results
+	//   description: page size of results (ignored if used with 'path')
 	//   type: integer
 	// responses:
 	//   "200":
@@ -149,46 +153,73 @@ func GetAllCommits(ctx *context.APIContext) {
 	}
 
 	sha := ctx.FormString("sha")
+	path := ctx.FormString("path")
 
-	var baseCommit *git.Commit
-	if len(sha) == 0 {
-		// no sha supplied - use default branch
-		head, err := gitRepo.GetHEADBranch()
+	var (
+		commitsCountTotal int64
+		commits           []*git.Commit
+	)
+
+	if len(path) == 0 {
+		var baseCommit *git.Commit
+		if len(sha) == 0 {
+			// no sha supplied - use default branch
+			head, err := gitRepo.GetHEADBranch()
+			if err != nil {
+				ctx.Error(http.StatusInternalServerError, "GetHEADBranch", err)
+				return
+			}
+
+			baseCommit, err = gitRepo.GetBranchCommit(head.Name)
+			if err != nil {
+				ctx.Error(http.StatusInternalServerError, "GetCommit", err)
+				return
+			}
+		} else {
+			// get commit specified by sha
+			baseCommit, err = gitRepo.GetCommit(sha)
+			if err != nil {
+				ctx.Error(http.StatusInternalServerError, "GetCommit", err)
+				return
+			}
+		}
+
+		// Total commit count
+		commitsCountTotal, err = baseCommit.CommitsCount()
 		if err != nil {
-			ctx.Error(http.StatusInternalServerError, "GetHEADBranch", err)
+			ctx.Error(http.StatusInternalServerError, "GetCommitsCount", err)
 			return
 		}
 
-		baseCommit, err = gitRepo.GetBranchCommit(head.Name)
+		// Query commits
+		commits, err = baseCommit.CommitsByRange(listOptions.Page, listOptions.PageSize)
 		if err != nil {
-			ctx.Error(http.StatusInternalServerError, "GetCommit", err)
+			ctx.Error(http.StatusInternalServerError, "CommitsByRange", err)
 			return
 		}
 	} else {
-		// get commit specified by sha
-		baseCommit, err = gitRepo.GetCommit(sha)
+		if len(sha) == 0 {
+			sha = ctx.Repo.Repository.DefaultBranch
+		}
+
+		commitsCountTotal, err = gitRepo.FileCommitsCount(sha, path)
 		if err != nil {
-			ctx.Error(http.StatusInternalServerError, "GetCommit", err)
+			ctx.Error(http.StatusInternalServerError, "FileCommitsCount", err)
+			return
+		} else if commitsCountTotal == 0 {
+			ctx.NotFound("FileCommitsCount", nil)
+			return
+		}
+
+		commits, err = gitRepo.CommitsByFileAndRange(sha, path, listOptions.Page)
+		if err != nil {
+			ctx.Error(http.StatusInternalServerError, "CommitsByFileAndRange", err)
 			return
 		}
 	}
 
-	// Total commit count
-	commitsCountTotal, err := baseCommit.CommitsCount()
-	if err != nil {
-		ctx.Error(http.StatusInternalServerError, "GetCommitsCount", err)
-		return
-	}
-
 	pageCount := int(math.Ceil(float64(commitsCountTotal) / float64(listOptions.PageSize)))
 
-	// Query commits
-	commits, err := baseCommit.CommitsByRange(listOptions.Page, listOptions.PageSize)
-	if err != nil {
-		ctx.Error(http.StatusInternalServerError, "CommitsByRange", err)
-		return
-	}
-
 	userCache := make(map[string]*user_model.User)
 
 	apiCommits := make([]*api.Commit, len(commits))
diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl
index 751d77e6ff39..b016ad22a2d6 100644
--- a/templates/swagger/v1_json.tmpl
+++ b/templates/swagger/v1_json.tmpl
@@ -2950,6 +2950,12 @@
             "name": "sha",
             "in": "query"
           },
+          {
+            "type": "string",
+            "description": "filepath of a file/dir",
+            "name": "path",
+            "in": "query"
+          },
           {
             "type": "integer",
             "description": "page number of results to return (1-based)",
@@ -2958,7 +2964,7 @@
           },
           {
             "type": "integer",
-            "description": "page size of results",
+            "description": "page size of results (ignored if used with 'path')",
             "name": "limit",
             "in": "query"
           }