git - 克隆完成后使用 GIT 获取另一个分支 --depth 1
问题描述
我最近被介绍给 git clone 的 --depth 1。显然,这并没有得到所有的历史记录,而且速度要快得多。我用了:
git clone --depth 1 -b 开发https://github.MyCompany.com/CoolProduct/CoolProduct.git
这让我可以玩、修改和分支开发分支。
但是,现在我想查看我尝试过的另一个分支“BillsFeature”:git checkout BillsFeature 并出现错误:pathspec 'BillsFeature' 与 git 已知的任何文件都不匹配
这对我来说有点道理。大概是因为我使用了--depth 1,所以我没有拉下分支名称。我如何获得另一个分支? 我也不需要 BillsFeature 的历史。我应该说我尝试过: git fetch --depth 1 origin BillsFeature 并且似乎发生了一些事情。但是,当我执行 git status 时,我得到了:
在分支开发您的分支是最新的'origin/develop'。
没什么可提交的,工作树干净
谢谢,戴夫
解决方案
这里问题的根源在于git clone
's--depth
选项也打开了--single-branch
。要在克隆时打败它,请使用--no-single-branch
. 之后要打败它,请参阅如何“撤消” --single -branch 克隆?
请注意,在对您拥有的克隆进行去单分支后,您将不得不git fetch --depth 1
再次运行。这将从您克隆的存储库中检索其余的分支名称——所有这些都成为远程跟踪名称;请参阅下面的详细信息 - 并允许您git checkout
在每个此类名称上运行以创建具有相同名称的本地分支。您还可以使用git remote set-branches --add
将个人名称添加到现有遥控器;再次,您将需要另一个git fetch --depth
.
可选阅读:详细信息,或者,为什么上述工作
Git 存储库——从技术上讲,是一个非裸存储库——实际上由以下三个部分组成:
- 一对数据库,如下所述;
- 一个索引,Git 通过它知道要提交哪些文件,即要跟踪哪些文件,尽管索引不仅仅是一个文件列表;和
- 您可以在其中使用和修改文件的工作树或工作树。这些文件实际上是你的,实际上根本不在 Git 中。Git 内部的文件,在主数据库中,都是只读的,并且是一种特殊的压缩和重复数据删除形式,只有 Git 本身可以使用。
当你运行时git clone
,你让你的 Git 复制主数据库——一个保存所有提交和文件等的数据库——或多或少批发,但让它读取另一个数据库,解析它并理解它并写入你的克隆,不同的数据库。
该--depth
标志会影响主数据库,因此您不会大量复制它。--single-branch
正如我们所指出的,该标志--depth
会自动打开 - 会影响辅助数据库。在我们继续之前,让我们给这两个数据库起个名字,这样我们就不会一直提到一些尴尬的短语,比如“第一部分的派对”:
我一直称之为“主数据库”的东西是 Git 的对象存储。这是一个简单的键值对数据库,其中键是哈希 ID,值是 Git 的提交和其他内部对象。1 通常这是 Git 存储库的最大部分。2
第二个数据库也是一个简单的键值存储,键是名称——包括分支和标签名称,但也包括几乎所有 Git 的其他名称3——值是哈希 ID。每个名称只存储一个哈希 ID,因为这就是所有必需的。
因此,回顾一下,无论如何git clone
都会调用其他--single-branch
Git并让它列出其所有分支和标签以及其他名称。然后它将使用这些名称来查找原始存储库中的所有提交和其他 Git 对象,并让其他 Git 发送所有这些对象。结果是对象数据库的完整副本。4 您现在拥有来自其他 Git 存储库的所有提交。--depth
但是,与此同时,您自己的 Git 会获取他们所有的名字,然后选择要使用的名字以及如何处理它们。一般来说,你的 Git 会使用它们所有的分支名称——它们的完整拼写是refs/heads/master
,refs/heads/topic
等等——然后将它们重命名为你自己的远程跟踪名称:refs/remotes/origin/master
、、refs/remotes/origin/topic
等等。然后,您的 Git 会创建自己的独立名称到哈希 ID 数据库,其中没有分支名称。5
最终结果是,在这一步之后git clone
,您立即拥有所有提交,但没有任何分支! 不过,这种情况很快就被 的最后一步纠正了git clone
。如果你没有说--no-checkout
,最后一步git clone
是运行git checkout
,这一步实际上创建了一个分支。您的 Git 创建的分支名称是您提供的-b
选项。如果您没有提供-b
选项,您的 Git 会询问另一个 Git它推荐哪个分支,如果其他所有方法都失败,您的 Git 会采用您自己的默认初始分支名称。6
1每个提交对象引用一个(单个)树对象,该对象保存该提交的快照,并具有元数据。每个树对象都包含一个部分文件名(名称组件,将根据需要串在一起)和另一个哈希 ID 的数组。该哈希 ID 标识另一棵树或存储某些文件内容的blob对象。Git 通过根据需要读取所有子树来构建文件的全名,并将完整的文件名存储在其索引中,然后使用在索引中看到的名称和 blob 哈希 ID 提取文件。这不是一个完整的描述,但这就是 Git 不能存储空目录的原因:没有办法将一个目录放入 Git 的索引中。
对象数据库还可以包含带注释的标记对象,每个对象都包含一个哈希 ID,通常是提交的 ID。这就是 Git 提供其注释标签的方式。
2也有例外:由于某种原因,旧存储库不断积累新名称,例如新的分支和标签名称,但几乎没有任何新的提交。但总的来说,对象数据库是使用大部分空间的地方,并且大部分时间用于初始克隆。
3其他名称包括诸如注释、进行中的二等分、某些交互式变基期间需要的名称等。基本上,任何将存储单个哈希 ID 的名称都会进入该数据库。不这样做的名称,例如遥控器的名称origin
,不要进入这里。那些通常放在目录中的config
文件中.git
。
该数据库目前实施得相当差。有时,名称在文件系统中存储为目录和文件名,这意味着在不区分大小写的文件系统上,例如 Windows 和 macOS 系统上的默认文件系统,分支名称变得不区分大小写。有时名称存储在一个名为 的纯文本文件中,这使得它们都像 Git 一直想要的那样区分大小写。一些特殊名称,例如,根本不会进入打包的引用文件,而是始终作为单独的文件存储在目录中。现在正在进行工作以提供适当的数据库,以解决这里的一系列问题。packed-refs
HEAD
.git
4从技术上讲,结果可以而且通常会省略使用名称无法找到的任何对象。不过,我们将在这里忽略这个细微的区别。
5你的 Git 通常也会忽略它们所有的非分支非标签名称。它如何处理它们的标签名称很复杂,但是在普通(不是单分支,没有深度限制)克隆中,您通常会复制所有它们的标签名称。
6这过去只是硬编码为master
,但现在变得可配置。
对此有何--single-branch
影响
使用该--single-branch
选项,您的 Git不会使用它们的所有名称。相反,您的 Git 仅使用您选项中的一个分支名称-b
,具有相同的默认值:如果您不提供-b
,您的 Git 会询问他们的 Git 他们推荐什么,或者使用另一个默认值。然后,您的 Git 将该分支名称转换为一个远程跟踪名称。它确保只向他们的 Git 询问在该分支上的提交,在另一个 Git 存储库中。
最终结果是您获得了一个远程跟踪名称,以及所有提交的一部分。最后git checkout
一步然后创建一个本地分支名称:与您的 Git 在选择要获取的提交子集时使用的名称相同。
对此有何--depth
影响
除了自动打开(--single-branch
但请注意,您可以使用它关闭--no-single-branch
它)之外,还可以--depth
创建一个浅克隆。要完全理解浅克隆,我们必须进入图论。(不过,我们不会在这里走得太远。)
在 Git 中,每个分支名称都准确地标识一个 commit。但是 Git 中的一个分支——如果我们忽略“分支”到底是什么意思的问题?(我们不应该忽略它,但我们会在这里)——通常有一堆提交。这是如何运作的?
答案是 Git 中的每个提交都包含一些较早提交的哈希 ID。在通常的简单情况下,我们最终会得到一长串提交,每个提交都向后指向一个较早的提交。此链中的最后一个提交是分支的尖端,或尖端提交。
让我们画一个简单的链,我们用一个大写字母代表每个提交的真实哈希 ID。哈希H
将是链中的最后一个,我们会说这是分支br1
:
... <-F <-G <-H <-- br1
该名称 br1
包含最后一次提交的哈希 IDH
。这就是我们如何让 Git 从对象数据库中取出它(记住,它是一个简单的键值存储:哈希 ID 是键)。但是在 commit 的主体中,Git 已经存储了之前commitH
的 hash ID 。因此,我们可以从中获取的 ID,并让 Git在键值存储中查找提交。同时 commit有的 ID,所以我们可以从to倒退。G
H
G
G
G
F
G
F
这就是 Git 的工作方式:向后。名称,如分支或标签或远程跟踪名称,存储一个哈希 ID。这就是我们想要的提交,然后,如果我们想要所有的提交,Git 会从那个提交倒退到前一个提交,然后继续前进。这个名字让我们开始;提交本身提供了路径的其余部分。
我们遍历的路径,以及我们在走这条路径时收集的所有提交,都是该分支上的可达提交。7 当两个分支分叉时,它们有一些共同的顺序:
I--J <-- br1
/
...--F--G--H <-- shared
\
K--L <-- br2
在这里,所有三个分支上的提交H
都在所有三个分支上,每个分支上的最后两个提交对其br*
分支都是唯一的。
这种可达性理念是 Git 的核心。这也是如何--depth
运作的。如果我们说--depth 1
,我们是在告诉我们的 Git:当你从另一个 Git 获得提交时,只执行一步。 如果我们--depth 1
在这里使用,我们得到:
i--J <-- br1
g--H <-- shared
j--L <-- br2
如果我们使用--depth 2
,我们会告诉我们的 Git:当您从另一个 Git 获取提交时,请执行两个步骤。 这次我们得到:
I--J <-- br1
/
f--G--H <-- shared
\
K--L <-- br2
请注意,如果br2
有更多独特的提交,我们将不会有从br2
back 到shared
.
这里的小写提交字母表示 Git 知道有父级,但这些父级被标记为“故意丢失”。更准确地说,浅层移植提交的哈希 ID 保存在目录中调用的文件shallow
中.git
。Git 知道不要尝试从对象存储库中加载这些提交,并且它们丢失并不是一个错误。通常,这将是一个错误。
由于它们是故意丢失的,git log
因此不能也不会显示这些提交,就好像浅嫁接的提交根本没有父母。这在某种程度上具有误导性,但也是您应该期望的。在大多数情况下,它是无害的。
7这假设我们使用的名称是一个分支名称。如果我们使用标签名称,这些是可从标签访问的提交;如果我们使用远程跟踪名称,这些是可从远程跟踪名称访问的提交。由于所有名称都使用相同的系统,因此每个名称都提供了某种方式来达到某些提交集。
这git fetch
是获得提交的操作
当我们使用 时git clone
,我们实际上是在运行相当于六个命令序列,其中五个是 Git 命令:
mkdir
, 创建一个新的空目录/文件夹;git init
, 在步骤 1 中创建的目录中创建一个新的空存储库;git remote add
,添加 nameorigin
或我们选择的其他名称,以及 URL 和fetch
配置——这是我们更改以击败单分支的配置;git config
,如果需要,添加在git clone
命令中指定的配置选项;git fetch
,获取提交并为步骤 3 中选择的一个或多个分支创建远程跟踪名称;和git checkout
, 创建一个本地分支名称并填写 Git 的索引和我们的工作树。
该--depth
选项被传递给git fetch
第 5 步。因此,如果我们必须调整我们的origin
远程配置,因为第 3 步仅添加了具有一个特定分支的远程(请参阅文档git remote
),我们必须运行一个新的git fetch
。这个新git fetch
的需要相同的--depth
选项。
结论
打开 both的--depth
选项,这限制了从另一个 Git 存储库获得的名称集,从而限制了提交,并将传递到 fetch 步骤,这限制了从另一个 Git 存储库获得的提交图的深度。在克隆时使用会抑制名称限制,同时保持深度限制。如果您需要撤消名称限制,或者如果您使用更新受限分支名称集,则必须再次运行。如果您希望它具有深度限制,则必须再次通过。git clone
--single-branch
--depth
--no-single-branch
git remote
git fetch
git fetch
--depth
请注意,git fetch
确实尊重现有的浅移植点,因此在某些情况下,省略--depth
有点无害。例如,如果您有一个如下所示的存储库的单分支克隆:
...--V--W--X <-- main
\
Y--Z <-- topic
并且您的单分支克隆深度为 1 on main
,因此提交W
被标记为浅移植点:
w--X <-- main
然后添加topic
没有 a--depth
得到你:
w--X <-- main
\
Y--Z <-- topic
也就是说,main
这次没有深入。但如果图表是:
...--V--W--X <-- main
\
Y--Z <-- topic
并且您在没有 new 的情况下添加topic
和获取--depth
,您将得到:
...--V w--X <-- main
\
Y--Z <-- topic
在您的克隆中,这意味着您必须V
更早地获得提交和所有内容。请注意,提交W
仍然标记和丢失:因为它丢失了,你的Git 看不到它w
会连接回来V
,你自己的 Git 会显示为:
X <-- main
..--V--Y--Z <-- topic
——这并没有错,从技术上讲,这只是一种误导。
推荐阅读
- javascript - 石头剪刀布游戏(js) - 如何创建一个圆形功能
- html - 提供用户选项以通过按钮将评估的 Google 脚本 html 模板下载为 pdf
- android - 问题:发现现有项目依赖项中的不一致。之间的版本不兼容: - com.google.firebase:firebase-auth:19.0.0@aar
- python - 我想在 python 中制作 3*3 矩阵格式列表
- typescript - 如何获取我的 npm 模块的 JSdoc 文档,以便在用户的 VScode 中显示函数?
- swift - 如何使用 Swift 获取 DispatchIO 的文件描述符?
- ios - AVPlayerViewController 上的关闭按钮第一次不起作用
- react-native - 在 react-native-table-component 中搜索
- python - 如何使用 .kv 文件在 kivy 中创建下拉列表
- sql-server - 如何连接具有不同列的两个表