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"
2021-03-04 03:48:19 +03:00
"io"
2016-11-04 01:16:01 +03:00
"strconv"
"strings"
2021-06-26 14:28:55 +03:00
"code.gitea.io/gitea/modules/setting"
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 ) {
2021-04-14 17:22:37 +03:00
return repo . GetRefCommitID ( TagPrefix + name )
2016-11-04 01:16:01 +03:00
}
2019-08-05 23:39:39 +03:00
// 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
}
2022-02-06 22:01:47 +03:00
stdout , err := NewCommand ( repo . Ctx , "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 ) {
2022-02-06 22:01:47 +03:00
stdout , err := NewCommand ( repo . Ctx , "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
}
2021-08-09 21:08:51 +03:00
return commits [ 0 ] , nil
2016-11-04 01:16:01 +03:00
}
2021-08-09 21:08:51 +03:00
func ( repo * Repository ) commitsByRange ( id SHA1 , page , pageSize int ) ( [ ] * Commit , error ) {
2022-02-06 22:01:47 +03:00
stdout , err := NewCommand ( repo . Ctx , "log" , id . String ( ) , "--skip=" + strconv . Itoa ( ( page - 1 ) * pageSize ) ,
2020-01-24 22:00:29 +03:00
"--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 )
}
2021-08-09 21:08:51 +03:00
func ( repo * Repository ) searchCommits ( id SHA1 , opts SearchCommitsOptions ) ( [ ] * Commit , error ) {
2020-06-12 00:44:39 +03:00
// create new git log command with limit of 100 commis
2022-02-06 22:01:47 +03:00
cmd := NewCommand ( repo . Ctx , "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
2021-07-08 14:38:13 +03:00
// add committers 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
2021-07-08 14:38:13 +03:00
// if there are any keywords (ie not committer:, author:, time:)
2020-06-12 00:44:39 +03:00
// 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
2022-02-06 22:01:47 +03:00
hashCmd := NewCommand ( repo . Ctx , "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 ) {
2022-02-06 22:01:47 +03:00
stdout , err := NewCommand ( repo . Ctx , "diff" , "--name-only" , id1 , id2 ) . RunInDirBytes ( repo . Path )
2016-11-04 01:16:01 +03:00
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 ) {
2022-02-06 22:01:47 +03:00
stdout , err := NewCommand ( repo . Ctx , "diff" , "--name-only" , "-z" , id1 , id2 , "--" , filename ) . RunInDirBytes ( repo . Path )
2019-04-17 19:06:35 +03:00
if err != nil {
return false , err
}
return len ( strings . TrimSpace ( string ( stdout ) ) ) > 0 , nil
}
2021-07-08 14:38:13 +03:00
// FileCommitsCount return the number of files at a revision
2016-11-04 01:16:01 +03:00
func ( repo * Repository ) FileCommitsCount ( revision , file string ) ( int64 , error ) {
2022-01-20 02:26:57 +03:00
return CommitsCountFiles ( repo . Ctx , repo . Path , [ ] string { revision } , [ ] string { file } )
2016-11-04 01:16:01 +03:00
}
2021-07-08 14:38:13 +03:00
// CommitsByFileAndRange return the commits according revision file and the page
2021-08-09 21:08:51 +03:00
func ( repo * Repository ) CommitsByFileAndRange ( revision , file string , page int ) ( [ ] * Commit , error ) {
2021-06-26 14:28:55 +03:00
skip := ( page - 1 ) * setting . Git . CommitsRangeSize
2021-03-04 03:48:19 +03:00
stdoutReader , stdoutWriter := io . Pipe ( )
defer func ( ) {
_ = stdoutReader . Close ( )
_ = stdoutWriter . Close ( )
} ( )
go func ( ) {
stderr := strings . Builder { }
2022-02-06 22:01:47 +03:00
err := NewCommand ( repo . Ctx , "log" , revision , "--follow" ,
2021-06-26 14:28:55 +03:00
"--max-count=" + strconv . Itoa ( setting . Git . CommitsRangeSize * page ) ,
2021-03-04 03:48:19 +03:00
prettyLogFormat , "--" , file ) .
2022-02-11 15:47:22 +03:00
RunWithContext ( & RunContext {
Timeout : - 1 ,
Dir : repo . Path ,
Stdout : stdoutWriter ,
Stderr : & stderr ,
} )
2021-03-04 03:48:19 +03:00
if err != nil {
_ = stdoutWriter . CloseWithError ( ConcatenateError ( err , ( & stderr ) . String ( ) ) )
} else {
_ = stdoutWriter . Close ( )
}
} ( )
if skip > 0 {
2021-09-22 08:38:34 +03:00
_ , err := io . CopyN ( io . Discard , stdoutReader , int64 ( skip * 41 ) )
2021-03-04 03:48:19 +03:00
if err != nil {
if err == io . EOF {
2021-08-09 21:08:51 +03:00
return [ ] * Commit { } , nil
2021-03-04 03:48:19 +03:00
}
_ = stdoutReader . CloseWithError ( err )
return nil , err
}
}
2021-09-22 08:38:34 +03:00
stdout , err := io . ReadAll ( stdoutReader )
2016-11-04 01:16:01 +03:00
if err != nil {
return nil , err
}
return repo . parsePrettyFormatLogToList ( stdout )
}
2021-07-08 14:38:13 +03:00
// CommitsByFileAndRangeNoFollow return the commits according revision file and the page
2021-08-09 21:08:51 +03:00
func ( repo * Repository ) CommitsByFileAndRangeNoFollow ( revision , file string , page int ) ( [ ] * Commit , error ) {
2022-02-06 22:01:47 +03:00
stdout , err := NewCommand ( repo . Ctx , "log" , revision , "--skip=" + strconv . Itoa ( ( page - 1 ) * 50 ) ,
2021-06-26 14:28:55 +03:00
"--max-count=" + strconv . Itoa ( setting . Git . CommitsRangeSize ) , prettyLogFormat , "--" , file ) . RunInDirBytes ( repo . Path )
2019-07-11 17:45:10 +03:00
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 ) {
2022-02-06 22:01:47 +03:00
stdout , err := NewCommand ( repo . Ctx , "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...
2022-02-06 22:01:47 +03:00
stdout , err = NewCommand ( repo . Ctx , "diff" , "--name-only" , startCommitID , endCommitID ) . RunInDir ( repo . Path )
2020-07-29 20:53:04 +03:00
}
2016-11-04 01:16:01 +03:00
if err != nil {
return 0 , err
}
return len ( strings . Split ( stdout , "\n" ) ) - 1 , nil
}
2021-06-30 20:49:06 +03:00
// CommitsBetween returns a list that contains commits between [before, last).
// If before is detached (removed by reset + push) it is not included.
2021-12-20 07:41:31 +03:00
func ( repo * Repository ) CommitsBetween ( last , before * Commit ) ( [ ] * Commit , error ) {
2019-12-31 02:34:11 +03:00
var stdout [ ] byte
var err error
if before == nil {
2022-02-06 22:01:47 +03:00
stdout , err = NewCommand ( repo . Ctx , "rev-list" , last . ID . String ( ) ) . RunInDirBytes ( repo . Path )
2019-12-31 02:34:11 +03:00
} else {
2022-02-06 22:01:47 +03:00
stdout , err = NewCommand ( repo . Ctx , "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...
2022-02-06 22:01:47 +03:00
stdout , err = NewCommand ( repo . Ctx , "rev-list" , before . ID . String ( ) , last . ID . String ( ) ) . RunInDirBytes ( repo . Path )
2020-07-29 20:53:04 +03:00
}
2019-12-31 02:34:11 +03:00
}
if err != nil {
return nil , err
}
return repo . parsePrettyFormatLogToList ( bytes . TrimSpace ( stdout ) )
}
2021-06-30 20:49:06 +03:00
// CommitsBetweenLimit returns a list that contains at most limit commits skipping the first skip commits between [before, last)
2021-12-20 07:41:31 +03:00
func ( repo * Repository ) CommitsBetweenLimit ( last , before * Commit , limit , skip int ) ( [ ] * Commit , error ) {
2019-12-31 02:34:11 +03:00
var stdout [ ] byte
var err error
if before == nil {
2022-02-06 22:01:47 +03:00
stdout , err = NewCommand ( repo . Ctx , "rev-list" , "--max-count" , strconv . Itoa ( limit ) , "--skip" , strconv . Itoa ( skip ) , last . ID . String ( ) ) . RunInDirBytes ( repo . Path )
2019-12-31 02:34:11 +03:00
} else {
2022-02-06 22:01:47 +03:00
stdout , err = NewCommand ( repo . Ctx , "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...
2022-02-06 22:01:47 +03:00
stdout , err = NewCommand ( repo . Ctx , "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
}
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
2021-08-09 21:08:51 +03:00
func ( repo * Repository ) CommitsBetweenIDs ( last , before string ) ( [ ] * Commit , error ) {
2016-11-04 01:16:01 +03:00
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 ) {
2022-01-20 02:26:57 +03:00
count , err := CommitsCountFiles ( repo . Ctx , repo . Path , [ ] string { start + ".." + end } , [ ] string { } )
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...
2022-01-20 02:26:57 +03:00
return CommitsCountFiles ( repo . Ctx , repo . Path , [ ] string { start , end } , [ ] string { } )
2020-07-29 20:53:04 +03:00
}
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.
2021-08-09 21:08:51 +03:00
func ( repo * Repository ) commitsBefore ( id SHA1 , limit int ) ( [ ] * Commit , error ) {
2022-02-06 22:01:47 +03:00
cmd := NewCommand ( repo . Ctx , "log" )
2017-12-11 05:23:34 +03:00
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
}
2021-08-09 21:08:51 +03:00
commits := make ( [ ] * Commit , 0 , len ( formattedLog ) )
for _ , commit := range formattedLog {
2017-12-11 05:23:34 +03:00
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
2021-08-09 21:08:51 +03:00
commits = append ( commits , 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
}
2021-08-09 21:08:51 +03:00
func ( repo * Repository ) getCommitsBefore ( id SHA1 ) ( [ ] * Commit , error ) {
2017-12-11 05:23:34 +03:00
return repo . commitsBefore ( id , 0 )
2016-11-04 01:16:01 +03:00
}
2021-08-09 21:08:51 +03:00
func ( repo * Repository ) getCommitsBeforeLimit ( id SHA1 , num int ) ( [ ] * Commit , 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-10-21 18:42:08 +03:00
if CheckGitVersionAtLeast ( "2.7.0" ) == nil {
2022-02-06 22:01:47 +03:00
stdout , err := NewCommand ( repo . Ctx , "for-each-ref" , "--count=" + strconv . Itoa ( limit ) , "--format=%(refname:strip=2)" , "--contains" , commit . ID . String ( ) , BranchPrefix ) . RunInDir ( repo . Path )
2018-05-27 21:47:34 +03:00
if err != nil {
return nil , err
}
branches := strings . Fields ( stdout )
return branches , nil
}
2022-02-06 22:01:47 +03:00
stdout , err := NewCommand ( repo . Ctx , "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
2021-08-09 21:08:51 +03:00
func ( repo * Repository ) GetCommitsFromIDs ( commitIDs [ ] string ) [ ] * Commit {
commits := make ( [ ] * Commit , 0 , len ( commitIDs ) )
2020-05-20 15:47:24 +03:00
for _ , commitID := range commitIDs {
commit , err := repo . GetCommit ( commitID )
if err == nil && commit != nil {
2021-08-09 21:08:51 +03:00
commits = append ( commits , commit )
2020-05-20 15:47:24 +03:00
}
}
return commits
}
2021-03-04 06:41:23 +03:00
// IsCommitInBranch check if the commit is on the branch
func ( repo * Repository ) IsCommitInBranch ( commitID , branch string ) ( r bool , err error ) {
2022-02-06 22:01:47 +03:00
stdout , err := NewCommand ( repo . Ctx , "branch" , "--contains" , commitID , branch ) . RunInDir ( repo . Path )
2021-03-04 06:41:23 +03:00
if err != nil {
return false , err
}
return len ( stdout ) > 0 , err
}