如何签出特定的单个文件以使用 go-git 检查它?

我想克隆一个特定的存储库,获取所有标签并遍历它们。对于每个标签,我想在根目录中检出一个特定文件 ( package.json )。如果不存在文件,它应该继续,否则它应该传递它以便我可以检查它。


我从以下代码开始(我的第一个 Go 应用程序......)


package main


import (

    "fmt"

    "github.com/go-git/go-billy/v5"

    "github.com/go-git/go-billy/v5/memfs"

    "github.com/go-git/go-git/v5"

    "github.com/go-git/go-git/v5/plumbing"

    "github.com/go-git/go-git/v5/plumbing/transport/http"

    "github.com/go-git/go-git/v5/storage/memory"

    "os"

)


func main() {

    authentication := &http.BasicAuth{

        Username: "me",

        Password: "my-key",

    }

    repositoryUrl := "my-repo-url"

    inMemoryStorage := memory.NewStorage()

    inMemoryFilesystem := memfs.New()


    repository, err := cloneRepository(repositoryUrl, authentication, inMemoryStorage, inMemoryFilesystem)


    if err != nil {

        handleError(err)

    }


    tagsIterator, err := repository.Tags()


    if err != nil {

        handleError(err)

    }


    err = tagsIterator.ForEach(func(tag *plumbing.Reference) error {

        fmt.Println(tag.Name().Short()) // for debugging purposes


        // checkout package.json file ( at root ) via tag


        return nil

    })


    if err != nil {

        handleError(err)

    }

}


func cloneRepository(repositoryUrl string, authentication *http.BasicAuth, inMemoryStorage *memory.Storage, inMemoryFilesystem billy.Filesystem) (*git.Repository, error) {

    return git.Clone(inMemoryStorage, inMemoryFilesystem, &git.CloneOptions{

        URL:  repositoryUrl,

        Auth: authentication,

    })

}


func handleError(err error) {

    fmt.Println(err)

    os.Exit(1)

}

有人知道如何通过给定标签尝试检查循环内的文件吗?


慕仙森
浏览 101回答 1
1回答

慕勒3428872

如果您只需要文件内容,则无需“签出”任何内容;您可以直接从存储库中提取它。但首先要注意:我既不是经验丰富的 Go 程序员,也没有合作go-git过,所以可能有更优化的方法来做到这一点。从标签开始,您可以:获取标签指向的提交获取提交指向的树遍历树寻找package.json如果找到它,请提取相应的 blob。现在你有了你的内容!上面的步骤可能看起来像这样:func getFileFromRef(repository *git.Repository, ref *plumbing.Hash, filename string) (bool, []byte, error) {    // Get the commit object corresponding to ref    commit, err := repository.CommitObject(*ref)    if err != nil {        return false, nil, err    }    // Get the tree object from the commit    tree, err := repository.TreeObject(commit.TreeHash)    if err != nil {        return false, nil, err    }    // Iterate through tree entries    for _, entry := range tree.Entries {        // If we find the target file...        if entry.Name == filename {            // Get the blob object from the repository            blob, err := repository.BlobObject(entry.Hash)            if err != nil {                return false, nil, err            }            // Ask for a Reader            reader, err := blob.Reader()            if err != nil {                return false, nil, err            }            // Allocate a slice for the data...            data := make([]byte, blob.Size)            // ...and read it in.            n, err := reader.Read(data)            if err != nil {                return false, nil, err            }            // Double check that we read as many bytes as            // we expected            if int64(n) != blob.Size {                return true, nil, fmt.Errorf("wrong size")            }            return true, data, nil        }    }    return false, nil, nil}上面的函数将在给定提交引用filename的情况下在存储库的顶层查找(正如所写的那样,它不会遍历子目录)。您需要修改函数中的tagsIterator.ForEach循环才能执行以下操作:main    err = tagsIterator.ForEach(func(tag *plumbing.Reference) error {        // Get the commit to which the tag refers. We need this to        // resolve annotated tags.        ref, err := repository.ResolveRevision(plumbing.Revision(tag.Hash().String()))        if err != nil {            handleError(err)        }        found, content, err := getFileFromRef(repository, ref, "package.json")        if found && err == nil {            fmt.Printf("found \"package.json\" in tag %s\n", tag.Name().Short())            fmt.Println(string(content))        }        return nil    })我不知道这是否是您要找的东西,但了解该go-git软件包很有趣。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go