forked from Shiloh/githaven
722a7c902d
In investigating #7947 it has become clear that the storage component of go-git repositories needs closing. This PR adds this Close function and adds the Close functions as necessary. In TransferOwnership the ctx.Repo.GitRepo is closed if it is open to help prevent the risk of multiple open files. Fixes #7947
183 lines
4.3 KiB
Go
183 lines
4.3 KiB
Go
// Copyright 2015 The Gogs Authors. All rights reserved.
|
|
// Copyright 2018 The Gitea Authors. All rights reserved.
|
|
// Use of this source code is governed by a MIT-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package git
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"gopkg.in/src-d/go-git.v4/plumbing"
|
|
)
|
|
|
|
// BranchPrefix base dir of the branch information file store on git
|
|
const BranchPrefix = "refs/heads/"
|
|
|
|
// IsReferenceExist returns true if given reference exists in the repository.
|
|
func IsReferenceExist(repoPath, name string) bool {
|
|
_, err := NewCommand("show-ref", "--verify", "--", name).RunInDir(repoPath)
|
|
return err == nil
|
|
}
|
|
|
|
// IsBranchExist returns true if given branch exists in the repository.
|
|
func IsBranchExist(repoPath, name string) bool {
|
|
return IsReferenceExist(repoPath, BranchPrefix+name)
|
|
}
|
|
|
|
// IsBranchExist returns true if given branch exists in current repository.
|
|
func (repo *Repository) IsBranchExist(name string) bool {
|
|
if name == "" {
|
|
return false
|
|
}
|
|
reference, err := repo.gogitRepo.Reference(plumbing.ReferenceName(BranchPrefix+name), true)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
return reference.Type() != plumbing.InvalidReference
|
|
}
|
|
|
|
// Branch represents a Git branch.
|
|
type Branch struct {
|
|
Name string
|
|
Path string
|
|
|
|
gitRepo *Repository
|
|
}
|
|
|
|
// GetHEADBranch returns corresponding branch of HEAD.
|
|
func (repo *Repository) GetHEADBranch() (*Branch, error) {
|
|
stdout, err := NewCommand("symbolic-ref", "HEAD").RunInDir(repo.Path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
stdout = strings.TrimSpace(stdout)
|
|
|
|
if !strings.HasPrefix(stdout, BranchPrefix) {
|
|
return nil, fmt.Errorf("invalid HEAD branch: %v", stdout)
|
|
}
|
|
|
|
return &Branch{
|
|
Name: stdout[len(BranchPrefix):],
|
|
Path: stdout,
|
|
gitRepo: repo,
|
|
}, nil
|
|
}
|
|
|
|
// SetDefaultBranch sets default branch of repository.
|
|
func (repo *Repository) SetDefaultBranch(name string) error {
|
|
_, err := NewCommand("symbolic-ref", "HEAD", BranchPrefix+name).RunInDir(repo.Path)
|
|
return err
|
|
}
|
|
|
|
// GetBranches returns all branches of the repository.
|
|
func (repo *Repository) GetBranches() ([]string, error) {
|
|
var branchNames []string
|
|
|
|
branches, err := repo.gogitRepo.Branches()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
_ = branches.ForEach(func(branch *plumbing.Reference) error {
|
|
branchNames = append(branchNames, strings.TrimPrefix(branch.Name().String(), BranchPrefix))
|
|
return nil
|
|
})
|
|
|
|
// TODO: Sort?
|
|
|
|
return branchNames, nil
|
|
}
|
|
|
|
// GetBranch returns a branch by it's name
|
|
func (repo *Repository) GetBranch(branch string) (*Branch, error) {
|
|
if !repo.IsBranchExist(branch) {
|
|
return nil, ErrBranchNotExist{branch}
|
|
}
|
|
return &Branch{
|
|
Path: repo.Path,
|
|
Name: branch,
|
|
gitRepo: repo,
|
|
}, nil
|
|
}
|
|
|
|
// GetBranchesByPath returns a branch by it's path
|
|
func GetBranchesByPath(path string) ([]*Branch, error) {
|
|
gitRepo, err := OpenRepository(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer gitRepo.Close()
|
|
|
|
brs, err := gitRepo.GetBranches()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
branches := make([]*Branch, len(brs))
|
|
for i := range brs {
|
|
branches[i] = &Branch{
|
|
Path: path,
|
|
Name: brs[i],
|
|
gitRepo: gitRepo,
|
|
}
|
|
}
|
|
|
|
return branches, nil
|
|
}
|
|
|
|
// DeleteBranchOptions Option(s) for delete branch
|
|
type DeleteBranchOptions struct {
|
|
Force bool
|
|
}
|
|
|
|
// DeleteBranch delete a branch by name on repository.
|
|
func (repo *Repository) DeleteBranch(name string, opts DeleteBranchOptions) error {
|
|
cmd := NewCommand("branch")
|
|
|
|
if opts.Force {
|
|
cmd.AddArguments("-D")
|
|
} else {
|
|
cmd.AddArguments("-d")
|
|
}
|
|
|
|
cmd.AddArguments("--", name)
|
|
_, err := cmd.RunInDir(repo.Path)
|
|
|
|
return err
|
|
}
|
|
|
|
// CreateBranch create a new branch
|
|
func (repo *Repository) CreateBranch(branch, oldbranchOrCommit string) error {
|
|
cmd := NewCommand("branch")
|
|
cmd.AddArguments("--", branch, oldbranchOrCommit)
|
|
|
|
_, err := cmd.RunInDir(repo.Path)
|
|
|
|
return err
|
|
}
|
|
|
|
// AddRemote adds a new remote to repository.
|
|
func (repo *Repository) AddRemote(name, url string, fetch bool) error {
|
|
cmd := NewCommand("remote", "add")
|
|
if fetch {
|
|
cmd.AddArguments("-f")
|
|
}
|
|
cmd.AddArguments(name, url)
|
|
|
|
_, err := cmd.RunInDir(repo.Path)
|
|
return err
|
|
}
|
|
|
|
// RemoveRemote removes a remote from repository.
|
|
func (repo *Repository) RemoveRemote(name string) error {
|
|
_, err := NewCommand("remote", "rm", name).RunInDir(repo.Path)
|
|
return err
|
|
}
|
|
|
|
// GetCommit returns the head commit of a branch
|
|
func (branch *Branch) GetCommit() (*Commit, error) {
|
|
return branch.gitRepo.GetBranchCommit(branch.Name)
|
|
}
|