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

2024-01-07

正如标题所示,我试图弄清楚如何使用创建本地分支go-git与 Git CLI 命令给出相同结果的方式git branch <branchname>.

据我所知,git branch <branchname>(没有明确的<start-point>论证)做了两件事:

  1. Creates .git/refs/heads/<branchname>指向当前的HEAD commit
  2. Creates .git/logs/refs/heads/<branchname>用一行记录分支的创建。

它可能会做更多的事情,但我知道它肯定会做这两件事。 (如果你知道更多它的作用,请分享!)

接下来的大部分内容记录了我在研究我的选择时的发现之旅,我想我现在可能已经掌握了上面的#1。不过,对于#2,我开始认为我可能是 SOL,至少使用go-git.

第一个想法:Repository.CreateBranch

我最初天真的想法就是打电话Repository.CreateBranch,并且有一个answer https://stackoverflow.com/a/64131712/1337498类似的问题(“How to checkout a new local Branch using go-git?”)似乎证实了这个想法。但一旦我开始研究细节,事情就变得very令人困惑。

First, Repository.CreateBranch需要一个config.Config作为输入(为什么?),并且似乎还修改了存储库的.git/config文件(再次,为什么?)。我已经验证过git branch <branchname>命令不会触及存储库的配置,当我调用该命令时,我当然不需要提及任何有关配置的内容。

其次,我上面链接的SO答案引用了代码go-git's repository_test.go执行以下操作:

r, _ := Init(memory.NewStorage(), nil) // init repo
testBranch := &config.Branch{
    Name:   "foo",
    Remote: "origin",
    Merge:  "refs/heads/foo",
}
err := r.CreateBranch(testBranch)

但定义config.Branch is:

type 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
    ...
}

and "refs/heads/foo" 不是参考规范(因为 refspec 有一个:分离其src and dst成分)。

经过大量的绞尽脑汁和代码阅读之后,我得出了(非常)初步的结论:注释中的“refspec”一词一定是错误的,而应该只是“ref”。但我对此完全不确定:如果我是对的,那么为什么这个字段被命名为Merge而不仅仅是Ref?

另一个初步的结论是Repository.CreateBranch并不是真正用于创建纯粹的本地分支,而是用于创建与远程分支存在某种关系的本地分支 - 例如,如果我从远程拉取其他人的分支。

其实,重读一遍存储库.CreateBranch https://github.com/go-git/go-git/blob/a50d22d149e9bb5f0b64f5d4c4a8e2cd0a2a51a4/repository.go#L638-L654方法,我一点也不相信它真的创建一个分支(也就是说,它创造了.git/refs/heads/<branchname>)。除非我错过了一些东西(完全有可能),否则它所做的似乎就是创建一个[branch "<name>"] section in .git/config。但如果这是真的的话为什么它是一种方法Repository at all?为什么它不是一种方法config.Config?

同样,还有一个相关的函数:

func (r *Repository) Branch(name string) (*config.Branch, error)

只会从配置返回分支信息。然而,文档中的下一个函数Repository is:

func (r *Repository) Branches() (storer.ReferenceIter, error) 

它确实返回了所有条目的迭代器.git/refs/heads/.

这是非常令人困惑的,而且文档(就像它本身一样)没有任何帮助。无论如何,除非有人能说服我,否则我很确定CreateBranch实际上不会有太大帮助创建分支.

工作树.结帐???

一些额外的网络搜索发现了旧版本中的这两个问题d-src/go-git repo:

  • 创建分支的示例#551 https://github.com/src-d/go-git/issues/551
  • 创建分支?第713章 https://github.com/src-d/go-git/issues/713

这两篇文章都提出了创建本地分支的基本方法:

wt, err := repo.Worktree()                                                                                                                                                                                                                           
if err != nil {                                                                                                                                                                                                                                  
        // deal with it                                                                                                                                                                                                                                   
}                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
err = w.Checkout(&git.CheckoutOptions{                                                                                                                                                                                                           
        Create: true,                                                                                                                                                                                                                            
        Force:  false,                                                                                                                                                                                                                           
        Branch: plumbing.ReferenceName("refs/heads/<branchname>"),                                                                                                                                                                                
})

除了这个事实之外退房新的分支机构,其中git branch <branchname>不这样做,它也无法创建.git/logs/refs/heads/<branchname>.

另外——作为一个潜在的very令人讨厌的惊喜——它清除工作树中所有未跟踪的文件。默认情况下,git checkout keeps对工作树中的文件进行本地修改,但在go-git你需要明确指定Keep: true,即使您已指定Force: false.

绝对违反了“最小惊讶原则”。值得庆幸的是,在我测试过的本地存储库中,它们都是旧的编辑器备份文件或我很久以前就放弃的旧项目的片段。

存储器.ReferenceStorer

事情发生时,其中一位go-git作者/维护者回应了第二个问题,并建议:

为了独立于工作树创建和删除引用,您应该使用storer.ReferenceStorer.

请看一下分支示例:https://github.com/src-d/go-git/blob/master/_examples/branch/main.go https://github.com/src-d/go-git/blob/master/_examples/branch/main.go

这很好而且很简单,但它只解决了分支引用的创建问题。

我在以下位置找到的所有出现的“log”一词go-git源代码似乎参考commit日志,不ref日志。鉴于引用日志条目看起来与.git树,我想需要一种不同类型的存储器来创建/更新它们——并且现有的存储器看起来(对我来说)都不是这样做的。

So...

关于如何获得适当的参考日志以配合参考有什么建议吗?

(或者,也许我误解得很严重,而且is一些创建分支的方法go-git,除了我上面列出的那些之外,这将满足我的要求。)


首先,我没有足够的声誉来评论佩德罗的回答,但他的方法在Checkout阶段,因为实际上没有在存储上创建分支(存储库的Storer从未被调用)。

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

这引导我找到实际的解决方案,这是作为分支示例提供的解决方案go-git 仓库 https://github.com/go-git/go-git/blob/master/_examples/branch/main.go.

  • 创建一个分支(脱离 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/config,所以应该调用repo.Branch函数,但这确实很滑稽且不直观。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

go-git:创建本地分支的正确方法,模拟“git分支 ”的行为? 的相关文章

  • 命令来确定当前 HEAD 的上游引用?

    我正在寻找我所希望的简单的一行命令确定当前签出分支的正确上游引用 本质上就像是 git branch remote HEAD 如果有效 会将符号模式 HEAD 转换为当前分支名称 然后选项 remote然后将其更改为远程跟踪分支的引用 但它
  • 如果文件已在服务器上,请避免使用 git-ftp 上传

    假设我有应用程序的本地副本 我将其推送到 github 然后使用 git ftp 将任何更改上传到我的服务器 我首先会使用 git ftp init u
  • Git 中的专有+开源设置? (例如铬/铬)

    您将如何设置一个拥有专有版本和开源版本 例如 Chrome 和 Chromium 的代码存储库 对于 Git 您会使用两个分支还是两个存储库 您如何使 私有 版本与开源版本保持同步 如果是我 我会有两个存储库 这样 您就可以对每个版本拥有不
  • 有没有办法列出Git中未修改的文件?

    我从另一个来源以 tarball 的形式获取了一些更改 我想知道哪些文件没有更改 目标是 Git 克隆 因此可以轻松查看新增内容和更改内容 有人知道如何获取未更改内容的列表 不包括未跟踪的内容 吗 编辑 换句话说 我希望利用 Git 来查找
  • Go io.Pipe 的缓冲版本

    有缓冲版本吗io Pipe https golang org pkg io Pipe 在标准库或第三方库中 在我推出自己的库之前 上下文 我正在尝试使用这个解决方案 https stackoverflow com a 36229262 15
  • 使用 GIT 自动增加 AssemblyFileVersion

    好吧 我知道这可能不是传统的 但除此之外 我使用 AssemblyFileVersion 作为我的 构建名称 字符串 它的格式如下 File Version information for an assembly consists of t
  • GAE Go — 如何对不存在的实体键使用 GetMulti?

    我发现自己需要做一个GetMulti使用键数组进行操作 其中某些实体存在 但有些实体不存在 我当前的代码 如下 返回错误 datastore no such entity err datastore GetMulti c keys info
  • 具有单独 work_tree 的 Git 子模块

    我按照本页上的教程使通过 Git 部署我的网站变得简单 http toroid org ams git website howto http toroid org ams git website howto 到目前为止一切都很好 但是我最近
  • git subtree pull -P 不管 总是合并冲突

    问题 即使我没有进行任何更改 每次尝试拉入子树时 我都会遇到合并冲突 我在做什么 In 子树仓库 Make some changes git commit am Changes made git push origin master In
  • DVCS命令的统一

    当处理多个 开源 项目时 多个版本控制系统开始出现问题 虽然它们共享共同的操作 但我经常在输入时犯错误hg add反而git add 我记得前段时间看到过一个项目 通过提供基本命令以统一的方式访问不同的源代码控制软件提交 ci add等在外
  • git 预提交钩子格式代码 - Intellij/Android Studio

    本要点展示了如何在预提交时使用 Eclipse 格式化程序自动格式化 Java 代码 Source https gist github com ktoso 708972 https gist github com ktoso 708972
  • 鸭子在 Go 中打字

    我想写一个Join函数接受任意对象String 方法 package main import fmt strings type myint int func i myint String string return fmt Sprintf
  • 相当于“svn update -r”的 git 是什么?

    我是最近的 git 转换者 能够使用 git svn 将我的分支保留在本地而不干扰 svn 服务器真是太棒了 最新版本的代码中存在一个错误 我想确定一个它起作用的时间 以便我可以使用 git bisect 我找不到正确的命令来及时返回 谢谢
  • 运行“git apply”时出错

    当我尝试时 您能否告诉我如何解决 补丁不适用 错误 git 应用补丁 git apply 0001 my patch error patch failed test xml 114 error text xml patch does not
  • 无法使用 git 配置文件进行 ssh

    我知道它被问了很多次 但我无法得到我的问题的答案 我正在尝试使用配置文件 ssh 到系统 配置文件是 Host qa HostName 10 218 70 345 User user IdentityFile C Users bean ss
  • refname 不明确且拉取失败

    我运行了以下命令 因为我想将生产分支移回而不必先签出 git branch f production HEAD 1 现在 当我检查生产时 我收到以下警告 warning refname production is ambiguous 然后我
  • IntelliJ:查看本地和 git 提交/分支之间所有已更改文件的差异

    使用 IntelliJ 的 diff 查看器是检查代码的一种非常好的方法 因为您可以使用 IntelliJ 代码编辑器的所有功能 重构 完成等 在本地版本中进行更改 不幸的是 我还没有弄清楚当你在 IntelliJ 中进行代码审查时如何做最
  • 如何使用交互式变基将提交编辑为未提交?

    我想使用交互式变基来编辑以前的提交 但是当我进入该提交的编辑模式时 所有文件都已提交 我知道我可以进行更改并修改提交 但我希望所有更改最初都未提交 暂存或以其他方式 这样我就可以对其进行编辑 就像在最初提交之前一样 这可能吗 Imagine
  • 如何从 android.googlesource.com 或 github.com 下载单个目录?

    我想下载 https android googlesource com platform frameworks base git master tools aapt https android googlesource com platfo
  • git diff - 只显示哪些目录发生了变化

    有没有办法只列出已更改的目录 如果我在 git root 的话 project 我更改的文件是 project subtool file1 project subtool file2 project subtool3 file1 我只是想

随机推荐