为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
慕仙森 2023-02-06 14:49:47
我想克隆一个特定的存储库,获取所有标签并遍历它们。对于每个标签,我想在根目录中检出一个特定文件 ( package.json )。如果不存在文件,它应该继续,否则它应该传递它以便我可以检查它。我从以下代码开始(我的第一个 Go 应用程序......)package mainimport (    "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)}有人知道如何通过给定标签尝试检查循环内的文件吗?
查看完整描述

1 回答

?
慕勒3428872

TA贡献1848条经验 获得超6个赞

如果您只需要文件内容,则无需“签出”任何内容;您可以直接从存储库中提取它。但首先要注意:我既不是经验丰富的 Go 程序员,也没有合作go-git过,所以可能有更优化的方法来做到这一点。

从标签开始,您可以:

  1. 获取标签指向的提交

  2. 获取提交指向的树

  3. 遍历树寻找package.json

  4. 如果找到它,请提取相应的 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软件包很有趣。


查看完整回答
反对 回复 2023-02-06
  • 1 回答
  • 0 关注
  • 100 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信