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

go-git:创建本地分支的正确方法,模拟“git分支<分支名称>”的行为?

go-git:创建本地分支的正确方法,模拟“git分支<分支名称>”的行为?

Go
潇湘沐 2022-08-24 17:00:59
正如标题所示,我正在尝试弄清楚如何以与Git CLI命令相同的结果的方式创建本地分支。go-gitgit branch <branchname>据我所知,(没有明确的论据)做了两件事:git branch <branchname><start-point>创建以指向当前提交.git/refs/heads/<branchname>HEAD用一行记录分支的创建。.git/logs/refs/heads/<branchname>它可能会做得更多,但我知道这两件事肯定是肯定的。(如果您知道更多的东西,请分享!接下来的大部分内容都记录了我在研究我的选择时的发现之旅,我想我现在可能已经掌握了上面的#1。但是,对于#2,我开始认为我可能是SOL,至少使用.go-git第一个想法:Repository.CreateBranch我最初天真的想法是打电话,并且有一个类似的SO问题的答案(“如何使用go-git签出一个新的本地分支?”),这似乎可以证明这个想法是可信的。但是一旦我开始研究细节,事情就变得非常混乱。Repository.CreateBranch首先,采用 as 输入(为什么?),并且似乎还修改了存储库的文件(再次,为什么?)。我已经验证了该命令没有触及存储库的配置,并且当我调用该命令时,我当然不需要提及有关配置的任何内容。Repository.CreateBranchconfig.Config.git/configgit branch <branchname>其次,我上面链接的SO答案引用了 中的代码,该代码执行以下操作:go-gitrepository_test.gor, _ := Init(memory.NewStorage(), nil) // init repotestBranch := &config.Branch{    Name:   "foo",    Remote: "origin",    Merge:  "refs/heads/foo",}err := r.CreateBranch(testBranch)但的定义是:config.Branchtype Branch struct {    // Name of branch    Name string    // Remote name of remote to track    Remote string    // Merge is the local refspec for the branch <=== ???    Merge plumbing.ReferenceName    ...}并且不是 refspec(因为 refspec 有一个分离它的和组件)。"refs/heads/foo":srcdst经过大量的挠头和代码阅读,我得出了(非常)初步的结论,即注释中的“refspec”一词一定是错误的,它应该只是“ref”。但我完全不确定这一点:如果我是对的,那么为什么这个字段被命名而不是仅仅命名?MergeRef另一个初步的结论是,这并不是为了创建一个纯粹的本地分支,而是为了创建一个本地分支,它与远程分支有某种关系 - 例如,如果我从远程数据库中提取其他人的分支。Repository.CreateBranch实际上,在重读 Repository.CreateBranch 方法时,我根本不相信它真的创建了一个分支(也就是说,它创建了 )。除非我错过了一些东西(完全有可能),否则它似乎所做的就是在 中创建一个部分。但是,如果这是真的,为什么它是一种存储库的方法呢?为什么它不是一种方法?.git/refs/heads/<branchname>[branch "<name>"].git/configconfig.Config同样,还有一个相关的函数:func (r *Repository) Branch(name string) (*config.Branch, error)只会从配置中返回分支信息。然而,文档中的下一个函数是:Repositoryfunc (r *Repository) Branches() (storer.ReferenceIter, error) 它确实返回了 中所有条目的迭代器。.git/refs/heads/这是非常令人困惑的,文档(就像它一样)无济于事。无论如何,除非有人能说服我,否则我很确定这对实际创建分支没有多大帮助。CreateBranch
查看完整描述

2 回答

?
万千封印

TA贡献1891条经验 获得超3个赞

首先,我没有足够的声誉来评论Pedro的答案,但他的方法在阶段失败了,因为实际上没有在存储上创建分支(从未调用存储库)。CheckoutStorer


其次,这是我第一次听说dir,所以不,不会为该dir中的分支创建记录。.git/loggit branch


这就引出了实际的解决方案,即作为 go-git 存储库分支的示例提供的解决方案。


要创建分支(脱离 HEAD):

Info("git branch test")

branchName := plumbing.NewBranchReferenceName("test")

headRef, err := r.Head()

CheckIfError(err)

ref := plumbing.NewHashReference(branchName, headRef.Hash())

err = r.Storer.SetReference(ref)

CheckIfError(err)

签出分支

Info("git checkout test")

w, err := r.Worktree()

CheckIfError(err)

err = w.Checkout(&git.CheckoutOptions{Branch: ref.Name()})

CheckIfError(err)

但是,这样,在 中没有此分支的配置,因此应该有对函数的调用,但这确实是可笑的不直观的。.git/configrepo.Branch


查看完整回答
反对 回复 2022-08-24
?
GCT1015

TA贡献1827条经验 获得超4个赞

我做到了:


创建对新分支的本地引用


branchName := "new-branch"

localRef := plumbing.NewBranchReferenceName(branchName)

创建分支


opts := &gitConfig.Branch{

    Name:   branchName,

    Remote: "origin",

    Merge:  localRef,

}


if err := repo.CreateBranch(opts); err != nil {

    return err

}

如果您确实需要更改为该分支...只是做一个结帐(不记得它是否实际更改为创建的分支与创建)


获取工作树


w, err := repo.Worktree()

if err != nil {

    return rest.InternalServerError(err.Error())

}

收款处


if err := w.Checkout(&git.CheckoutOptions{Branch: plumbing.ReferenceName(localRef.String())}); err != nil {

    return nil

}

如果要跟踪远程分支


创建远程引用


remoteRef := plumbing.NewRemoteReferenceName("origin", branchName)

跟踪远程


newReference := plumbing.NewSymbolicReference(localRef, remoteRef)


if err := repo.Storer.SetReference(newReference); err != nil {

   return err

}


查看完整回答
反对 回复 2022-08-24
  • 2 回答
  • 0 关注
  • 252 浏览
慕课专栏
更多

添加回答

举报

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