mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 00:20:25 +08:00 
			
		
		
		
	Filters for GetAllCommits (#24568)
The `GetAllCommits` endpoint can be pretty slow, especially in repos with a lot of commits. The issue is that it spends a lot of time calculating information that may not be useful/needed by the user. The `stat` param was previously added in #21337 to address this, by allowing the user to disable the calculating stats for each commit. But this has two issues: 1. The name `stat` is rather misleading, because disabling `stat` disables the Stat **and** Files. This should be separated out into two different params, because getting a list of affected files is much less expensive than calculating the stats 2. There's still other costly information provided that the user may not need, such as `Verification` This PR, adds two parameters to the endpoint, `files` and `verification` to allow the user to explicitly disable this information when listing commits. The default behavior is true.
This commit is contained in:
		@@ -69,7 +69,7 @@ func getCommit(ctx *context.APIContext, identifier string) {
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	json, err := convert.ToCommit(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, commit, nil, true)
 | 
						json, err := convert.ToCommit(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, commit, nil, convert.ToCommitOptions{Stat: true})
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		ctx.Error(http.StatusInternalServerError, "toCommit", err)
 | 
							ctx.Error(http.StatusInternalServerError, "toCommit", err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
@@ -107,6 +107,14 @@ func GetAllCommits(ctx *context.APIContext) {
 | 
				
			|||||||
	//   in: query
 | 
						//   in: query
 | 
				
			||||||
	//   description: include diff stats for every commit (disable for speedup, default 'true')
 | 
						//   description: include diff stats for every commit (disable for speedup, default 'true')
 | 
				
			||||||
	//   type: boolean
 | 
						//   type: boolean
 | 
				
			||||||
 | 
						// - name: verification
 | 
				
			||||||
 | 
						//   in: query
 | 
				
			||||||
 | 
						//   description: include verification for every commit (disable for speedup, default 'true')
 | 
				
			||||||
 | 
						//   type: boolean
 | 
				
			||||||
 | 
						// - name: files
 | 
				
			||||||
 | 
						//   in: query
 | 
				
			||||||
 | 
						//   description: include a list of affected files for every commit (disable for speedup, default 'true')
 | 
				
			||||||
 | 
						//   type: boolean
 | 
				
			||||||
	// - name: page
 | 
						// - name: page
 | 
				
			||||||
	//   in: query
 | 
						//   in: query
 | 
				
			||||||
	//   description: page number of results to return (1-based)
 | 
						//   description: page number of results to return (1-based)
 | 
				
			||||||
@@ -238,10 +246,18 @@ func GetAllCommits(ctx *context.APIContext) {
 | 
				
			|||||||
	apiCommits := make([]*api.Commit, len(commits))
 | 
						apiCommits := make([]*api.Commit, len(commits))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	stat := ctx.FormString("stat") == "" || ctx.FormBool("stat")
 | 
						stat := ctx.FormString("stat") == "" || ctx.FormBool("stat")
 | 
				
			||||||
 | 
						verification := ctx.FormString("verification") == "" || ctx.FormBool("verification")
 | 
				
			||||||
 | 
						files := ctx.FormString("files") == "" || ctx.FormBool("files")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for i, commit := range commits {
 | 
						for i, commit := range commits {
 | 
				
			||||||
		// Create json struct
 | 
							// Create json struct
 | 
				
			||||||
		apiCommits[i], err = convert.ToCommit(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, commit, userCache, stat)
 | 
							apiCommits[i], err = convert.ToCommit(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, commit, userCache,
 | 
				
			||||||
 | 
								convert.ToCommitOptions{
 | 
				
			||||||
 | 
									Stat:         stat,
 | 
				
			||||||
 | 
									Verification: verification,
 | 
				
			||||||
 | 
									Files:        files,
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			ctx.Error(http.StatusInternalServerError, "toCommit", err)
 | 
								ctx.Error(http.StatusInternalServerError, "toCommit", err)
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -78,7 +78,7 @@ func getNote(ctx *context.APIContext, identifier string) {
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cmt, err := convert.ToCommit(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, note.Commit, nil, true)
 | 
						cmt, err := convert.ToCommit(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, note.Commit, nil, convert.ToCommitOptions{Stat: true})
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		ctx.Error(http.StatusInternalServerError, "ToCommit", err)
 | 
							ctx.Error(http.StatusInternalServerError, "ToCommit", err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1318,7 +1318,7 @@ func GetPullRequestCommits(ctx *context.APIContext) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	apiCommits := make([]*api.Commit, 0, end-start)
 | 
						apiCommits := make([]*api.Commit, 0, end-start)
 | 
				
			||||||
	for i := start; i < end; i++ {
 | 
						for i := start; i < end; i++ {
 | 
				
			||||||
		apiCommit, err := convert.ToCommit(ctx, ctx.Repo.Repository, baseGitRepo, commits[i], userCache, true)
 | 
							apiCommit, err := convert.ToCommit(ctx, ctx.Repo.Repository, baseGitRepo, commits[i], userCache, convert.ToCommitOptions{Stat: true})
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			ctx.ServerError("toCommit", err)
 | 
								ctx.ServerError("toCommit", err)
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -72,8 +72,14 @@ func ToPayloadCommit(ctx context.Context, repo *repo_model.Repository, c *git.Co
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ToCommitOptions struct {
 | 
				
			||||||
 | 
						Stat         bool
 | 
				
			||||||
 | 
						Verification bool
 | 
				
			||||||
 | 
						Files        bool
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ToCommit convert a git.Commit to api.Commit
 | 
					// ToCommit convert a git.Commit to api.Commit
 | 
				
			||||||
func ToCommit(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, commit *git.Commit, userCache map[string]*user_model.User, stat bool) (*api.Commit, error) {
 | 
					func ToCommit(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, commit *git.Commit, userCache map[string]*user_model.User, opts ToCommitOptions) (*api.Commit, error) {
 | 
				
			||||||
	var apiAuthor, apiCommitter *api.User
 | 
						var apiAuthor, apiCommitter *api.User
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Retrieve author and committer information
 | 
						// Retrieve author and committer information
 | 
				
			||||||
@@ -162,19 +168,24 @@ func ToCommit(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Rep
 | 
				
			|||||||
				SHA:     commit.ID.String(),
 | 
									SHA:     commit.ID.String(),
 | 
				
			||||||
				Created: commit.Committer.When,
 | 
									Created: commit.Committer.When,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			Verification: ToVerification(ctx, commit),
 | 
					 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		Author:    apiAuthor,
 | 
							Author:    apiAuthor,
 | 
				
			||||||
		Committer: apiCommitter,
 | 
							Committer: apiCommitter,
 | 
				
			||||||
		Parents:   apiParents,
 | 
							Parents:   apiParents,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Retrieve verification for commit
 | 
				
			||||||
 | 
						if opts.Verification {
 | 
				
			||||||
 | 
							res.RepoCommit.Verification = ToVerification(ctx, commit)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Retrieve files affected by the commit
 | 
						// Retrieve files affected by the commit
 | 
				
			||||||
	if stat {
 | 
						if opts.Files {
 | 
				
			||||||
		fileStatus, err := git.GetCommitFileStatus(gitRepo.Ctx, repo.RepoPath(), commit.ID.String())
 | 
							fileStatus, err := git.GetCommitFileStatus(gitRepo.Ctx, repo.RepoPath(), commit.ID.String())
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, err
 | 
								return nil, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		affectedFileList := make([]*api.CommitAffectedFiles, 0, len(fileStatus.Added)+len(fileStatus.Removed)+len(fileStatus.Modified))
 | 
							affectedFileList := make([]*api.CommitAffectedFiles, 0, len(fileStatus.Added)+len(fileStatus.Removed)+len(fileStatus.Modified))
 | 
				
			||||||
		for _, files := range [][]string{fileStatus.Added, fileStatus.Removed, fileStatus.Modified} {
 | 
							for _, files := range [][]string{fileStatus.Added, fileStatus.Removed, fileStatus.Modified} {
 | 
				
			||||||
			for _, filename := range files {
 | 
								for _, filename := range files {
 | 
				
			||||||
@@ -184,6 +195,11 @@ func ToCommit(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Rep
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							res.Files = affectedFileList
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Get diff stats for commit
 | 
				
			||||||
 | 
						if opts.Stat {
 | 
				
			||||||
		diff, err := gitdiff.GetDiff(gitRepo, &gitdiff.DiffOptions{
 | 
							diff, err := gitdiff.GetDiff(gitRepo, &gitdiff.DiffOptions{
 | 
				
			||||||
			AfterCommitID: commit.ID.String(),
 | 
								AfterCommitID: commit.ID.String(),
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
@@ -191,7 +207,6 @@ func ToCommit(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Rep
 | 
				
			|||||||
			return nil, err
 | 
								return nil, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		res.Files = affectedFileList
 | 
					 | 
				
			||||||
		res.Stats = &api.CommitStats{
 | 
							res.Stats = &api.CommitStats{
 | 
				
			||||||
			Total:     diff.TotalAddition + diff.TotalDeletion,
 | 
								Total:     diff.TotalAddition + diff.TotalDeletion,
 | 
				
			||||||
			Additions: diff.TotalAddition,
 | 
								Additions: diff.TotalAddition,
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										12
									
								
								templates/swagger/v1_json.tmpl
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										12
									
								
								templates/swagger/v1_json.tmpl
									
									
									
										generated
									
									
									
								
							@@ -3794,6 +3794,18 @@
 | 
				
			|||||||
            "name": "stat",
 | 
					            "name": "stat",
 | 
				
			||||||
            "in": "query"
 | 
					            "in": "query"
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "type": "boolean",
 | 
				
			||||||
 | 
					            "description": "include verification for every commit (disable for speedup, default 'true')",
 | 
				
			||||||
 | 
					            "name": "verification",
 | 
				
			||||||
 | 
					            "in": "query"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            "type": "boolean",
 | 
				
			||||||
 | 
					            "description": "include a list of affected files for every commit (disable for speedup, default 'true')",
 | 
				
			||||||
 | 
					            "name": "files",
 | 
				
			||||||
 | 
					            "in": "query"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
          {
 | 
					          {
 | 
				
			||||||
            "type": "integer",
 | 
					            "type": "integer",
 | 
				
			||||||
            "description": "page number of results to return (1-based)",
 | 
					            "description": "page number of results to return (1-based)",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -135,6 +135,27 @@ func TestAPIReposGitCommitListDifferentBranch(t *testing.T) {
 | 
				
			|||||||
	compareCommitFiles(t, []string{"readme.md"}, apiData[0].Files)
 | 
						compareCommitFiles(t, []string{"readme.md"}, apiData[0].Files)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestAPIReposGitCommitListWithoutSelectFields(t *testing.T) {
 | 
				
			||||||
 | 
						defer tests.PrepareTestEnv(t)()
 | 
				
			||||||
 | 
						user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
 | 
				
			||||||
 | 
						// Login as User2.
 | 
				
			||||||
 | 
						session := loginUser(t, user.Name)
 | 
				
			||||||
 | 
						token := getTokenForLoggedInUser(t, session)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Test getting commits without files, verification, and stats
 | 
				
			||||||
 | 
						req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo16/commits?token="+token+"&sha=good-sign&stat=false&files=false&verification=false", user.Name)
 | 
				
			||||||
 | 
						resp := 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)
 | 
				
			||||||
 | 
						assert.Equal(t, (*api.CommitStats)(nil), apiData[0].Stats)
 | 
				
			||||||
 | 
						assert.Equal(t, (*api.PayloadCommitVerification)(nil), apiData[0].RepoCommit.Verification)
 | 
				
			||||||
 | 
						assert.Equal(t, ([]*api.CommitAffectedFiles)(nil), apiData[0].Files)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestDownloadCommitDiffOrPatch(t *testing.T) {
 | 
					func TestDownloadCommitDiffOrPatch(t *testing.T) {
 | 
				
			||||||
	defer tests.PrepareTestEnv(t)()
 | 
						defer tests.PrepareTestEnv(t)()
 | 
				
			||||||
	user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
 | 
						user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user