2016-11-04 01:16:01 +03:00
// Copyright 2015 The Gogs Authors. All rights reserved.
2019-04-19 15:17:27 +03:00
// Copyright 2019 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 (
"bytes"
"container/list"
2019-04-19 15:17:27 +03:00
"fmt"
2016-11-04 01:16:01 +03:00
"strconv"
"strings"
2018-05-27 21:47:34 +03:00
2020-03-17 19:19:58 +03:00
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/object"
2016-11-04 01:16:01 +03:00
)
2018-01-19 09:18:51 +03:00
// GetRefCommitID returns the last commit ID string of given reference (branch or tag).
func ( repo * Repository ) GetRefCommitID ( name string ) ( string , error ) {
2019-04-19 15:17:27 +03:00
ref , err := repo . gogitRepo . Reference ( plumbing . ReferenceName ( name ) , true )
2016-11-04 01:16:01 +03:00
if err != nil {
2020-03-09 10:06:38 +03:00
if err == plumbing . ErrReferenceNotFound {
return "" , ErrNotExist {
ID : name ,
}
}
2016-11-04 01:16:01 +03:00
return "" , err
}
2019-04-19 15:17:27 +03:00
return ref . Hash ( ) . String ( ) , nil
2016-11-04 01:16:01 +03:00
}
2019-06-07 23:29:29 +03:00
// IsCommitExist returns true if given commit exists in current repository.
func ( repo * Repository ) IsCommitExist ( name string ) bool {
hash := plumbing . NewHash ( name )
_ , err := repo . gogitRepo . CommitObject ( hash )
2019-06-12 22:41:28 +03:00
return err == nil
2019-06-07 23:29:29 +03:00
}
2016-11-04 01:16:01 +03:00
// GetBranchCommitID returns last commit ID string of given branch.
func ( repo * Repository ) GetBranchCommitID ( name string ) ( string , error ) {
2018-01-19 09:18:51 +03:00
return repo . GetRefCommitID ( BranchPrefix + name )
2016-11-04 01:16:01 +03:00
}
// GetTagCommitID returns last commit ID string of given tag.
func ( repo * Repository ) GetTagCommitID ( name string ) ( string , error ) {
2020-06-12 02:49:47 +03:00
stdout , err := NewCommand ( "rev-list" , "-n" , "1" , TagPrefix + name ) . RunInDir ( repo . Path )
2019-03-11 06:44:58 +03:00
if err != nil {
if strings . Contains ( err . Error ( ) , "unknown revision or path" ) {
return "" , ErrNotExist { name , "" }
}
return "" , err
}
return strings . TrimSpace ( stdout ) , nil
2016-11-04 01:16:01 +03:00
}
2019-04-19 15:17:27 +03:00
func convertPGPSignatureForTag ( t * object . Tag ) * CommitGPGSignature {
if t . PGPSignature == "" {
return nil
}
2018-09-07 05:06:09 +03:00
2019-04-19 15:17:27 +03:00
var w strings . Builder
var err error
if _ , err = fmt . Fprintf ( & w ,
"object %s\ntype %s\ntag %s\ntagger " ,
t . Target . String ( ) , t . TargetType . Bytes ( ) , t . Name ) ; err != nil {
return nil
}
if err = t . Tagger . Encode ( & w ) ; err != nil {
return nil
}
if _ , err = fmt . Fprintf ( & w , "\n\n" ) ; err != nil {
return nil
}
if _ , err = fmt . Fprintf ( & w , t . Message ) ; err != nil {
return nil
}
return & CommitGPGSignature {
Signature : t . PGPSignature ,
Payload : strings . TrimSpace ( w . String ( ) ) + "\n" ,
2016-11-04 01:16:01 +03:00
}
}
2016-12-22 12:30:52 +03:00
func ( repo * Repository ) getCommit ( id SHA1 ) ( * Commit , error ) {
2019-04-19 15:17:27 +03:00
var tagObject * object . Tag
2016-11-04 01:16:01 +03:00
2019-07-23 21:50:39 +03:00
gogitCommit , err := repo . gogitRepo . CommitObject ( id )
2019-04-19 15:17:27 +03:00
if err == plumbing . ErrObjectNotFound {
2019-07-23 21:50:39 +03:00
tagObject , err = repo . gogitRepo . TagObject ( id )
2020-03-28 21:59:21 +03:00
if err == plumbing . ErrObjectNotFound {
return nil , ErrNotExist {
ID : id . String ( ) ,
}
}
2019-04-19 15:17:27 +03:00
if err == nil {
gogitCommit , err = repo . gogitRepo . CommitObject ( tagObject . Target )
2016-11-04 01:16:01 +03:00
}
2020-03-28 21:59:21 +03:00
// if we get a plumbing.ErrObjectNotFound here then the repository is broken and it should be 500
2016-11-04 01:16:01 +03:00
}
if err != nil {
return nil , err
}
2019-04-19 15:17:27 +03:00
commit := convertCommit ( gogitCommit )
2016-11-04 01:16:01 +03:00
commit . repo = repo
2019-04-19 15:17:27 +03:00
if tagObject != nil {
commit . CommitMessage = strings . TrimSpace ( tagObject . Message )
commit . Author = & tagObject . Tagger
commit . Signature = convertPGPSignatureForTag ( tagObject )
}
tree , err := gogitCommit . Tree ( )
2019-02-06 00:47:01 +03:00
if err != nil {
return nil , err
}
2019-04-19 15:17:27 +03:00
commit . Tree . ID = tree . Hash
commit . Tree . gogitTree = tree
2019-02-06 00:47:01 +03:00
2016-11-04 01:16:01 +03:00
return commit , nil
}
2019-08-05 23:39:39 +03:00
// ConvertToSHA1 returns a Hash object from a potential ID string
func ( repo * Repository ) ConvertToSHA1 ( commitID string ) ( SHA1 , error ) {
2016-11-04 01:16:01 +03:00
if len ( commitID ) != 40 {
var err error
2019-08-05 23:39:39 +03:00
actualCommitID , err := NewCommand ( "rev-parse" , "--verify" , commitID ) . RunInDir ( repo . Path )
2016-11-04 01:16:01 +03:00
if err != nil {
2019-08-05 23:39:39 +03:00
if strings . Contains ( err . Error ( ) , "unknown revision or path" ) ||
strings . Contains ( err . Error ( ) , "fatal: Needed a single revision" ) {
return SHA1 { } , ErrNotExist { commitID , "" }
2019-02-03 06:35:17 +03:00
}
2019-08-05 23:39:39 +03:00
return SHA1 { } , err
2016-11-04 01:16:01 +03:00
}
2019-03-11 21:01:00 +03:00
commitID = actualCommitID
2016-11-04 01:16:01 +03:00
}
2019-08-05 23:39:39 +03:00
return NewIDFromString ( commitID )
}
// GetCommit returns commit object of by ID string.
func ( repo * Repository ) GetCommit ( commitID string ) ( * Commit , error ) {
id , err := repo . ConvertToSHA1 ( commitID )
2016-11-04 01:16:01 +03:00
if err != nil {
return nil , err
}
return repo . getCommit ( id )
}
// GetBranchCommit returns the last commit of given branch.
func ( repo * Repository ) GetBranchCommit ( name string ) ( * Commit , error ) {
commitID , err := repo . GetBranchCommitID ( name )
if err != nil {
return nil , err
}
return repo . GetCommit ( commitID )
}
2016-12-22 12:30:52 +03:00
// GetTagCommit get the commit of the specific tag via name
2016-11-04 01:16:01 +03:00
func ( repo * Repository ) GetTagCommit ( name string ) ( * Commit , error ) {
commitID , err := repo . GetTagCommitID ( name )
if err != nil {
return nil , err
}
return repo . GetCommit ( commitID )
}
2016-12-22 12:30:52 +03:00
func ( repo * Repository ) getCommitByPathWithID ( id SHA1 , relpath string ) ( * Commit , error ) {
2016-11-04 01:16:01 +03:00
// File name starts with ':' must be escaped.
if relpath [ 0 ] == ':' {
relpath = ` \ ` + relpath
}
2016-12-22 12:30:52 +03:00
stdout , err := NewCommand ( "log" , "-1" , prettyLogFormat , id . String ( ) , "--" , relpath ) . RunInDir ( repo . Path )
2016-11-04 01:16:01 +03:00
if err != nil {
return nil , err
}
id , err = NewIDFromString ( stdout )
if err != nil {
return nil , err
}
return repo . getCommit ( id )
}
// GetCommitByPath returns the last commit of relative path.
func ( repo * Repository ) GetCommitByPath ( relpath string ) ( * Commit , error ) {
2016-12-22 12:30:52 +03:00
stdout , err := NewCommand ( "log" , "-1" , prettyLogFormat , "--" , relpath ) . RunInDirBytes ( repo . Path )
2016-11-04 01:16:01 +03:00
if err != nil {
return nil , err
}
commits , err := repo . parsePrettyFormatLogToList ( stdout )
if err != nil {
return nil , err
}
return commits . Front ( ) . Value . ( * Commit ) , nil
}
2016-12-22 12:30:52 +03:00
// CommitsRangeSize the default commits range size
2016-11-04 01:16:01 +03:00
var CommitsRangeSize = 50
2020-01-24 22:00:29 +03:00
func ( repo * Repository ) commitsByRange ( id SHA1 , page , pageSize int ) ( * list . List , error ) {
stdout , err := NewCommand ( "log" , id . String ( ) , "--skip=" + strconv . Itoa ( ( page - 1 ) * pageSize ) ,
"--max-count=" + strconv . Itoa ( pageSize ) , prettyLogFormat ) . RunInDirBytes ( repo . Path )
2016-11-04 01:16:01 +03:00
if err != nil {
return nil , err
}
return repo . parsePrettyFormatLogToList ( stdout )
}
2019-04-12 05:28:44 +03:00
func ( repo * Repository ) searchCommits ( id SHA1 , opts SearchCommitsOptions ) ( * list . List , error ) {
2020-06-12 00:44:39 +03:00
// create new git log command with limit of 100 commis
2019-09-03 02:38:04 +03:00
cmd := NewCommand ( "log" , id . String ( ) , "-100" , prettyLogFormat )
2020-06-12 00:44:39 +03:00
// ignore case
2019-09-03 02:38:04 +03:00
args := [ ] string { "-i" }
2020-06-12 00:44:39 +03:00
// add authors if present in search query
2019-04-12 05:28:44 +03:00
if len ( opts . Authors ) > 0 {
for _ , v := range opts . Authors {
2019-09-03 02:38:04 +03:00
args = append ( args , "--author=" + v )
2019-04-12 05:28:44 +03:00
}
}
2020-06-12 00:44:39 +03:00
// add commiters if present in search query
2019-04-12 05:28:44 +03:00
if len ( opts . Committers ) > 0 {
for _ , v := range opts . Committers {
2019-09-03 02:38:04 +03:00
args = append ( args , "--committer=" + v )
2019-04-12 05:28:44 +03:00
}
}
2020-06-12 00:44:39 +03:00
// add time constraints if present in search query
2019-04-12 05:28:44 +03:00
if len ( opts . After ) > 0 {
2019-09-03 02:38:04 +03:00
args = append ( args , "--after=" + opts . After )
2019-04-12 05:28:44 +03:00
}
if len ( opts . Before ) > 0 {
2019-09-03 02:38:04 +03:00
args = append ( args , "--before=" + opts . Before )
2019-04-12 05:28:44 +03:00
}
2020-06-12 00:44:39 +03:00
// pretend that all refs along with HEAD were listed on command line as <commis>
// https://git-scm.com/docs/git-log#Documentation/git-log.txt---all
// note this is done only for command created above
2019-04-12 05:28:44 +03:00
if opts . All {
2020-06-12 00:44:39 +03:00
cmd . AddArguments ( "--all" )
2019-09-03 02:38:04 +03:00
}
2020-06-12 00:44:39 +03:00
// add remaining keywords from search string
// note this is done only for command created above
2019-09-03 02:38:04 +03:00
if len ( opts . Keywords ) > 0 {
for _ , v := range opts . Keywords {
cmd . AddArguments ( "--grep=" + v )
}
2017-02-05 17:43:28 +03:00
}
2020-06-12 00:44:39 +03:00
// search for commits matching given constraints and keywords in commit msg
2019-09-03 02:38:04 +03:00
cmd . AddArguments ( args ... )
2017-02-05 17:43:28 +03:00
stdout , err := cmd . RunInDirBytes ( repo . Path )
2016-11-04 01:16:01 +03:00
if err != nil {
return nil , err
}
2019-09-03 02:38:04 +03:00
if len ( stdout ) != 0 {
stdout = append ( stdout , '\n' )
}
2020-06-12 00:44:39 +03:00
// if there are any keywords (ie not commiter:, author:, time:)
// then let's iterate over them
2019-09-03 02:38:04 +03:00
if len ( opts . Keywords ) > 0 {
for _ , v := range opts . Keywords {
2020-06-12 00:44:39 +03:00
// ignore anything below 4 characters as too unspecific
2019-09-03 02:38:04 +03:00
if len ( v ) >= 4 {
2020-06-12 00:44:39 +03:00
// create new git log command with 1 commit limit
2019-09-03 02:38:04 +03:00
hashCmd := NewCommand ( "log" , "-1" , prettyLogFormat )
2020-06-12 00:44:39 +03:00
// add previous arguments except for --grep and --all
2019-09-03 02:38:04 +03:00
hashCmd . AddArguments ( args ... )
2020-06-12 00:44:39 +03:00
// add keyword as <commit>
2019-09-03 02:38:04 +03:00
hashCmd . AddArguments ( v )
2020-06-12 00:44:39 +03:00
// search with given constraints for commit matching sha hash of v
2019-09-03 02:38:04 +03:00
hashMatching , err := hashCmd . RunInDirBytes ( repo . Path )
if err != nil || bytes . Contains ( stdout , hashMatching ) {
continue
}
stdout = append ( stdout , hashMatching ... )
stdout = append ( stdout , '\n' )
}
}
}
return repo . parsePrettyFormatLogToList ( bytes . TrimSuffix ( stdout , [ ] byte { '\n' } ) )
2016-11-04 01:16:01 +03:00
}
2019-04-17 19:06:35 +03:00
func ( repo * Repository ) getFilesChanged ( id1 , id2 string ) ( [ ] string , error ) {
2016-11-04 01:16:01 +03:00
stdout , err := NewCommand ( "diff" , "--name-only" , id1 , id2 ) . RunInDirBytes ( repo . Path )
if err != nil {
return nil , err
}
return strings . Split ( string ( stdout ) , "\n" ) , nil
}
2019-04-17 19:06:35 +03:00
// FileChangedBetweenCommits Returns true if the file changed between commit IDs id1 and id2
2019-08-05 23:39:39 +03:00
// You must ensure that id1 and id2 are valid commit ids.
2019-04-17 19:06:35 +03:00
func ( repo * Repository ) FileChangedBetweenCommits ( filename , id1 , id2 string ) ( bool , error ) {
stdout , err := NewCommand ( "diff" , "--name-only" , "-z" , id1 , id2 , "--" , filename ) . RunInDirBytes ( repo . Path )
if err != nil {
return false , err
}
return len ( strings . TrimSpace ( string ( stdout ) ) ) > 0 , nil
}
2016-12-22 12:30:52 +03:00
// FileCommitsCount return the number of files at a revison
2016-11-04 01:16:01 +03:00
func ( repo * Repository ) FileCommitsCount ( revision , file string ) ( int64 , error ) {
2020-07-29 20:53:04 +03:00
return commitsCount ( repo . Path , [ ] string { revision } , [ ] string { file } )
2016-11-04 01:16:01 +03:00
}
2019-03-27 12:33:00 +03:00
// CommitsByFileAndRange return the commits according revison file and the page
2016-11-04 01:16:01 +03:00
func ( repo * Repository ) CommitsByFileAndRange ( revision , file string , page int ) ( * list . List , error ) {
2017-04-08 05:23:39 +03:00
stdout , err := NewCommand ( "log" , revision , "--follow" , "--skip=" + strconv . Itoa ( ( page - 1 ) * 50 ) ,
2016-12-22 12:30:52 +03:00
"--max-count=" + strconv . Itoa ( CommitsRangeSize ) , prettyLogFormat , "--" , file ) . RunInDirBytes ( repo . Path )
2016-11-04 01:16:01 +03:00
if err != nil {
return nil , err
}
return repo . parsePrettyFormatLogToList ( stdout )
}
2019-07-11 17:45:10 +03:00
// CommitsByFileAndRangeNoFollow return the commits according revison file and the page
func ( repo * Repository ) CommitsByFileAndRangeNoFollow ( revision , file string , page int ) ( * list . List , error ) {
stdout , err := NewCommand ( "log" , revision , "--skip=" + strconv . Itoa ( ( page - 1 ) * 50 ) ,
"--max-count=" + strconv . Itoa ( CommitsRangeSize ) , prettyLogFormat , "--" , file ) . RunInDirBytes ( repo . Path )
if err != nil {
return nil , err
}
return repo . parsePrettyFormatLogToList ( stdout )
}
2016-12-22 12:30:52 +03:00
// FilesCountBetween return the number of files changed between two commits
2016-11-04 01:16:01 +03:00
func ( repo * Repository ) FilesCountBetween ( startCommitID , endCommitID string ) ( int , error ) {
stdout , err := NewCommand ( "diff" , "--name-only" , startCommitID + "..." + endCommitID ) . RunInDir ( repo . Path )
2020-07-29 20:53:04 +03:00
if err != nil && strings . Contains ( err . Error ( ) , "no merge base" ) {
// git >= 2.28 now returns an error if startCommitID and endCommitID have become unrelated.
// previously it would return the results of git diff --name-only startCommitID endCommitID so let's try that...
stdout , err = NewCommand ( "diff" , "--name-only" , startCommitID , endCommitID ) . RunInDir ( repo . Path )
}
2016-11-04 01:16:01 +03:00
if err != nil {
return 0 , err
}
return len ( strings . Split ( stdout , "\n" ) ) - 1 , nil
}
// CommitsBetween returns a list that contains commits between [last, before).
func ( repo * Repository ) CommitsBetween ( last * Commit , before * Commit ) ( * list . List , error ) {
2019-12-31 02:34:11 +03:00
var stdout [ ] byte
var err error
if before == nil {
2020-02-11 02:04:43 +03:00
stdout , err = NewCommand ( "rev-list" , last . ID . String ( ) ) . RunInDirBytes ( repo . Path )
2019-12-31 02:34:11 +03:00
} else {
stdout , err = NewCommand ( "rev-list" , before . ID . String ( ) + "..." + last . ID . String ( ) ) . RunInDirBytes ( repo . Path )
2020-07-29 20:53:04 +03:00
if err != nil && strings . Contains ( err . Error ( ) , "no merge base" ) {
// future versions of git >= 2.28 are likely to return an error if before and last have become unrelated.
// previously it would return the results of git rev-list before last so let's try that...
stdout , err = NewCommand ( "rev-list" , before . ID . String ( ) , last . ID . String ( ) ) . RunInDirBytes ( repo . Path )
}
2019-12-31 02:34:11 +03:00
}
if err != nil {
return nil , err
}
return repo . parsePrettyFormatLogToList ( bytes . TrimSpace ( stdout ) )
}
// CommitsBetweenLimit returns a list that contains at most limit commits skipping the first skip commits between [last, before)
func ( repo * Repository ) CommitsBetweenLimit ( last * Commit , before * Commit , limit , skip int ) ( * list . List , error ) {
var stdout [ ] byte
var err error
if before == nil {
stdout , err = NewCommand ( "rev-list" , "--max-count" , strconv . Itoa ( limit ) , "--skip" , strconv . Itoa ( skip ) , last . ID . String ( ) ) . RunInDirBytes ( repo . Path )
} else {
stdout , err = NewCommand ( "rev-list" , "--max-count" , strconv . Itoa ( limit ) , "--skip" , strconv . Itoa ( skip ) , before . ID . String ( ) + "..." + last . ID . String ( ) ) . RunInDirBytes ( repo . Path )
2020-07-29 20:53:04 +03:00
if err != nil && strings . Contains ( err . Error ( ) , "no merge base" ) {
// future versions of git >= 2.28 are likely to return an error if before and last have become unrelated.
// previously it would return the results of git rev-list --max-count n before last so let's try that...
stdout , err = NewCommand ( "rev-list" , "--max-count" , strconv . Itoa ( limit ) , "--skip" , strconv . Itoa ( skip ) , before . ID . String ( ) , last . ID . String ( ) ) . RunInDirBytes ( repo . Path )
}
2019-12-31 02:34:11 +03:00
}
2017-10-23 16:36:14 +03:00
if err != nil {
return nil , err
2016-11-04 01:16:01 +03:00
}
2017-10-23 16:36:14 +03:00
return repo . parsePrettyFormatLogToList ( bytes . TrimSpace ( stdout ) )
2016-11-04 01:16:01 +03:00
}
2016-12-22 12:30:52 +03:00
// CommitsBetweenIDs return commits between twoe commits
2016-11-04 01:16:01 +03:00
func ( repo * Repository ) CommitsBetweenIDs ( last , before string ) ( * list . List , error ) {
lastCommit , err := repo . GetCommit ( last )
if err != nil {
return nil , err
}
2019-12-31 02:34:11 +03:00
if before == "" {
return repo . CommitsBetween ( lastCommit , nil )
}
2016-11-04 01:16:01 +03:00
beforeCommit , err := repo . GetCommit ( before )
if err != nil {
return nil , err
}
return repo . CommitsBetween ( lastCommit , beforeCommit )
}
2016-12-22 12:30:52 +03:00
// CommitsCountBetween return numbers of commits between two commits
2016-11-04 01:16:01 +03:00
func ( repo * Repository ) CommitsCountBetween ( start , end string ) ( int64 , error ) {
2020-07-29 20:53:04 +03:00
count , err := commitsCount ( repo . Path , [ ] string { start + "..." + end } , [ ] string { } )
if err != nil && strings . Contains ( err . Error ( ) , "no merge base" ) {
// future versions of git >= 2.28 are likely to return an error if before and last have become unrelated.
// previously it would return the results of git rev-list before last so let's try that...
return commitsCount ( repo . Path , [ ] string { start , end } , [ ] string { } )
}
return count , err
2016-11-04 01:16:01 +03:00
}
2016-12-22 12:30:52 +03:00
// commitsBefore the limit is depth, not total number of returned commits.
2017-12-11 05:23:34 +03:00
func ( repo * Repository ) commitsBefore ( id SHA1 , limit int ) ( * list . List , error ) {
cmd := NewCommand ( "log" )
if limit > 0 {
2018-05-27 21:47:34 +03:00
cmd . AddArguments ( "-" + strconv . Itoa ( limit ) , prettyLogFormat , id . String ( ) )
2017-12-11 05:23:34 +03:00
} else {
cmd . AddArguments ( prettyLogFormat , id . String ( ) )
2016-11-04 01:16:01 +03:00
}
2017-12-11 05:23:34 +03:00
stdout , err := cmd . RunInDirBytes ( repo . Path )
2016-11-04 01:16:01 +03:00
if err != nil {
2017-12-11 05:23:34 +03:00
return nil , err
2016-11-04 01:16:01 +03:00
}
2017-12-11 05:23:34 +03:00
formattedLog , err := repo . parsePrettyFormatLogToList ( bytes . TrimSpace ( stdout ) )
if err != nil {
return nil , err
2016-11-04 01:16:01 +03:00
}
2017-12-11 05:23:34 +03:00
commits := list . New ( )
for logEntry := formattedLog . Front ( ) ; logEntry != nil ; logEntry = logEntry . Next ( ) {
commit := logEntry . Value . ( * Commit )
branches , err := repo . getBranches ( commit , 2 )
2016-11-04 01:16:01 +03:00
if err != nil {
2017-12-11 05:23:34 +03:00
return nil , err
2016-11-04 01:16:01 +03:00
}
2017-12-11 05:23:34 +03:00
if len ( branches ) > 1 {
break
2016-11-04 01:16:01 +03:00
}
2017-12-11 05:23:34 +03:00
commits . PushBack ( commit )
2016-11-04 01:16:01 +03:00
}
2017-12-11 05:23:34 +03:00
return commits , nil
2016-11-04 01:16:01 +03:00
}
2016-12-22 12:30:52 +03:00
func ( repo * Repository ) getCommitsBefore ( id SHA1 ) ( * list . List , error ) {
2017-12-11 05:23:34 +03:00
return repo . commitsBefore ( id , 0 )
2016-11-04 01:16:01 +03:00
}
2016-12-22 12:30:52 +03:00
func ( repo * Repository ) getCommitsBeforeLimit ( id SHA1 , num int ) ( * list . List , error ) {
2017-12-11 05:23:34 +03:00
return repo . commitsBefore ( id , num )
}
func ( repo * Repository ) getBranches ( commit * Commit , limit int ) ( [ ] string , error ) {
2020-09-05 19:42:58 +03:00
if CheckGitVersionConstraint ( ">= 2.7.0" ) == nil {
2018-05-27 21:47:34 +03:00
stdout , err := NewCommand ( "for-each-ref" , "--count=" + strconv . Itoa ( limit ) , "--format=%(refname:strip=2)" , "--contains" , commit . ID . String ( ) , BranchPrefix ) . RunInDir ( repo . Path )
if err != nil {
return nil , err
}
branches := strings . Fields ( stdout )
return branches , nil
}
stdout , err := NewCommand ( "branch" , "--contains" , commit . ID . String ( ) ) . RunInDir ( repo . Path )
2017-12-11 05:23:34 +03:00
if err != nil {
return nil , err
}
refs := strings . Split ( stdout , "\n" )
2018-05-27 21:47:34 +03:00
var max int
if len ( refs ) > limit {
max = limit
} else {
max = len ( refs ) - 1
}
branches := make ( [ ] string , max )
for i , ref := range refs [ : max ] {
parts := strings . Fields ( ref )
branches [ i ] = parts [ len ( parts ) - 1 ]
2017-12-11 05:23:34 +03:00
}
return branches , nil
2016-11-04 01:16:01 +03:00
}
2020-05-20 15:47:24 +03:00
// GetCommitsFromIDs get commits from commit IDs
func ( repo * Repository ) GetCommitsFromIDs ( commitIDs [ ] string ) ( commits * list . List ) {
if len ( commitIDs ) == 0 {
return nil
}
commits = list . New ( )
for _ , commitID := range commitIDs {
commit , err := repo . GetCommit ( commitID )
if err == nil && commit != nil {
commits . PushBack ( commit )
}
}
return commits
}