2016-11-04 01:16:01 +03:00
// Copyright 2015 The Gogs Authors. All rights reserved.
2018-11-28 00:52:20 +03:00
// Copyright 2018 The Gitea Authors. All rights reserved.
2016-11-04 01:16:01 +03:00
// 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"
2018-11-28 00:52:20 +03:00
2020-03-17 19:19:58 +03:00
"github.com/go-git/go-git/v5/plumbing"
2016-11-04 01:16:01 +03:00
)
2016-12-22 12:30:52 +03:00
// BranchPrefix base dir of the branch information file store on git
const BranchPrefix = "refs/heads/"
2016-11-04 01:16:01 +03:00
// IsReferenceExist returns true if given reference exists in the repository.
func IsReferenceExist ( repoPath , name string ) bool {
2019-05-11 18:29:17 +03:00
_ , err := NewCommand ( "show-ref" , "--verify" , "--" , name ) . RunInDir ( repoPath )
2016-11-04 01:16:01 +03:00
return err == nil
}
// IsBranchExist returns true if given branch exists in the repository.
func IsBranchExist ( repoPath , name string ) bool {
2016-12-22 12:30:52 +03:00
return IsReferenceExist ( repoPath , BranchPrefix + name )
2016-11-04 01:16:01 +03:00
}
2016-12-22 12:30:52 +03:00
// IsBranchExist returns true if given branch exists in current repository.
2016-11-04 01:16:01 +03:00
func ( repo * Repository ) IsBranchExist ( name string ) bool {
2019-10-13 19:29:08 +03:00
if name == "" {
return false
}
reference , err := repo . gogitRepo . Reference ( plumbing . ReferenceName ( BranchPrefix + name ) , true )
if err != nil {
return false
}
return reference . Type ( ) != plumbing . InvalidReference
2016-11-04 01:16:01 +03:00
}
// Branch represents a Git branch.
type Branch struct {
Name string
Path string
2019-04-19 15:17:27 +03:00
gitRepo * Repository
2016-11-04 01:16:01 +03:00
}
// GetHEADBranch returns corresponding branch of HEAD.
func ( repo * Repository ) GetHEADBranch ( ) ( * Branch , error ) {
2020-02-26 09:32:22 +03:00
if repo == nil {
return nil , fmt . Errorf ( "nil repo" )
}
2016-11-04 01:16:01 +03:00
stdout , err := NewCommand ( "symbolic-ref" , "HEAD" ) . RunInDir ( repo . Path )
if err != nil {
return nil , err
}
stdout = strings . TrimSpace ( stdout )
2016-12-22 12:30:52 +03:00
if ! strings . HasPrefix ( stdout , BranchPrefix ) {
2016-11-04 01:16:01 +03:00
return nil , fmt . Errorf ( "invalid HEAD branch: %v" , stdout )
}
return & Branch {
2019-04-19 15:17:27 +03:00
Name : stdout [ len ( BranchPrefix ) : ] ,
Path : stdout ,
gitRepo : repo ,
2016-11-04 01:16:01 +03:00
} , nil
}
// SetDefaultBranch sets default branch of repository.
func ( repo * Repository ) SetDefaultBranch ( name string ) error {
2016-12-22 12:30:52 +03:00
_ , err := NewCommand ( "symbolic-ref" , "HEAD" , BranchPrefix + name ) . RunInDir ( repo . Path )
2016-11-04 01:16:01 +03:00
return err
}
// GetBranches returns all branches of the repository.
func ( repo * Repository ) GetBranches ( ) ( [ ] string , error ) {
2019-04-19 15:17:27 +03:00
var branchNames [ ] string
branches , err := repo . gogitRepo . Branches ( )
2016-11-04 01:16:01 +03:00
if err != nil {
return nil , err
}
2019-06-12 22:41:28 +03:00
_ = branches . ForEach ( func ( branch * plumbing . Reference ) error {
2019-04-19 15:17:27 +03:00
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 )
2018-11-28 00:52:20 +03:00
if err != nil {
return nil , err
2016-11-04 01:16:01 +03:00
}
2019-11-13 10:01:19 +03:00
defer gitRepo . Close ( )
2019-04-19 15:17:27 +03:00
brs , err := gitRepo . GetBranches ( )
if err != nil {
2018-11-28 00:52:20 +03:00
return nil , err
}
2019-04-19 15:17:27 +03:00
branches := make ( [ ] * Branch , len ( brs ) )
for i := range brs {
branches [ i ] = & Branch {
Path : path ,
Name : brs [ i ] ,
gitRepo : gitRepo ,
}
}
2016-11-04 01:16:01 +03:00
return branches , nil
}
2016-12-22 12:30:52 +03:00
// DeleteBranchOptions Option(s) for delete branch
2016-11-04 01:16:01 +03:00
type DeleteBranchOptions struct {
Force bool
}
// DeleteBranch delete a branch by name on repository.
func ( repo * Repository ) DeleteBranch ( name string , opts DeleteBranchOptions ) error {
2017-08-03 16:48:36 +03:00
cmd := NewCommand ( "branch" )
2016-11-04 01:16:01 +03:00
if opts . Force {
2017-08-03 16:48:36 +03:00
cmd . AddArguments ( "-D" )
} else {
cmd . AddArguments ( "-d" )
2016-11-04 01:16:01 +03:00
}
2019-08-05 23:39:39 +03:00
cmd . AddArguments ( "--" , name )
2016-11-04 01:16:01 +03:00
_ , err := cmd . RunInDir ( repo . Path )
return err
}
2017-02-05 17:43:28 +03:00
// CreateBranch create a new branch
2019-05-11 18:29:17 +03:00
func ( repo * Repository ) CreateBranch ( branch , oldbranchOrCommit string ) error {
2017-02-05 17:43:28 +03:00
cmd := NewCommand ( "branch" )
2019-05-11 18:29:17 +03:00
cmd . AddArguments ( "--" , branch , oldbranchOrCommit )
2017-02-05 17:43:28 +03:00
_ , err := cmd . RunInDir ( repo . Path )
return err
}
2016-11-04 01:16:01 +03:00
// 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 {
2019-10-12 03:13:27 +03:00
_ , err := NewCommand ( "remote" , "rm" , name ) . RunInDir ( repo . Path )
2016-11-04 01:16:01 +03:00
return err
}
2019-04-19 15:17:27 +03:00
// GetCommit returns the head commit of a branch
func ( branch * Branch ) GetCommit ( ) ( * Commit , error ) {
return branch . gitRepo . GetBranchCommit ( branch . Name )
}