github.com/jenkins-x/jx/v2@v2.1.155/pkg/gits/git_fake.go (about)

     1  package gits
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  	"io"
     8  	"net/url"
     9  	"strings"
    10  	"time"
    11  
    12  	"github.com/jenkins-x/jx/v2/pkg/auth"
    13  	gitcfg "gopkg.in/src-d/go-git.v4/config"
    14  )
    15  
    16  // GitRemote a remote url
    17  type GitRemote struct {
    18  	Name string
    19  	URL  string
    20  }
    21  
    22  // GitTag git tag
    23  type GitTag struct {
    24  	Name    string
    25  	Message string
    26  }
    27  
    28  // GitFake provides a fake Gitter
    29  type GitFake struct {
    30  	GitRemotes     []GitRemote
    31  	Branches       []string
    32  	BranchesRemote []string
    33  	CurrentBranch  string
    34  	AccessTokenURL string
    35  	RepoInfo       GitRepository
    36  	Fork           bool
    37  	GitVersion     string
    38  	GitUser        GitUser
    39  	Commits        []GitCommit
    40  	Changes        bool
    41  	GitTags        []GitTag
    42  	Revision       string
    43  }
    44  
    45  // NewGitFake creates a new fake Gitter
    46  func NewGitFake() Gitter {
    47  	return &GitFake{}
    48  }
    49  
    50  func (g *GitFake) IsVersionControlled(dir string) (bool, error) {
    51  	return true, nil
    52  }
    53  
    54  func (g *GitFake) Config(dir string, args ...string) error {
    55  	return nil
    56  }
    57  
    58  // FindGitConfigDir finds the git config dir
    59  func (g *GitFake) FindGitConfigDir(dir string) (string, string, error) {
    60  	return dir, dir, nil
    61  }
    62  
    63  // PrintCreateRepositoryGenerateAccessToken prints the generate access token URL
    64  func (g *GitFake) PrintCreateRepositoryGenerateAccessToken(server *auth.AuthServer, username string, o io.Writer) {
    65  	fmt.Fprintf(o, "Access token URL: %s\n\n", g.AccessTokenURL)
    66  }
    67  
    68  // Status check the status
    69  func (g *GitFake) Status(dir string) error {
    70  	return nil
    71  }
    72  
    73  // Server returns the server URL
    74  func (g *GitFake) Server(dir string) (string, error) {
    75  	return g.RepoInfo.HostURL(), nil
    76  }
    77  
    78  // Info returns the git repo info
    79  func (g *GitFake) Info(dir string) (*GitRepository, error) {
    80  	return &g.RepoInfo, nil
    81  }
    82  
    83  // IsFork returns trie if this repo is a fork
    84  func (g *GitFake) IsFork(dir string) (bool, error) {
    85  	return g.Fork, nil
    86  }
    87  
    88  // Version returns the git version
    89  func (g *GitFake) Version() (string, error) {
    90  	return g.GitVersion, nil
    91  }
    92  
    93  // RepoName returns the repo name
    94  func (g *GitFake) RepoName(org string, repoName string) string {
    95  	if org != "" {
    96  		return org + "/" + repoName
    97  	}
    98  	return repoName
    99  }
   100  
   101  // Username returns the current user name
   102  func (g *GitFake) Username(dir string) (string, error) {
   103  	return g.GitUser.Name, nil
   104  }
   105  
   106  // SetUsername sets the username
   107  func (g *GitFake) SetUsername(dir string, username string) error {
   108  	g.GitUser.Name = username
   109  	return nil
   110  }
   111  
   112  // Email returns the current user git email address
   113  func (g *GitFake) Email(dir string) (string, error) {
   114  	return g.GitUser.Email, nil
   115  }
   116  
   117  // SetEmail sets the git email address
   118  func (g *GitFake) SetEmail(dir string, email string) error {
   119  	g.GitUser.Email = email
   120  	return nil
   121  }
   122  
   123  // GetAuthorEmailForCommit returns the author email for a commit
   124  func (g *GitFake) GetAuthorEmailForCommit(dir string, sha string) (string, error) {
   125  	for _, commit := range g.Commits {
   126  		if commit.SHA == sha {
   127  			return commit.Author.Email, nil
   128  		}
   129  	}
   130  	return "", errors.New("no commit found with given SHA")
   131  }
   132  
   133  // Init initialises git in a dir
   134  func (g *GitFake) Init(dir string) error {
   135  	return nil
   136  }
   137  
   138  // Clone clones the repo to the given dir
   139  func (g *GitFake) Clone(url string, directory string) error {
   140  	return nil
   141  }
   142  
   143  // ShallowCloneBranch shallow clone of a branch
   144  func (g *GitFake) ShallowCloneBranch(url string, branch string, directory string) error {
   145  	return nil
   146  }
   147  
   148  // ShallowClone shallow clones the repo at url from the specified commitish or pull request to a local master branch
   149  func (g *GitFake) ShallowClone(dir string, url string, commitish string, pullRequest string) error {
   150  	return nil
   151  }
   152  
   153  // Push performs a git push
   154  func (g *GitFake) Push(dir string, remote string, force bool, refspec ...string) error {
   155  	return nil
   156  }
   157  
   158  // PushMaster pushes to master
   159  func (g *GitFake) PushMaster(dir string) error {
   160  	return nil
   161  }
   162  
   163  // PushTag pushes a tag
   164  func (g *GitFake) PushTag(dir string, tag string) error {
   165  	return nil
   166  }
   167  
   168  // CreateAuthenticatedURL creates a Push URL
   169  func (g *GitFake) CreateAuthenticatedURL(cloneURL string, userAuth *auth.UserAuth) (string, error) {
   170  	u, err := url.Parse(cloneURL)
   171  	if err != nil {
   172  		return cloneURL, nil
   173  	}
   174  	if userAuth.Username != "" || userAuth.ApiToken != "" {
   175  		u.User = url.UserPassword(userAuth.Username, userAuth.ApiToken)
   176  		return u.String(), nil
   177  	}
   178  	return cloneURL, nil
   179  }
   180  
   181  // ForcePushBranch force push a branch
   182  func (g *GitFake) ForcePushBranch(dir string, localBranch string, remoteBranch string) error {
   183  	return nil
   184  }
   185  
   186  // CloneOrPull performs a clone or pull
   187  func (g *GitFake) CloneOrPull(url string, directory string) error {
   188  	return nil
   189  }
   190  
   191  // Pull git pulls
   192  func (g *GitFake) Pull(dir string) error {
   193  	return nil
   194  }
   195  
   196  // PullRemoteBranches pull remote branches
   197  func (g *GitFake) PullRemoteBranches(dir string) error {
   198  	return nil
   199  }
   200  
   201  // PullUpstream pulls upstream
   202  func (g *GitFake) PullUpstream(dir string) error {
   203  	return nil
   204  }
   205  
   206  // ResetToUpstream resets the given branch to the upstream version
   207  func (g *GitFake) ResetToUpstream(dir string, branch string) error {
   208  	return nil
   209  }
   210  
   211  // AddRemote adds a remote
   212  func (g *GitFake) AddRemote(dir string, name string, url string) error {
   213  	r := GitRemote{
   214  		Name: name,
   215  		URL:  url,
   216  	}
   217  	g.GitRemotes = append(g.GitRemotes, r)
   218  	return nil
   219  }
   220  
   221  func (g *GitFake) findRemote(name string) (*GitRemote, error) {
   222  	for _, remote := range g.GitRemotes {
   223  		if remote.Name == name {
   224  			return &remote, nil
   225  		}
   226  	}
   227  	return nil, fmt.Errorf("no remote found with name '%s'", name)
   228  }
   229  
   230  // SetRemoteURL sets a remote URL
   231  func (g *GitFake) SetRemoteURL(dir string, name string, gitURL string) error {
   232  	remote, err := g.findRemote(name)
   233  	if err != nil {
   234  		r := GitRemote{
   235  			Name: name,
   236  			URL:  gitURL,
   237  		}
   238  		g.GitRemotes = append(g.GitRemotes, r)
   239  		return nil
   240  	}
   241  	remote.URL = gitURL
   242  	return nil
   243  }
   244  
   245  // UpdateRemote updates a remote
   246  func (g *GitFake) UpdateRemote(dir string, url string) error {
   247  	return g.SetRemoteURL(dir, "origin", url)
   248  }
   249  
   250  // DeleteRemoteBranch deletes a remote branch
   251  func (g *GitFake) DeleteRemoteBranch(dir string, remoteName string, branch string) error {
   252  	return nil
   253  }
   254  
   255  // DeleteLocalBranch deletes a remote branch
   256  func (g *GitFake) DeleteLocalBranch(dir string, branch string) error {
   257  	return nil
   258  }
   259  
   260  // DiscoverRemoteGitURL discover the remote git URL
   261  func (g *GitFake) DiscoverRemoteGitURL(gitConf string) (string, error) {
   262  	origin, err := g.findRemote("origin")
   263  	if err != nil {
   264  		upstream, err := g.findRemote("upstream")
   265  		if err != nil {
   266  			return "", err
   267  		}
   268  		return upstream.URL, nil
   269  	}
   270  	return origin.URL, nil
   271  }
   272  
   273  // DiscoverUpstreamGitURL discover the upstream git URL
   274  func (g *GitFake) DiscoverUpstreamGitURL(gitConf string) (string, error) {
   275  	upstream, err := g.findRemote("upstream")
   276  	if err != nil {
   277  		origin, err := g.findRemote("origin")
   278  		if err != nil {
   279  			return "", err
   280  		}
   281  		return origin.URL, nil
   282  	}
   283  	return upstream.URL, nil
   284  }
   285  
   286  // RemoteBranches list the remote branches
   287  func (g *GitFake) RemoteBranches(dir string) ([]string, error) {
   288  	return g.BranchesRemote, nil
   289  }
   290  
   291  // RemoteBranchNames list the remote branch names
   292  func (g *GitFake) RemoteBranchNames(dir string, prefix string) ([]string, error) {
   293  	remoteBranches := []string{}
   294  	for _, remoteBranch := range g.BranchesRemote {
   295  		remoteBranch = strings.TrimSpace(strings.TrimPrefix(remoteBranch, "* "))
   296  		if prefix != "" {
   297  			remoteBranch = strings.TrimPrefix(remoteBranch, prefix)
   298  		}
   299  		remoteBranches = append(remoteBranches, remoteBranch)
   300  	}
   301  	return remoteBranches, nil
   302  }
   303  
   304  // RemoteMergedBranchNames list the remote branch names that are merged
   305  func (g *GitFake) RemoteMergedBranchNames(dir string, prefix string) ([]string, error) {
   306  	return g.RemoteBranchNames(dir, prefix)
   307  }
   308  
   309  // GetRemoteUrl get the remote URL
   310  func (g *GitFake) GetRemoteUrl(config *gitcfg.Config, name string) string {
   311  	if len(g.GitRemotes) == 0 {
   312  		return ""
   313  	}
   314  	return g.GitRemotes[0].URL
   315  }
   316  
   317  // Branch returns the current branch
   318  func (g *GitFake) Branch(dir string) (string, error) {
   319  	return g.CurrentBranch, nil
   320  }
   321  
   322  // CreateBranch creates a branch
   323  func (g *GitFake) CreateBranch(dir string, branch string) error {
   324  	g.Branches = append(g.Branches, branch)
   325  	return nil
   326  }
   327  
   328  // CheckoutRemoteBranch checkout remote branch
   329  func (g *GitFake) CheckoutRemoteBranch(dir string, branch string) error {
   330  	g.CurrentBranch = branch
   331  	g.Branches = append(g.Branches, branch)
   332  	return nil
   333  }
   334  
   335  // Checkout checkout the branch
   336  func (g *GitFake) Checkout(dir string, branch string) error {
   337  	g.CurrentBranch = branch
   338  	return nil
   339  }
   340  
   341  // CheckoutCommitFiles checks out the given files
   342  func (g *GitFake) CheckoutCommitFiles(dir string, commit string, files []string) error {
   343  	return nil
   344  }
   345  
   346  // CheckoutOrphan checkout the orphan
   347  func (g *GitFake) CheckoutOrphan(dir string, branch string) error {
   348  	g.CurrentBranch = branch
   349  	return nil
   350  }
   351  
   352  // ConvertToValidBranchName converts the name to a valid branch name
   353  func (g *GitFake) ConvertToValidBranchName(name string) string {
   354  	name = strings.TrimSuffix(name, "/")
   355  	name = strings.TrimSuffix(name, ".lock")
   356  	var buffer bytes.Buffer
   357  
   358  	last := ' '
   359  	for _, ch := range name {
   360  		if ch <= 32 {
   361  			ch = replaceInvalidBranchChars
   362  		}
   363  		switch ch {
   364  		case '~':
   365  			ch = replaceInvalidBranchChars
   366  		case '^':
   367  			ch = replaceInvalidBranchChars
   368  		case ':':
   369  			ch = replaceInvalidBranchChars
   370  		case ' ':
   371  			ch = replaceInvalidBranchChars
   372  		case '\n':
   373  			ch = replaceInvalidBranchChars
   374  		case '\r':
   375  			ch = replaceInvalidBranchChars
   376  		case '\t':
   377  			ch = replaceInvalidBranchChars
   378  		}
   379  		if ch != replaceInvalidBranchChars || last != replaceInvalidBranchChars {
   380  			buffer.WriteString(string(ch))
   381  		}
   382  		last = ch
   383  	}
   384  	return buffer.String()
   385  }
   386  
   387  // FetchBranch fetch branch
   388  func (g *GitFake) FetchBranch(dir string, repo string, refspec ...string) error {
   389  	return nil
   390  }
   391  
   392  // FetchBranch fetch branch
   393  func (g *GitFake) FetchBranchUnshallow(dir string, repo string, refspec ...string) error {
   394  	return nil
   395  }
   396  
   397  // FetchBranchShallow fetch branch
   398  func (g *GitFake) FetchBranchShallow(dir string, repo string, refspec ...string) error {
   399  	return nil
   400  }
   401  
   402  // StashPush git stash
   403  func (g *GitFake) StashPush(dir string) error {
   404  	return nil
   405  }
   406  
   407  // Remove a file from git
   408  func (g *GitFake) Remove(dir string, fileName string) error {
   409  	return nil
   410  }
   411  
   412  // RemoveForce remove force
   413  func (g *GitFake) RemoveForce(dir string, fileName string) error {
   414  	return nil
   415  }
   416  
   417  // CleanForce clean force
   418  func (g *GitFake) CleanForce(dir string, fileName string) error {
   419  	return nil
   420  }
   421  
   422  // Add add files to git
   423  func (g *GitFake) Add(dir string, args ...string) error {
   424  	return nil
   425  }
   426  
   427  // CommitIfChanges git commit if there are changes
   428  func (g *GitFake) CommitIfChanges(dir string, message string) error {
   429  	commit := GitCommit{
   430  		SHA:       "",
   431  		Message:   message,
   432  		Author:    &g.GitUser,
   433  		URL:       g.RepoInfo.URL,
   434  		Branch:    g.CurrentBranch,
   435  		Committer: &g.GitUser,
   436  	}
   437  	g.Commits = append(g.Commits, commit)
   438  	return nil
   439  }
   440  
   441  // CommitDir commit a dir
   442  func (g *GitFake) CommitDir(dir string, message string) error {
   443  	return g.CommitIfChanges(dir, message)
   444  }
   445  
   446  // AddCommit add a commit
   447  func (g *GitFake) AddCommit(dir string, msg string) error {
   448  	return g.CommitIfChanges(dir, msg)
   449  }
   450  
   451  // AddCommitFiles add files to a commit
   452  func (g *GitFake) AddCommitFiles(dir string, msg string, files []string) error {
   453  	return g.CommitIfChanges(dir, msg)
   454  }
   455  
   456  // HasChanges returns true if has changes in git
   457  func (g *GitFake) HasChanges(dir string) (bool, error) {
   458  	return g.Changes, nil
   459  }
   460  
   461  // HasFileChanged returns true if file has changes in git
   462  func (g *GitFake) HasFileChanged(dir string, fileName string) (bool, error) {
   463  	return g.Changes, nil
   464  }
   465  
   466  // GetCommitPointedToByPreviousTag returns the previous git tag SHA
   467  func (g *GitFake) GetCommitPointedToByPreviousTag(dir string) (string, string, error) {
   468  	len := len(g.Commits)
   469  	if len < 2 {
   470  		return "", "", errors.New("no previous commit found")
   471  	}
   472  	return g.Commits[len-2].SHA, "", nil
   473  }
   474  
   475  // GetCommitPointedToByLatestTag returns the current git tag sha
   476  func (g *GitFake) GetCommitPointedToByLatestTag(dir string) (string, string, error) {
   477  	len := len(g.Commits)
   478  	if len < 1 {
   479  		return "", "", errors.New("no current commit found")
   480  	}
   481  	return g.Commits[len-1].SHA, "", nil
   482  }
   483  
   484  // GetCommitPointedToByTag return the SHA of the commit pointed to by the given git tag
   485  func (g *GitFake) GetCommitPointedToByTag(dir string, tag string) (string, error) {
   486  	len := len(g.Commits)
   487  	if len < 1 {
   488  		return "", errors.New("no commit found")
   489  	}
   490  	return g.Commits[len-1].SHA, nil
   491  }
   492  
   493  // GetLatestCommitMessage returns the last commit message
   494  func (g *GitFake) GetLatestCommitMessage(dir string) (string, error) {
   495  	len := len(g.Commits)
   496  	if len < 1 {
   497  		return "", errors.New("no current commit found")
   498  	}
   499  	return g.Commits[len-1].Message, nil
   500  }
   501  
   502  // GetLatestCommitSha returns the sha of the last commit
   503  func (g *GitFake) GetLatestCommitSha(dir string) (string, error) {
   504  	len := len(g.Commits)
   505  	if len < 1 {
   506  		return "", errors.New("no commits found")
   507  	}
   508  	return g.Commits[len-1].SHA, nil
   509  }
   510  
   511  // GetFirstCommitSha returns the last commit message
   512  func (g *GitFake) GetFirstCommitSha(dir string) (string, error) {
   513  	len := len(g.Commits)
   514  	if len < 1 {
   515  		return "", errors.New("no commits found")
   516  	}
   517  	return g.Commits[0].SHA, nil
   518  }
   519  
   520  // FetchTags fetches tags
   521  func (g *GitFake) FetchTags(dir string) error {
   522  	return nil
   523  }
   524  
   525  // FetchRemoteTags fetches tags from a remote repository
   526  func (g *GitFake) FetchRemoteTags(dir string, repo string) error {
   527  	return nil
   528  }
   529  
   530  // Tags lists the tags
   531  func (g *GitFake) Tags(dir string) ([]string, error) {
   532  	tags := []string{}
   533  	for _, tag := range g.GitTags {
   534  		tags = append(tags, tag.Name)
   535  	}
   536  	return tags, nil
   537  }
   538  
   539  // FilterTags returns all tags from the repository at the given directory that match the filter
   540  func (g *GitFake) FilterTags(dir string, filter string) ([]string, error) {
   541  	return make([]string, 0), nil
   542  }
   543  
   544  // CreateTag creates a tag
   545  func (g *GitFake) CreateTag(dir string, tag string, msg string) error {
   546  	t := GitTag{
   547  		Name:    tag,
   548  		Message: msg,
   549  	}
   550  	g.GitTags = append(g.GitTags, t)
   551  	return nil
   552  }
   553  
   554  // GetRevisionBeforeDate get the revision before the date
   555  func (g *GitFake) GetRevisionBeforeDate(dir string, t time.Time) (string, error) {
   556  	return g.Revision, nil
   557  }
   558  
   559  // GetRevisionBeforeDateText get the revision before the date text
   560  func (g *GitFake) GetRevisionBeforeDateText(dir string, dateText string) (string, error) {
   561  	return g.Revision, nil
   562  }
   563  
   564  // Diff performs a git diff
   565  func (g *GitFake) Diff(dir string) (string, error) {
   566  	return "", nil
   567  }
   568  
   569  // ListChangedFilesFromBranch lists changes files between current checkout and a branch
   570  func (g *GitFake) ListChangedFilesFromBranch(dir string, branch string) (string, error) {
   571  	return "", nil
   572  }
   573  
   574  // LoadFileFromBranch returns a files's contents from a branch
   575  func (g *GitFake) LoadFileFromBranch(dir string, branch string, file string) (string, error) {
   576  	return "", nil
   577  }
   578  
   579  // FetchUnshallow deepens a shallow git clone
   580  func (g *GitFake) FetchUnshallow(dir string) error {
   581  	return nil
   582  }
   583  
   584  // IsShallow returns false
   585  func (g *GitFake) IsShallow(dir string) (bool, error) {
   586  	return false, nil
   587  }
   588  
   589  // CreateBranchFrom creates a new branch called branchName from startPoint
   590  func (g *GitFake) CreateBranchFrom(dir string, branchName string, startPoint string) error {
   591  	return g.CreateBranch(dir, branchName)
   592  }
   593  
   594  // Merge merges the commitish into the current branch
   595  func (g *GitFake) Merge(dir string, commitish string) error {
   596  	return nil
   597  }
   598  
   599  // Reset performs a git reset --hard back to the commitish specified
   600  func (g *GitFake) Reset(dir string, commitish string, hard bool) error {
   601  	return nil
   602  }
   603  
   604  // RemoteUpdate performs a git remote update
   605  func (g *GitFake) RemoteUpdate(dir string) error {
   606  	return nil
   607  }
   608  
   609  // LocalBranches will list all local branches
   610  func (g *GitFake) LocalBranches(dir string) ([]string, error) {
   611  	return g.Branches, nil
   612  }
   613  
   614  //MergeTheirs does nothing
   615  func (g *GitFake) MergeTheirs(dir string, commitish string) error {
   616  	return nil
   617  }
   618  
   619  //RebaseTheirs does nothing
   620  func (g *GitFake) RebaseTheirs(dir string, upstream string, branch string, skipEmpty bool) error {
   621  	return nil
   622  }
   623  
   624  // GetCommits returns the commits in a range, exclusive of startSha and inclusive of endSha
   625  func (g *GitFake) GetCommits(dir string, startSha string, endSha string) ([]GitCommit, error) {
   626  	return nil, nil
   627  }
   628  
   629  // RevParse runs git rev-parse on rev
   630  func (g *GitFake) RevParse(dir string, rev string) (string, error) {
   631  	return "", nil
   632  }
   633  
   634  // SetUpstreamTo will set the given branch to track the origin branch with the same name
   635  func (g *GitFake) SetUpstreamTo(dir string, branch string) error {
   636  	return nil
   637  }
   638  
   639  // Remotes will list the names of the remotes
   640  func (g *GitFake) Remotes(dir string) ([]string, error) {
   641  	answer := make([]string, 0)
   642  	for _, r := range g.GitRemotes {
   643  		answer = append(answer, r.Name)
   644  	}
   645  	return answer, nil
   646  }
   647  
   648  // StashPop does nothing
   649  func (g *GitFake) StashPop(dir string) error {
   650  	return nil
   651  }
   652  
   653  // CloneBare does nothing
   654  func (g *GitFake) CloneBare(dir string, url string) error {
   655  	return nil
   656  }
   657  
   658  // PushMirror does nothing
   659  func (g *GitFake) PushMirror(dir string, url string) error {
   660  	return nil
   661  }
   662  
   663  // GetCommitsNotOnAnyRemote returns a list of commits which are on branch but not present on a remote
   664  func (g *GitFake) GetCommitsNotOnAnyRemote(dir string, branch string) ([]GitCommit, error) {
   665  	return nil, nil
   666  }
   667  
   668  // CherryPick does a git cherry-pick of commit
   669  func (g *GitFake) CherryPick(dir string, commit string) error {
   670  	return nil
   671  }
   672  
   673  // CherryPickTheirs does a git cherry-pick of commit
   674  func (g *GitFake) CherryPickTheirs(dir string, commit string) error {
   675  	return nil
   676  }
   677  
   678  // CherryPickTheirsKeepRedundantCommits does a git cherry-pick of commit
   679  func (g *GitFake) CherryPickTheirsKeepRedundantCommits(dir string, commit string) error {
   680  	return nil
   681  }
   682  
   683  // Describe does a git describe of commitish, optionally adding the abbrev arg if not empty
   684  func (g *GitFake) Describe(dir string, contains bool, commitish string, abbrev string, fallback bool) (string, string, error) {
   685  	return "", "", nil
   686  }
   687  
   688  // IsAncestor checks if the possible ancestor commit-ish is an ancestor of the given commit-ish.
   689  func (g *GitFake) IsAncestor(dir string, possibleAncestor string, commitish string) (bool, error) {
   690  	return false, nil
   691  }
   692  
   693  // WriteRepoAttributes writes the given content to .git/info/attributes
   694  func (g *GitFake) WriteRepoAttributes(dir string, content string) error {
   695  	return nil
   696  }
   697  
   698  // ReadRepoAttributes reads the existing content, if any, in .git/info/attributes
   699  func (g *GitFake) ReadRepoAttributes(dir string) (string, error) {
   700  	return "", nil
   701  }