github.com/olli-ai/jx/v2@v2.0.400-0.20210921045218-14731b4dd448/pkg/gits/git_local.go (about)

     1  package gits
     2  
     3  import (
     4  	"io"
     5  	"time"
     6  
     7  	"github.com/olli-ai/jx/v2/pkg/auth"
     8  
     9  	gitcfg "gopkg.in/src-d/go-git.v4/config"
    10  )
    11  
    12  // GitLocal provides a semi-fake Gitter - local operations delegate to GitCLI but remote operations are delegated to
    13  // FakeGit. When using it in tests you must make sure you are operating on a temporary copy of a git repo NOT the
    14  // real one on your disk (as it will get changed!).
    15  // Faked out methods have the comment "Faked out"
    16  type GitLocal struct {
    17  	GitCLI  *GitCLI
    18  	GitFake *GitFake
    19  }
    20  
    21  // NewGitLocal creates a new GitLocal instance
    22  func NewGitLocal() *GitLocal {
    23  	return &GitLocal{
    24  		GitCLI:  NewGitCLI(),
    25  		GitFake: &GitFake{},
    26  	}
    27  }
    28  
    29  func (g *GitLocal) IsVersionControlled(dir string) (bool, error) {
    30  	return g.GitCLI.IsVersionControlled(dir)
    31  }
    32  
    33  // FindGitConfigDir tries to find the `.git` directory either in the current directory or in parent directories
    34  // Faked out
    35  func (g *GitLocal) FindGitConfigDir(dir string) (string, string, error) {
    36  	return g.GitCLI.FindGitConfigDir(dir)
    37  }
    38  
    39  func (g *GitLocal) Config(dir string, args ...string) error {
    40  	return g.GitCLI.Config(dir, args...)
    41  }
    42  
    43  // Clone clones the given git URL into the given directory
    44  // Faked out
    45  func (g *GitLocal) Clone(url string, dir string) error {
    46  	return g.GitFake.Clone(url, dir)
    47  }
    48  
    49  // ShallowCloneBranch clones a single branch of the given git URL into the given directory
    50  // Faked out
    51  func (g *GitLocal) ShallowCloneBranch(url string, branch string, dir string) error {
    52  	return g.GitFake.ShallowCloneBranch(url, branch, dir)
    53  }
    54  
    55  // ShallowClone shallow clones the repo at url from the specified commitish or pull request to a local master branch
    56  // Faked out
    57  func (g *GitLocal) ShallowClone(dir string, url string, commitish string, pullRequest string) error {
    58  	return g.GitFake.ShallowClone(dir, url, commitish, pullRequest)
    59  }
    60  
    61  // Pull pulls the Git repository in the given directory
    62  // Faked out
    63  func (g *GitLocal) Pull(dir string) error {
    64  	return g.GitFake.Pull(dir)
    65  }
    66  
    67  // PullRemoteBranches pulls the remote Git tags from the given given directory
    68  // Faked out
    69  func (g *GitLocal) PullRemoteBranches(dir string) error {
    70  	return g.GitFake.PullRemoteBranches(dir)
    71  }
    72  
    73  // DeleteRemoteBranch deletes the remote branch in the given given directory
    74  // Faked out
    75  func (g *GitLocal) DeleteRemoteBranch(dir string, remoteName string, branch string) error {
    76  	return g.GitFake.DeleteRemoteBranch(dir, remoteName, branch)
    77  }
    78  
    79  // DeleteLocalBranch deletes a remote branch
    80  func (g *GitLocal) DeleteLocalBranch(dir string, branch string) error {
    81  	return g.GitFake.DeleteLocalBranch(dir, branch)
    82  }
    83  
    84  // CloneOrPull clones  the given git URL or pull if it already exists
    85  // Faked out
    86  func (g *GitLocal) CloneOrPull(url string, dir string) error {
    87  	return g.GitFake.CloneOrPull(url, dir)
    88  }
    89  
    90  // PullUpstream pulls the remote upstream branch into master branch into the given directory
    91  // Faked out
    92  func (g *GitLocal) PullUpstream(dir string) error {
    93  	return g.GitFake.PullUpstream(dir)
    94  }
    95  
    96  // ResetToUpstream resets the given branch to the upstream version
    97  func (g *GitLocal) ResetToUpstream(dir string, branch string) error {
    98  	return g.GitFake.ResetToUpstream(dir, branch)
    99  }
   100  
   101  // AddRemote adds a remote repository at the given URL and with the given name
   102  func (g *GitLocal) AddRemote(dir string, name string, url string) error {
   103  	return g.GitCLI.AddRemote(dir, name, url)
   104  }
   105  
   106  // UpdateRemote updates the URL of the remote repository
   107  func (g *GitLocal) UpdateRemote(dir, url string) error {
   108  	return g.GitCLI.UpdateRemote(dir, url)
   109  }
   110  
   111  // StashPush stashes the current changes from the given directory
   112  func (g *GitLocal) StashPush(dir string) error {
   113  	return g.GitCLI.StashPush(dir)
   114  }
   115  
   116  // CheckoutRemoteBranch checks out the given remote tracking branch
   117  func (g *GitLocal) CheckoutRemoteBranch(dir string, branch string) error {
   118  	return g.GitCLI.CheckoutRemoteBranch(dir, branch)
   119  }
   120  
   121  // RemoteBranches returns the remote branches
   122  func (g *GitLocal) RemoteBranches(dir string) ([]string, error) {
   123  	return g.GitCLI.RemoteBranches(dir)
   124  }
   125  
   126  // Checkout checks out the given branch
   127  func (g *GitLocal) Checkout(dir string, branch string) error {
   128  	return g.GitCLI.Checkout(dir, branch)
   129  }
   130  
   131  // CheckoutCommitFiles checks out the given files
   132  func (g *GitLocal) CheckoutCommitFiles(dir string, commit string, files []string) error {
   133  	return g.GitCLI.CheckoutCommitFiles(dir, commit, files)
   134  }
   135  
   136  // CheckoutOrphan checks out the given branch as an orphan
   137  func (g *GitLocal) CheckoutOrphan(dir string, branch string) error {
   138  	return g.GitCLI.CheckoutOrphan(dir, branch)
   139  }
   140  
   141  // Init inits a git repository into the given directory
   142  func (g *GitLocal) Init(dir string) error {
   143  	return g.GitCLI.Init(dir)
   144  }
   145  
   146  // Remove removes the given file from a Git repository located at the given directory
   147  func (g *GitLocal) Remove(dir, fileName string) error {
   148  	return g.GitCLI.Remove(dir, fileName)
   149  }
   150  
   151  // RemoveForce removes the given file from a git repository located at the given directory
   152  func (g *GitLocal) RemoveForce(dir, fileName string) error {
   153  	return g.GitCLI.RemoveForce(dir, fileName)
   154  }
   155  
   156  // CleanForce cleans a git repository located at a given directory
   157  func (g *GitLocal) CleanForce(dir, fileName string) error {
   158  	return g.CleanForce(dir, fileName)
   159  }
   160  
   161  // Status returns the status of the git repository at the given directory
   162  func (g *GitLocal) Status(dir string) error {
   163  	return g.GitCLI.Status(dir)
   164  }
   165  
   166  // Branch returns the current branch of the repository located at the given directory
   167  func (g *GitLocal) Branch(dir string) (string, error) {
   168  	return g.GitCLI.Branch(dir)
   169  }
   170  
   171  // Push pushes the changes from the repository at the given directory
   172  // Faked out
   173  func (g *GitLocal) Push(dir string, remote string, force bool, refspec ...string) error {
   174  	return g.GitFake.Push(dir, "origin", false)
   175  }
   176  
   177  // ForcePushBranch does a force push of the local branch into the remote branch of the repository at the given directory
   178  // Faked out
   179  func (g *GitLocal) ForcePushBranch(dir string, localBranch string, remoteBranch string) error {
   180  	return g.GitFake.ForcePushBranch(dir, localBranch, remoteBranch)
   181  }
   182  
   183  // PushMaster pushes the master branch into the origin
   184  // Faked out
   185  func (g *GitLocal) PushMaster(dir string) error {
   186  	return g.GitFake.PushMaster(dir)
   187  }
   188  
   189  // PushTag pushes the given tag into the origin
   190  // Faked out
   191  func (g *GitLocal) PushTag(dir string, tag string) error {
   192  	return g.GitFake.PushTag(dir, tag)
   193  }
   194  
   195  // Add does a git add for all the given arguments
   196  func (g *GitLocal) Add(dir string, args ...string) error {
   197  	return g.GitCLI.Add(dir, args...)
   198  }
   199  
   200  // HasChanges indicates if there are any changes in the repository from the given directory
   201  func (g *GitLocal) HasChanges(dir string) (bool, error) {
   202  	return g.GitCLI.HasChanges(dir)
   203  }
   204  
   205  // HasFileChanged returns true if file has changes in git
   206  func (g *GitLocal) HasFileChanged(dir string, fileName string) (bool, error) {
   207  	return g.GitCLI.HasFileChanged(dir, fileName)
   208  }
   209  
   210  // CommitIfChanges does a commit if there are any changes in the repository at the given directory
   211  func (g *GitLocal) CommitIfChanges(dir string, message string) error {
   212  	return g.GitCLI.CommitIfChanges(dir, message)
   213  }
   214  
   215  // CommitDir commits all changes from the given directory
   216  func (g *GitLocal) CommitDir(dir string, message string) error {
   217  	return g.GitCLI.CommitDir(dir, message)
   218  }
   219  
   220  // AddCommit perform an add and commit of the changes from the repository at the given directory with the given messages
   221  func (g *GitLocal) AddCommit(dir string, msg string) error {
   222  	return g.GitCLI.AddCommit(dir, msg)
   223  }
   224  
   225  // CreateAuthenticatedURL creates the Git repository URL with the username and password encoded for HTTPS based URLs
   226  func (g *GitLocal) CreateAuthenticatedURL(cloneURL string, userAuth *auth.UserAuth) (string, error) {
   227  	return g.GitCLI.CreateAuthenticatedURL(cloneURL, userAuth)
   228  }
   229  
   230  // AddCommitFiles add files to a commit
   231  func (g *GitLocal) AddCommitFiles(dir string, msg string, files []string) error {
   232  	return g.GitCLI.AddCommitFiles(dir, msg, files)
   233  }
   234  
   235  // RepoName formats the repository names based on the organization
   236  func (g *GitLocal) RepoName(org, repoName string) string {
   237  	return g.GitCLI.RepoName(org, repoName)
   238  }
   239  
   240  // Server returns the Git server of the repository at the given directory
   241  func (g *GitLocal) Server(dir string) (string, error) {
   242  	return g.GitCLI.Server(dir)
   243  }
   244  
   245  // Info returns the git info of the repository at the given directory
   246  func (g *GitLocal) Info(dir string) (*GitRepository, error) {
   247  	return g.GitCLI.Info(dir)
   248  }
   249  
   250  // ConvertToValidBranchName converts the given branch name into a valid git branch string
   251  // replacing any dodgy characters
   252  func (g *GitLocal) ConvertToValidBranchName(name string) string {
   253  	return g.GitCLI.ConvertToValidBranchName(name)
   254  }
   255  
   256  // FetchBranch fetches a branch
   257  // Faked out
   258  func (g *GitLocal) FetchBranch(dir string, repo string, refspec ...string) error {
   259  	return g.GitFake.FetchBranch(dir, repo, refspec...)
   260  }
   261  
   262  // FetchBranchShallow fetches a branch
   263  // Faked out
   264  func (g *GitLocal) FetchBranchShallow(dir string, repo string, refspec ...string) error {
   265  	return g.GitFake.FetchBranchShallow(dir, repo, refspec...)
   266  }
   267  
   268  // FetchBranchUnshallow fetches a branch
   269  // Faked out
   270  func (g *GitLocal) FetchBranchUnshallow(dir string, repo string, refspec ...string) error {
   271  	return g.GitFake.FetchBranch(dir, repo, refspec...)
   272  }
   273  
   274  // GetAuthorEmailForCommit returns the author email from commit message with the given SHA
   275  func (g *GitLocal) GetAuthorEmailForCommit(dir string, sha string) (string, error) {
   276  	return g.GitCLI.GetAuthorEmailForCommit(dir, sha)
   277  }
   278  
   279  // SetRemoteURL sets the remote URL of the remote with the given name
   280  func (g *GitLocal) SetRemoteURL(dir string, name string, gitURL string) error {
   281  	return g.GitCLI.SetRemoteURL(dir, name, gitURL)
   282  }
   283  
   284  // DiscoverRemoteGitURL discovers the remote git URL from the given git configuration
   285  func (g *GitLocal) DiscoverRemoteGitURL(gitConf string) (string, error) {
   286  	return g.GitCLI.DiscoverRemoteGitURL(gitConf)
   287  }
   288  
   289  // DiscoverUpstreamGitURL discovers the upstream git URL from the given git configuration
   290  func (g *GitLocal) DiscoverUpstreamGitURL(gitConf string) (string, error) {
   291  	return g.GitCLI.DiscoverUpstreamGitURL(gitConf)
   292  }
   293  
   294  // GetRemoteUrl returns the remote URL from the given git config
   295  func (g *GitLocal) GetRemoteUrl(config *gitcfg.Config, name string) string {
   296  	return g.GitCLI.GetRemoteUrl(config, name)
   297  }
   298  
   299  // RemoteBranchNames returns all remote branch names with the given prefix
   300  func (g *GitLocal) RemoteBranchNames(dir string, prefix string) ([]string, error) {
   301  	return g.GitCLI.RemoteBranchNames(dir, prefix)
   302  }
   303  
   304  // RemoteMergedBranchNames returns all remote branch names with the given prefix
   305  func (g *GitLocal) RemoteMergedBranchNames(dir string, prefix string) ([]string, error) {
   306  	return g.GitCLI.RemoteMergedBranchNames(dir, prefix)
   307  }
   308  
   309  // GetCommitPointedToByPreviousTag returns the previous git tag from the repository at the given directory
   310  func (g *GitLocal) GetCommitPointedToByPreviousTag(dir string) (string, string, error) {
   311  	return g.GitCLI.GetCommitPointedToByPreviousTag(dir)
   312  }
   313  
   314  // GetRevisionBeforeDate returns the revision before the given date
   315  func (g *GitLocal) GetRevisionBeforeDate(dir string, t time.Time) (string, error) {
   316  	return g.GitCLI.GetRevisionBeforeDate(dir, t)
   317  }
   318  
   319  // GetRevisionBeforeDateText returns the revision before the given date in format "MonthName dayNumber year"
   320  func (g *GitLocal) GetRevisionBeforeDateText(dir string, dateText string) (string, error) {
   321  	return g.GitCLI.GetRevisionBeforeDateText(dir, dateText)
   322  }
   323  
   324  // GetCommitPointedToByLatestTag return the SHA of the current git tag from the repository at the given directory
   325  func (g *GitLocal) GetCommitPointedToByLatestTag(dir string) (string, string, error) {
   326  	return g.GitCLI.GetCommitPointedToByLatestTag(dir)
   327  }
   328  
   329  // GetCommitPointedToByTag return the SHA of the commit pointed to by the given git tag
   330  func (g *GitLocal) GetCommitPointedToByTag(dir string, tag string) (string, error) {
   331  	return g.GitCLI.GetCommitPointedToByTag(dir, tag)
   332  }
   333  
   334  // GetLatestCommitMessage returns the latest git commit message
   335  func (g *GitLocal) GetLatestCommitMessage(dir string) (string, error) {
   336  	return g.GitCLI.GetLatestCommitMessage(dir)
   337  }
   338  
   339  // FetchTags fetches all the tags
   340  // Faked out
   341  func (g *GitLocal) FetchTags(dir string) error {
   342  	return g.GitFake.FetchTags(dir)
   343  }
   344  
   345  // FetchRemoteTags fetches all the tags from a remote repository
   346  // Faked out
   347  func (g *GitLocal) FetchRemoteTags(dir string, repo string) error {
   348  	return g.GitFake.FetchRemoteTags(dir, repo)
   349  }
   350  
   351  // Tags returns all tags from the repository at the given directory
   352  func (g *GitLocal) Tags(dir string) ([]string, error) {
   353  	return g.GitCLI.Tags(dir)
   354  }
   355  
   356  // FilterTags returns all tags from the repository at the given directory that match the filter
   357  func (g *GitLocal) FilterTags(dir string, filter string) ([]string, error) {
   358  	return g.GitCLI.FilterTags(dir, filter)
   359  }
   360  
   361  // CreateTag creates a tag with the given name and message in the repository at the given directory
   362  func (g *GitLocal) CreateTag(dir string, tag string, msg string) error {
   363  	return g.GitCLI.CreateTag(dir, tag, msg)
   364  }
   365  
   366  // PrintCreateRepositoryGenerateAccessToken prints the access token URL of a Git repository
   367  func (g *GitLocal) PrintCreateRepositoryGenerateAccessToken(server *auth.AuthServer, username string, o io.Writer) {
   368  	g.GitCLI.PrintCreateRepositoryGenerateAccessToken(server, username, o)
   369  }
   370  
   371  // IsFork indicates if the repository at the given directory is a fork
   372  func (g *GitLocal) IsFork(dir string) (bool, error) {
   373  	return g.GitCLI.IsFork(dir)
   374  }
   375  
   376  // Version returns the git version
   377  func (g *GitLocal) Version() (string, error) {
   378  	return g.GitCLI.Version()
   379  }
   380  
   381  // Username return the username from the git configuration
   382  // Faked out
   383  func (g *GitLocal) Username(dir string) (string, error) {
   384  	// Use GitFake as this is a global setting
   385  	return g.GitFake.Username(dir)
   386  }
   387  
   388  // SetUsername sets the username in the git configuration
   389  // Faked out
   390  func (g *GitLocal) SetUsername(dir string, username string) error {
   391  	// Use GitFake as this is a global setting
   392  	return g.GitFake.SetUsername(dir, username)
   393  }
   394  
   395  // Email returns the email from the git configuration
   396  // Faked out
   397  func (g *GitLocal) Email(dir string) (string, error) {
   398  	// Use GitFake as this is a global setting
   399  	return g.GitFake.Email(dir)
   400  }
   401  
   402  // SetEmail sets the given email in the git configuration
   403  // Faked out
   404  func (g *GitLocal) SetEmail(dir string, email string) error {
   405  	// Use GitFake as this is a global setting
   406  	return g.GitFake.SetEmail(dir, email)
   407  }
   408  
   409  // CreateBranch creates a branch with the given name in the Git repository from the given directory
   410  func (g *GitLocal) CreateBranch(dir string, branch string) error {
   411  	return g.GitCLI.CreateBranch(dir, branch)
   412  }
   413  
   414  // Diff runs git diff
   415  func (g *GitLocal) Diff(dir string) (string, error) {
   416  	return g.GitCLI.Diff(dir)
   417  }
   418  
   419  // ListChangedFilesFromBranch lists files changed between branches
   420  func (g *GitLocal) ListChangedFilesFromBranch(dir string, branch string) (string, error) {
   421  	return g.GitCLI.ListChangedFilesFromBranch(dir, branch)
   422  }
   423  
   424  // LoadFileFromBranch returns a files's contents from a branch
   425  func (g *GitLocal) LoadFileFromBranch(dir string, branch string, file string) (string, error) {
   426  	return g.GitCLI.LoadFileFromBranch(dir, branch, file)
   427  }
   428  
   429  // FetchUnshallow does nothing
   430  // Faked out
   431  func (g *GitLocal) FetchUnshallow(dir string) error {
   432  	return g.GitFake.FetchUnshallow(dir)
   433  }
   434  
   435  // IsShallow runs git rev-parse --is-shalllow-repository in dir
   436  func (g *GitLocal) IsShallow(dir string) (bool, error) {
   437  	return g.GitCLI.IsShallow(dir)
   438  }
   439  
   440  // CreateBranchFrom creates a new branch called branchName from startPoint
   441  func (g *GitLocal) CreateBranchFrom(dir string, branchName string, startPoint string) error {
   442  	return g.GitCLI.CreateBranchFrom(dir, branchName, startPoint)
   443  }
   444  
   445  // Merge merges the commitish into the current branch
   446  func (g *GitLocal) Merge(dir string, commitish string) error {
   447  	return g.GitCLI.Merge(dir, commitish)
   448  }
   449  
   450  // GetLatestCommitSha returns the sha of the last commit
   451  func (g *GitLocal) GetLatestCommitSha(dir string) (string, error) {
   452  	return g.GitCLI.GetLatestCommitSha(dir)
   453  }
   454  
   455  // GetFirstCommitSha gets the first commit sha
   456  func (g *GitLocal) GetFirstCommitSha(dir string) (string, error) {
   457  	return g.GitCLI.GetFirstCommitSha(dir)
   458  }
   459  
   460  // Reset performs a git reset --hard back to the commitish specified
   461  func (g *GitLocal) Reset(dir string, commitish string, hard bool) error {
   462  	return g.GitCLI.Reset(dir, commitish, true)
   463  }
   464  
   465  // RemoteUpdate performs a git remote update
   466  // Faked out
   467  func (g *GitLocal) RemoteUpdate(dir string) error {
   468  	return g.GitFake.RemoteUpdate(dir)
   469  }
   470  
   471  // LocalBranches will list all local branches
   472  func (g *GitLocal) LocalBranches(dir string) ([]string, error) {
   473  	return g.GitCLI.LocalBranches(dir)
   474  }
   475  
   476  // MergeTheirs performs a cherry pick of commitish
   477  func (g *GitLocal) MergeTheirs(dir string, commitish string) error {
   478  	return g.GitCLI.MergeTheirs(dir, commitish)
   479  }
   480  
   481  // RebaseTheirs runs git rebase upstream branch
   482  func (g *GitLocal) RebaseTheirs(dir string, upstream string, branch string, skipEmpty bool) error {
   483  	return g.GitCLI.RebaseTheirs(dir, upstream, branch, false)
   484  }
   485  
   486  // GetCommits returns the commits in a range, exclusive of startSha and inclusive of endSha
   487  func (g *GitLocal) GetCommits(dir string, startSha string, endSha string) ([]GitCommit, error) {
   488  	return g.GitCLI.GetCommits(dir, startSha, endSha)
   489  }
   490  
   491  // RevParse runs git rev parse
   492  func (g *GitLocal) RevParse(dir string, rev string) (string, error) {
   493  	return g.GitCLI.RevParse(dir, rev)
   494  }
   495  
   496  // SetUpstreamTo will set the given branch to track the origin branch with the same name
   497  func (g *GitLocal) SetUpstreamTo(dir string, branch string) error {
   498  	return g.GitCLI.SetUpstreamTo(dir, branch)
   499  }
   500  
   501  // Remotes will list the names of the remotes
   502  func (g *GitLocal) Remotes(dir string) ([]string, error) {
   503  	return g.GitCLI.Remotes(dir)
   504  }
   505  
   506  // StashPop runs git stash pop
   507  func (g *GitLocal) StashPop(dir string) error {
   508  	return g.GitCLI.StashPop(dir)
   509  }
   510  
   511  // CloneBare does nothing
   512  func (g *GitLocal) CloneBare(dir string, url string) error {
   513  	return nil
   514  }
   515  
   516  // PushMirror does nothing
   517  func (g *GitLocal) PushMirror(dir string, url string) error {
   518  	return nil
   519  }
   520  
   521  // GetCommitsNotOnAnyRemote returns a list of commits which are on branch but not present on a remote
   522  func (g *GitLocal) GetCommitsNotOnAnyRemote(dir string, branch string) ([]GitCommit, error) {
   523  	return g.GitCLI.GetCommitsNotOnAnyRemote(dir, branch)
   524  }
   525  
   526  // CherryPick does a git cherry-pick of commit
   527  func (g *GitLocal) CherryPick(dir string, commit string) error {
   528  	return g.GitCLI.CherryPick(dir, commit)
   529  }
   530  
   531  // CherryPickTheirs does a git cherry-pick of commit
   532  func (g *GitLocal) CherryPickTheirs(dir string, commit string) error {
   533  	return g.GitCLI.CherryPickTheirs(dir, commit)
   534  }
   535  
   536  // CherryPickTheirsKeepRedundantCommits does a git cherry-pick of commit
   537  func (g *GitLocal) CherryPickTheirsKeepRedundantCommits(dir string, commit string) error {
   538  	return g.GitCLI.CherryPickTheirsKeepRedundantCommits(dir, commit)
   539  }
   540  
   541  // Describe does a git describe of commitish, optionally adding the abbrev arg if not empty
   542  func (g *GitLocal) Describe(dir string, contains bool, commitish string, abbrev string, fallback bool) (string, string, error) {
   543  	return g.GitCLI.Describe(dir, false, commitish, abbrev, fallback)
   544  }
   545  
   546  // IsAncestor checks if the possible ancestor commit-ish is an ancestor of the given commit-ish.
   547  func (g *GitLocal) IsAncestor(dir string, possibleAncestor string, commitish string) (bool, error) {
   548  	return g.GitCLI.IsAncestor(dir, possibleAncestor, commitish)
   549  }
   550  
   551  // WriteRepoAttributes writes the given content to .git/info/attributes
   552  func (g *GitLocal) WriteRepoAttributes(dir string, content string) error {
   553  	return g.GitCLI.WriteRepoAttributes(dir, content)
   554  }
   555  
   556  // ReadRepoAttributes reads the existing content, if any, in .git/info/attributes
   557  func (g *GitLocal) ReadRepoAttributes(dir string) (string, error) {
   558  	return g.GitCLI.ReadRepoAttributes(dir)
   559  }