【问题标题】:Why does "git clone" not take a refspec?为什么“git clone”不采用 refspec?
【发布时间】:2014-01-05 19:58:54
【问题描述】:

似乎很多人已经将git clone 替换为组合git init && git fetch。这似乎很愚蠢,不幸的是,像 Jenkins 这样的工具不会为您做到这一点。那么为什么 git clone 不接受 refspec,就像 git fetch 一样呢?

具体来说,如果你想在 Jenkins 上运行 gerrit 触发的构建任务,你需要确保工作空间存在,否则 jenkins 将无法检查包含 gerrit 更改的修订。这是因为 gerrit 使用的 ref 路径不在 git clone 获取的路径中。

【问题讨论】:

  • 答案可能取决于人们为什么选择git init && git fetch 组合而不是git clone
  • 解释了问题中的用例。

标签: git jenkins gerrit


【解决方案1】:

请指定 gerrit 使用的 refname 是什么,克隆后缺少该名称。并且只需git clone --origin <gerrit-suitable-origin-name> 就可以解决问题吗?

现在是长版本。您的问题可能是两个问题的结合。为什么 git initgit remote addgit fetch 有优势,为什么在您最初克隆存储库时没有一种方法可以方便地过滤 refspec?

refspecs - 在 clone 初始化一个 repo 之后,该命令的 remote-refspec 行为是在 .gitconfig 中添加一个默认部分,该部分概述了 fetch 规范:

[remote "origin"]
url = ssh://host/your.git
fetch = +refs/heads/*:refs/remotes/origin/*

这些都是好的和健全的默认值,并且提供的 refspecs 旨在从远程获取所有内容。如果您需要更改 refspecs,您可以通过编辑文件手动完成。例如,

[remote "origin"]
url = ssh://host/your.git
fetch = +refs/heads/atari:refs/remotes/origin/atari
fetch = +refs/heads/vertigo:refs/remotes/origin/vertigo

编辑后,获取将仅涉及来自原始远程的atarivertigo 分支,例如,通常存在的master 以及远程可能存在的所有其他分支都将被忽略。这当然类似于在命令行上将 refspecs 提供给 git fetch 的选项。

总的来说,它只是没有必要,而且我认为这不是一个干净的设计,能够在 git clone 命令行上预先支持多个初始 refspecs,其唯一目的是将它们放在 .gitconfig 中。您甚至可以通过在 .gitconfig 文件上运行 git clone 然后运行 ​​sed 来编写相同的脚本。考虑到许多可能的 refspecs,在克隆时确定哪个是要签出的初始分支也是有问题的。

init over clone - 假设我们避免讨论更高级的git clone 设置,例如利用--reference,使用--depth 进行浅深度,或者创建裸回购,init- add-fetch 和 clone 对于您的日常流程来说非常小。

普通克隆只是复制现有存储库并将“源”设置为创建源的远程。这带来了一些小麻烦——“源”远程被强加给你,远程跟踪分支被创建,初始分支被设置,HEAD 被签出。但是,如果您从 git init 开始,您的控制力会稍强一些。您可以开始手动添加遥控器并获取特定分支而无需检查任何内容。

请注意,尽管git clone 行为的许多方面都可以通过命令行开关来控制——所以可能喜欢git init 的开发人员只是不知道它们?问题中没有足够的信息来决定。与替代方案相比,git clone 为您节省了一些输入,避免了宇宙的热死亡并设置了合理的上游默认值 - 例如拥有一个跟踪分支。我投票给克隆。

【讨论】:

  • 我想这是一个公平的答案,但与 git 中的许多事情一样,它会导致编码人员犯错误。我现在已经看到了几段使用以下错误逻辑的代码:if repo-exists then git fetch else git clone fi。正确的逻辑需要是if not repo-exists then git clone fi; git fetch。我认为 git 设计会导致此错误。哦,gerrit 使用 refs/changes/for//,所以它完全是非标准的,并且打破了 jenkins 关于克隆的假设,这就是提出这个问题的原因。
  • Git 为您提供了一套可供选择的选项,我认为这很好而且功能强大。所以我不同意 git 方式中的任何东西都会导致开发人员犯错误的事实。处理可变性和错误的一种方法是制定一个让每个人都遵循的程序,但 git 不能强制用户执行。
  • 对于 gerrit 部分,在 clone/init 之后,映射 fetch = +refs/changes/for/*:refs/remotes/origin/* (如我的回答中所述)对 jenkins 有帮助吗?它应该规范化名称。
  • 问题是 Jenkins 在克隆时不会运行 fetch。是的,很明显,我可以分叉 Jenkins 并通过修改代码让它做我想做的事情(或者希望有一天,有人会为我做这件事)。我目前的解决方法是简单地确保我希望 Jenkisn 使用的所有工作空间都预先填充了正确的克隆。
  • 在克隆期间支持硬链接是与 init-fetch-workflow 相比的一大优势(和差异)。
【解决方案2】:

git clone 可以通过通用--configoption获取refspec

在新创建的存储库中设置一个配置变量;这在存储库初始化后立即生效,但在获取远程历史记录或签出任何文件之前。 [...] 这使得安全,例如,向源远程添加额外的 fetch refspecs。

例子:

 git clone -c remote.origin.fetch=+refs/changes/*:refs/remotes/origin/changes/* https://gerrit.googlesource.com/git-repo

然而,我刚刚意识到这对git version 2.12.2.windows.2 并不像我预期的那样工作,因为在克隆时并没有真正获取changes 引用。它被正确添加到.git/config,但我需要在克隆后手动获取它通过

cd git-repo
git fetch

编辑:原来是known bug

【讨论】:

    猜你喜欢
    • 2017-11-04
    • 1970-01-01
    • 1970-01-01
    • 2019-08-16
    • 2013-09-03
    • 1970-01-01
    • 2014-07-03
    • 2016-10-10
    • 2021-07-10
    相关资源
    最近更新 更多