You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

repo_branch.go 4.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. // Copyright 2015 The Gogs Authors. All rights reserved.
  2. // Copyright 2018 The Gitea Authors. All rights reserved.
  3. // Use of this source code is governed by a MIT-style
  4. // license that can be found in the LICENSE file.
  5. package git
  6. import (
  7. "fmt"
  8. "strings"
  9. "github.com/go-git/go-git/v5/plumbing"
  10. )
  11. // BranchPrefix base dir of the branch information file store on git
  12. const BranchPrefix = "refs/heads/"
  13. // IsReferenceExist returns true if given reference exists in the repository.
  14. func IsReferenceExist(repoPath, name string) bool {
  15. _, err := NewCommand("show-ref", "--verify", "--", name).RunInDir(repoPath)
  16. return err == nil
  17. }
  18. // IsBranchExist returns true if given branch exists in the repository.
  19. func IsBranchExist(repoPath, name string) bool {
  20. return IsReferenceExist(repoPath, BranchPrefix+name)
  21. }
  22. // IsBranchExist returns true if given branch exists in current repository.
  23. func (repo *Repository) IsBranchExist(name string) bool {
  24. if name == "" {
  25. return false
  26. }
  27. reference, err := repo.gogitRepo.Reference(plumbing.ReferenceName(BranchPrefix+name), true)
  28. if err != nil {
  29. return false
  30. }
  31. return reference.Type() != plumbing.InvalidReference
  32. }
  33. // Branch represents a Git branch.
  34. type Branch struct {
  35. Name string
  36. Path string
  37. gitRepo *Repository
  38. }
  39. // GetHEADBranch returns corresponding branch of HEAD.
  40. func (repo *Repository) GetHEADBranch() (*Branch, error) {
  41. if repo == nil {
  42. return nil, fmt.Errorf("nil repo")
  43. }
  44. stdout, err := NewCommand("symbolic-ref", "HEAD").RunInDir(repo.Path)
  45. if err != nil {
  46. return nil, err
  47. }
  48. stdout = strings.TrimSpace(stdout)
  49. if !strings.HasPrefix(stdout, BranchPrefix) {
  50. return nil, fmt.Errorf("invalid HEAD branch: %v", stdout)
  51. }
  52. return &Branch{
  53. Name: stdout[len(BranchPrefix):],
  54. Path: stdout,
  55. gitRepo: repo,
  56. }, nil
  57. }
  58. // SetDefaultBranch sets default branch of repository.
  59. func (repo *Repository) SetDefaultBranch(name string) error {
  60. _, err := NewCommand("symbolic-ref", "HEAD", BranchPrefix+name).RunInDir(repo.Path)
  61. return err
  62. }
  63. // GetBranches returns all branches of the repository.
  64. func (repo *Repository) GetBranches() ([]string, error) {
  65. var branchNames []string
  66. branches, err := repo.gogitRepo.Branches()
  67. if err != nil {
  68. return nil, err
  69. }
  70. _ = branches.ForEach(func(branch *plumbing.Reference) error {
  71. branchNames = append(branchNames, strings.TrimPrefix(branch.Name().String(), BranchPrefix))
  72. return nil
  73. })
  74. // TODO: Sort?
  75. return branchNames, nil
  76. }
  77. // GetBranch returns a branch by it's name
  78. func (repo *Repository) GetBranch(branch string) (*Branch, error) {
  79. if !repo.IsBranchExist(branch) {
  80. return nil, ErrBranchNotExist{branch}
  81. }
  82. return &Branch{
  83. Path: repo.Path,
  84. Name: branch,
  85. gitRepo: repo,
  86. }, nil
  87. }
  88. // GetBranchesByPath returns a branch by it's path
  89. func GetBranchesByPath(path string) ([]*Branch, error) {
  90. gitRepo, err := OpenRepository(path)
  91. if err != nil {
  92. return nil, err
  93. }
  94. defer gitRepo.Close()
  95. brs, err := gitRepo.GetBranches()
  96. if err != nil {
  97. return nil, err
  98. }
  99. branches := make([]*Branch, len(brs))
  100. for i := range brs {
  101. branches[i] = &Branch{
  102. Path: path,
  103. Name: brs[i],
  104. gitRepo: gitRepo,
  105. }
  106. }
  107. return branches, nil
  108. }
  109. // DeleteBranchOptions Option(s) for delete branch
  110. type DeleteBranchOptions struct {
  111. Force bool
  112. }
  113. // DeleteBranch delete a branch by name on repository.
  114. func (repo *Repository) DeleteBranch(name string, opts DeleteBranchOptions) error {
  115. cmd := NewCommand("branch")
  116. if opts.Force {
  117. cmd.AddArguments("-D")
  118. } else {
  119. cmd.AddArguments("-d")
  120. }
  121. cmd.AddArguments("--", name)
  122. _, err := cmd.RunInDir(repo.Path)
  123. return err
  124. }
  125. // CreateBranch create a new branch
  126. func (repo *Repository) CreateBranch(branch, oldbranchOrCommit string) error {
  127. cmd := NewCommand("branch")
  128. cmd.AddArguments("--", branch, oldbranchOrCommit)
  129. _, err := cmd.RunInDir(repo.Path)
  130. return err
  131. }
  132. // AddRemote adds a new remote to repository.
  133. func (repo *Repository) AddRemote(name, url string, fetch bool) error {
  134. cmd := NewCommand("remote", "add")
  135. if fetch {
  136. cmd.AddArguments("-f")
  137. }
  138. cmd.AddArguments(name, url)
  139. _, err := cmd.RunInDir(repo.Path)
  140. return err
  141. }
  142. // RemoveRemote removes a remote from repository.
  143. func (repo *Repository) RemoveRemote(name string) error {
  144. _, err := NewCommand("remote", "rm", name).RunInDir(repo.Path)
  145. return err
  146. }
  147. // GetCommit returns the head commit of a branch
  148. func (branch *Branch) GetCommit() (*Commit, error) {
  149. return branch.gitRepo.GetBranchCommit(branch.Name)
  150. }