gitea源码

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. // Copyright 2025 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package pull
  4. import (
  5. "context"
  6. "fmt"
  7. "strconv"
  8. "time"
  9. repo_model "code.gitea.io/gitea/models/repo"
  10. "code.gitea.io/gitea/modules/git"
  11. "code.gitea.io/gitea/modules/gitrepo"
  12. "code.gitea.io/gitea/modules/graceful"
  13. logger "code.gitea.io/gitea/modules/log"
  14. )
  15. // CompareInfo represents needed information for comparing references.
  16. type CompareInfo struct {
  17. MergeBase string
  18. BaseCommitID string
  19. HeadCommitID string
  20. Commits []*git.Commit
  21. NumFiles int
  22. }
  23. // GetCompareInfo generates and returns compare information between base and head branches of repositories.
  24. func GetCompareInfo(ctx context.Context, baseRepo, headRepo *repo_model.Repository, headGitRepo *git.Repository, baseBranch, headBranch string, directComparison, fileOnly bool) (_ *CompareInfo, err error) {
  25. var (
  26. remoteBranch string
  27. tmpRemote string
  28. )
  29. // We don't need a temporary remote for same repository.
  30. if headGitRepo.Path != baseRepo.RepoPath() {
  31. // Add a temporary remote
  32. tmpRemote = strconv.FormatInt(time.Now().UnixNano(), 10)
  33. if err = gitrepo.GitRemoteAdd(ctx, headRepo, tmpRemote, baseRepo.RepoPath()); err != nil {
  34. return nil, fmt.Errorf("GitRemoteAdd: %w", err)
  35. }
  36. defer func() {
  37. if err := gitrepo.GitRemoteRemove(graceful.GetManager().ShutdownContext(), headRepo, tmpRemote); err != nil {
  38. logger.Error("GetPullRequestInfo: GitRemoteRemove: %v", err)
  39. }
  40. }()
  41. }
  42. compareInfo := new(CompareInfo)
  43. compareInfo.HeadCommitID, err = git.GetFullCommitID(ctx, headGitRepo.Path, headBranch)
  44. if err != nil {
  45. compareInfo.HeadCommitID = headBranch
  46. }
  47. compareInfo.MergeBase, remoteBranch, err = headGitRepo.GetMergeBase(tmpRemote, baseBranch, headBranch)
  48. if err == nil {
  49. compareInfo.BaseCommitID, err = git.GetFullCommitID(ctx, headGitRepo.Path, remoteBranch)
  50. if err != nil {
  51. compareInfo.BaseCommitID = remoteBranch
  52. }
  53. separator := "..."
  54. baseCommitID := compareInfo.MergeBase
  55. if directComparison {
  56. separator = ".."
  57. baseCommitID = compareInfo.BaseCommitID
  58. }
  59. // We have a common base - therefore we know that ... should work
  60. if !fileOnly {
  61. compareInfo.Commits, err = headGitRepo.ShowPrettyFormatLogToList(ctx, baseCommitID+separator+headBranch)
  62. if err != nil {
  63. return nil, fmt.Errorf("ShowPrettyFormatLogToList: %w", err)
  64. }
  65. } else {
  66. compareInfo.Commits = []*git.Commit{}
  67. }
  68. } else {
  69. compareInfo.Commits = []*git.Commit{}
  70. compareInfo.MergeBase, err = git.GetFullCommitID(ctx, headGitRepo.Path, remoteBranch)
  71. if err != nil {
  72. compareInfo.MergeBase = remoteBranch
  73. }
  74. compareInfo.BaseCommitID = compareInfo.MergeBase
  75. }
  76. // Count number of changed files.
  77. // This probably should be removed as we need to use shortstat elsewhere
  78. // Now there is git diff --shortstat but this appears to be slower than simply iterating with --nameonly
  79. compareInfo.NumFiles, err = headGitRepo.GetDiffNumChangedFiles(remoteBranch, headBranch, directComparison)
  80. if err != nil {
  81. return nil, err
  82. }
  83. return compareInfo, nil
  84. }