【问题标题】:How to update a git shallow clone?如何更新 git 浅克隆?
【发布时间】:2017-04-25 20:24:25
【问题描述】:

背景

(对于 tl;dr,请参阅下面的#questions)

我有多个 git 存储库浅克隆。我使用的是浅克隆,因为它比深层克隆要小得多。每个都被克隆了大约git clone --single-branch --depth 1 <git-repo-url> <dir-name>

这很好用,只是我不知道如何更新它。

当我通过标签克隆时,更新没有意义,因为标签被冻结在时间点(据我所知)。在这种情况下,如果我想更新,这意味着我想通过另一个标签克隆,所以我只是 rm -rf <dir-name> 并再次克隆。

当我克隆了 master 分支的 HEAD 之后想要更新它时,事情变得更加复杂。

我尝试了git pull --depth 1,但虽然我不会将任何内容推送到远程存储库,但它抱怨它不知道我是谁。

我试过git fetch --depth 1,但虽然它似乎更新了一些东西,但我检查它不是最新的(远程存储库中的某些文件与我的克隆上的文件内容不同)。

https://stackoverflow.com/a/20508591/279335 之后,我尝试了git fetch --depth 1; git reset --hard origin/master,但有两件事:首先我不明白为什么需要git reset,其次,虽然文件似乎是最新的,但仍然存在一些旧文件,以及@ 987654329@ 不会删除这些文件。

问题

让一个使用git clone --single-branch --depth 1 <git-repo-url> <dir-name> 创建的克隆。如何更新它以达到与rm -rf <dir-name>; git clone --single-branch --depth 1 <git-repo-url> <dir-name> 相同的结果?还是rm -rf <dir-name> 再克隆一次?

注意

这不是 How to update a shallow cloned submodule without increasing main repo size 的重复,因为答案不符合我的期望,而且我使用的是简单的存储库,而不是子模块(我不知道)。

【问题讨论】:

  • 投反对票的人还敢评论解释原因?对于这个有价值的问题得到的很好的答复也不公平。有了这样的幽灵,stackoverflow 正在成为一个可以避免的地方。

标签: git git-clone


【解决方案1】:

TL;DR

假设您有一个从分支 B 克隆的现有 --depth 1 存储库,并且您希望 Git 的行为就像您删除并重新克隆一样,您可以使用以下命令序列:

git fetch --depth 1
git reset --hard origin/B
git clean -dfx

(例如,git reset --hard origin/master——我不能在上面的代码文字部分中使用斜体)。您应该可以在其他两个命令之前或之后的任何时间点执行git clean 步骤,但git reset 必须在git fetch 之后。

[稍微改写和格式化] 给定一个使用git clone --single-branch --depth 1 <em>url</em> <em>directory</em> 创建的克隆,我如何更新它以获得与rm -rf <em>directory</em>; git clone --single-branch --depth 1 <em>url</em> <em>directory</em> 相同的结果?

注意--single-branch 是使用--depth 1 时的默认。 (单个)分支是您使用-b 提供的分支。关于使用带有标签的-b,这里还有很长的一段话,但我将把它留到以后。如果你使用-b,你的Git会询问“上游”Git——url处的Git——it检查了哪个分支-out,并假装你使用了-b <em>thatbranch</em>。这意味着在使用 --single-branch without -b 时一定要小心,以确保这个上游存储库的当前分支是合理的,当然,当你这样做 使用-b,以确保您提供的分支参数确实命名了一个分支,而不是一个标签。

简单的答案基本上就是这个,有两个细微的变化:

https://stackoverflow.com/a/20508591/279335之后,我尝试了git fetch --depth 1; git reset --hard origin/master,但是有两件事:首先我不明白为什么需要git reset,其次,虽然文件似乎是最新的,但仍然有一些旧文件,以及@ 987654345@ 不会删除这些文件。

两个细微的变化是:确保使用origin/<em>branchname</em>,并将-xgit clean -d -f -xgit clean -dfx)添加到git clean 步骤。至于为什么,那就有点复杂了。

发生了什么

没有--depth 1git fetch 步骤调用另一个 Git 并从中获取分支名称和相应提交哈希 ID 的列表。也就是说,它会找到 all 上游分支及其当前提交的列表。然后,因为你有一个--single-branch 存储库,你的 Git 会抛出除单个分支之外的所有分支,并带来 Git 将当前提交连接回你已经拥有的提交所需的一切您的存储库。

有了 --depth 1,您的 Git 根本不会费心将新提交连接到旧的历史提交。相反,它只获取一个提交和完成该提交所需的其他 Git 对象。然后它会写入一个额外的“浅嫁接”条目,以将该提交标记为新的伪根提交。

常规(非浅层)克隆和获取

这些都与使用普通(非浅层、非单分支)克隆时 Git 的行为方式有关:git fetch 调用上游 Git,获取所有内容的列表,然后将其带过来任何你还没有的东西。这就是为什么初始克隆如此缓慢,而获取更新通常如此之快的原因:一旦你得到一个完整的克隆,更新很少会带来很多东西:可能是几个提交,可能是几百个,并且大多数提交也不需要太多其他内容。

存储库的历史是由提交形成的。每个提交命名它的 parent 提交(或对于合并,父提交,复数),在一个从“最新提交”到前一个提交,再到一些更祖先的提交的链中,以及很快。当到达没有父级的提交时,链最终会停止,例如在存储库中进行的第一次提交。这种提交是 root 提交。

也就是说,我们可以绘制提交图。在一个非常简单的存储库中,该图只是一条直线,所有箭头都指向后方:

o <- o <- o <- o   <-- master

名称master 指向第四个也是最新的提交,它又指向第三个,又指向第二个,又指向第一个。

每个提交都带有该提交中所有文件的完整快照。完全没有更改的文件在这些提交中共享:第四次提交只是从第三次提交中“借用”未更改的版本,从第二次提交中“借用”它,依此类推。因此,每个提交都会命名它需要的所有“Git 对象”,Git 要么在本地找到这些对象——因为它已经拥有它们——要么使用fetch 协议将它们从另一个上游 Git 带过来。有一种称为“打包”的压缩格式,以及一种称为“瘦包”的网络传输的特殊变体,它允许 Git 做得更好/更漂亮,但原理很简单:Git 需要所有,而且只需要那些对象随着新的提交,它正在接受。你的 Git 决定它是否有这些对象,如果没有,从他们的 Git 获取它们。

一个更复杂、更完整的图通常有几个分支点,一些点合并,多个分支名称指向不同的分支提示:

        o--o   <-- feature/tall
       /
o--o--o---o    <-- master
    \    /
     o--o      <-- bug/short

这里的分支bug/short 被合并回master,而分支feature/tall 仍在开发中。 name bug/short 现在可以(可能)被完全删除:如果我们完成了对它的提交,我们就不再需要它了。 master 顶端的提交命名两个 以前的提交,包括 bug/short 顶端的提交,因此通过获取 master,我们将获取 bug/short 提交。

请注意,简单图和稍微复杂的图都只有一个根提交。这很典型:所有有提交的存储库至少有一个根提交,因为第一个提交始终是根提交;但大多数存储库只有一个根提交。但是,您可以有不同的根提交,如下图所示:

 o--o
     \
o--o--o   <-- master

或者这个:

 o--o     <-- orphan

o--o      <-- master

实际上,只有master 的那个很可能是通过将orphan 合并到master,然后删除名称orphan 制成的。

移植和替换

长期以来,Git 一直(可能不稳定)对 grafts 的支持被替换为对通用 替换 的(更好,实际上更可靠)支持。为了具体掌握它们,我们需要在上面添加每个提交都有自己唯一 ID 的概念。这些 ID 是丑陋的 40 字符 SHA-1 哈希、face0ff... 等等。事实上,每个 Git 对象都有一个唯一的 ID,尽管出于图表目的,我们只关心提交。

对于绘制图形,那些大的哈希 ID 使用起来太痛苦了,所以我们可以使用单字母名称 AZ 来代替。让我们再次使用该图,但输入一个字母的名称:

        E--H   <-- feature/tall
       /
A--B--D---G    <-- master
    \    /
     C--F      <-- bug/short

提交H 指回提交EEH父级)。提交G,这是一个合并提交——意味着它至少有两个父节点——指回DF,等等。

请注意,分支名称feature/tallmasterbug/short,每个都指向单个提交。名称bug/short 指向提交F。这就是为什么提交 F 位于分支 bug/short 上的原因......但提交 C 也是如此。提交 C 位于 bug/short 上,因为它从名称中可达。这个名字让我们到达FF 让我们到达C,所以C 位于分支bug/short

但是请注意,提交 Gmaster 的提示,让我们提交 F。这意味着提交F 也是 在分支master 上。 这是 Git 中的一个关键概念:提交可能在 onemany 甚至 no 分支上。 A分支名称只是在提交图中开始的一种方式。还有其他方法,例如标签名称、refs/stash(它可以让您进入当前存储:每个存储实际上是几个提交)和 reflog(通常隐藏在视图之外,因为它们通常只是杂乱无章)。

然而,这也让我们进行移植和替换。移植只是一种有限的替换,shallow 存储库使用有限形式的移植。1我不会在这里完整描述替换,因为它们有点复杂,但总的来说,Git 对所有这些所做的是将移植或替换用作“替代”。对于 commits 的具体情况,我们在这里想要的是能够改变——或者至少,假装改变——任何提交的父 ID 或多个 ID。 . 对于 shallow 存储库,我们希望能够假装有问题的提交有 个父级。


1浅层存储库使用移植代码的方式不稳定。对于更一般的情况,我建议改用git replace,因为这也是并且现在不稳定。移植的唯一推荐用途是(或者至少是,几年前)将它们放置在足够长的时间以运行 git filter-branch复制一个改变的 - 移植的 - 历史,之后你应该只是完全抛弃嫁接的历史。您也可以为此目的使用git replace,但与移植不同的是,您可以永久或半永久地使用git replace不需要git filter-branch


制作浅层克隆

要对上游存储库的当前状态进行深度 1 浅层克隆,我们将选择三个分支名称之一——feature/tallmasterbug/short——并将其转换为提交 ID .然后我们将编写一个特殊的嫁接条目,上面写着:“当你看到那个提交时,假装它有 no 个父提交,即,是根提交。”

假设我们选择mastermaster 名称指向 commit G,所以要对 commit G 进行 shallow 克隆,我们照常从上游 Git 获取 commit G,然后写一个特殊的嫁接声称提交 G 的条目有 no 父母。我们将它放入我们的存储库中,现在我们的图表如下所示:

G   <-- master, origin/master

那些父ID实际上仍然在G中;只是每次我们使用 Git 或向我们展示历史记录时,它都会立即“移植”什么都没有,因此 G 似乎是根提交,用于历史跟踪目的.

更新我们之前制作的浅层克隆

但是如果我们已经有了一个(深度为 1 的浅)克隆,并且我们想要更新它呢?嗯,这不是一个真正的问题。假设我们在master 指向提交B 时,在新分支和错误修复之前对上游进行了浅层克隆。这意味着我们目前有这个:

B   <-- master, origin/master

虽然B 的真正父级是A,但我们有一个浅克隆嫁接条目说“假装B 是根提交”。现在我们git fetch --depth 1,它查找上游的master——这个东西我们调用origin/master——并看到提交G。我们从上游抓取提交 G 及其对象,但故意不要抓取提交 DF。然后我们更新我们的浅克隆移植条目,说“假装G 也是根提交”:

B   <-- master

G   <-- origin/master

我们的存储库现在有 两个 根提交:名称 master(仍然)指向提交 B,我们(仍然)假装其父项不存在,名称 @987654440 @ 指向 G,我们假装其父母不存在。

这就是为什么你需要git reset

在普通存储库中,您可能会使用git pull,实际上是git fetch,后跟git merge。但是git merge 需要历史,而我们没有:我们用假根提交伪造了 Git,而他们背后没有历史。所以我们必须改用git reset

git reset 所做的有点复杂,因为它最多可以影响三个不同的东西:分支名称索引工作-树。我们已经看到了分支名称是什么:它们只是指向一个(一个,特定的)提交,我们称之为分支的 tip。剩下的就是索引和工作树。

工作树 很容易解释:它是所有文件所在的位置。就是这样:不多也不少。它的存在是为了让您真正使用 Git:Git 就是要永远存储每一个提交,以便它们都可以被检索。但它们的格式对凡人无用。为了使用,一个文件——或者更典型地,整个提交的文件价值——必须被提取成它的正常格式。工作树就是发生这种情况的地方,然后您可以对其进行处理并使用它进行新的提交。

index 有点难以解释。这是 Git 特有的东西:其他版本控制系统没有,或者如果他们有类似的东西,他们不会公开它。吉特可以。 Git 的索引本质上是你保存 next 提交的地方,但这意味着它开始保存你提取到工作树中的 current 提交,而 Git使用它来使 Git 更快。我们稍后会详细介绍。

git reset --hard 所做的是影响所有三个:分支名称、索引和工作树。它移动分支名称,使其指向(可能不同的)提交。然后它更新索引以匹配该提交,并更新工作树以匹配新索引。

因此:

git reset --hard origin/master

告诉 Git 查找 origin/master。由于我们运行了git fetch,现在指向提交G。然后,Git 使 我们的 主分支——我们当前的(也是唯一的)分支——也指向提交 G,然后更新我们的索引和工作树。我们的图表现在看起来像这样:

B   [abandoned - but see below]

G   <-- master, origin/master

现在masterorigin/master 都命名为commit G,commit G 是签出到工作树中的那个。

为什么需要git clean -dfx

这里的答案有点复杂,但通常是“你不知道”(需要git clean)。

当你确实需要git clean时,这是因为你——或者你运行的东西——向你的工作树添加了你没有告诉Git的文件。这些是未跟踪和/或忽略文件。使用git clean -df 将删除未跟踪 文件(和空目录);添加-x 也会删除被忽略的文件。

有关“未跟踪”和“忽略”之间区别的更多信息,请参阅this answer

为什么你不需要git clean:索引

我在上面提到你通常不需要运行git clean。这是因为索引。正如我之前所说,Git 的索引主要是“下一次提交”。如果您从不添加自己的文件——如果您只是使用git checkout 来检查您一直拥有的各种现有提交,或者您使用git fetch 添加的;或者如果您使用git reset --hard 移动分支名称并将索引和工作树切换到另一个提交 - 那么索引中的任何内容现在都在那里因为 一个较早的git checkout(或git reset它放入索引中,也放入工作树中。

换句话说,索引有一个简短的——Git 可以快速访问的——summarymanifest 描述当前的工作树。 Git 使用它来知道现在工作树中的内容。当您通过git checkoutgit reset --hard 要求Git 切换到另一个提交时,Git 可以快速将现有索引与新提交进行比较。任何已更改的文件,Git 必须从新提交中提取(并更新索引)。任何新添加的文件,Git 还必须提取(并更新索引)。任何已消失的文件——在现有索引中,但不在新提交中——Git 必须 remove ...这就是 Git 所做的。 Git 根据当前索引和新提交之间的比较来更新、添加和删除工作树中的这些文件。

这意味着如果你确实需要git clean,那么你一定是在Git之外做了一些添加文件的事情。这些添加的文件不在索引中,因此by definition,它们未被跟踪和/或被忽略。如果它们只是未被跟踪,git clean -f 将删除它们,但如果它们被忽略,则只有 git clean -fx 将删除它们。 (您希望-d 仅删除在清理过程中为空或变为空的目录。)

放弃的提交和垃圾收集

我提到并绘制了更新的浅图,当我们git fetch --depth 1git reset --hard 时,我们结束了放弃之前的 depth-1 浅图提交。 (在我绘制的图表中,这是提交 B。)然而,在 Git 中,被放弃的提交很少被真正放弃——至少,不是马上被放弃。取而代之的是,像ORIG_HEAD 这样的一些特殊名称会在它们身上保留一段时间,并且每个reference(分支和标签都是引用形式)都带有一个log“以前的值”。

您可以使用git reflog <em>refname</em> 显示每个引用日志。例如,git reflog master 不仅会显示master 的哪个提交现在,而且还显示它在过去命名的哪个提交。 HEAD 本身也有一个 reflog,这是 git reflog 默认显示的内容。

Reflog 条目最终会过期。它们的确切持续时间各不相同,但默认情况下,在某些情况下,它们有资格在 30 天后到期,在其他情况下则在 90 天后到期。一旦它们过期,这些 reflog 条目就不再保护放弃的提交(或者,对于带注释的标记引用,带注释的标记对象 - 标记不 supposed 移动,因此这种情况不是 supposed 发生,但如果发生了——如果你强制 Git 移动一个标签——它只是以与所有其他引用相同的方式处理)。

一旦任何 Git 对象——提交、注释标签、“树”或“blob”(文件)——真的没有被引用,Git 就可以真正删除它。2 只有在这一点上,提交和文件的底层存储库数据才会消失。即便如此,它也只会在运行git gc 时发生。因此,使用git fetch --depth 1 更新的浅存储库与使用--depth 1 更新的新克隆完全相同:浅存储库可能对原始提交有一些挥之不去的名称,并且不会删除额外的存储库对象,直到这些名称过期或以其他方式被清除。


2除了引用检查之外,对象在过期之前也有一个最短时间。默认为两周。这可以防止 git gc 删除 Git 正在创建但尚未建立引用的临时对象。例如,在进行新提交时,Git 首先将索引转换为一系列 tree 对象,它们相互引用但没有顶级引用。然后它创建一个新的commit 对象,该对象引用顶级树,但还没有任何内容引用提交。最后,它更新当前分支名称。在最后一步完成之前,树和新提交是无法访问的!


--single-branch 和/或浅克隆的特殊注意事项

我在上面提到你给git clone -b 的名字可以引用一个标签。对于普通的(非浅层或非单分支)克隆,这和预期的一样:你得到一个普通的克隆,然后 Git 通过标签名称执行 git checkout。结果是通常分离的 HEAD,在一个完全普通的克隆中。

但是,对于浅层或单分支克隆,会产生一些不寻常的后果。在某种程度上,这些都是 Git 让实现显示出来的结果。

首先,如果您使用 --single-branch,Git 会更改新存储库中的正常 fetch 配置。正常的fetch 配置取决于您为remote 选择的名称,但默认为origin,所以我将在这里使用origin。上面写着:

fetch = +refs/heads/*:refs/remotes/origin/*

同样,这是正常(非单分支)克隆的正常配置。此配置告诉git fetch要获取什么,即“所有分支”。但是,当您使用 --single-branch 时,您会得到一个仅引用一个分支的 fetch 行:

fetch = +refs/heads/zorg:refs/remotes/origin/zorg

如果您要克隆 zorg 分支。

无论你克隆哪个分支,都会进入fetch 行。每个未来git fetch 都会遵循这一行,3 sup> 所以你不会获取任何其他分支。如果您确实想稍后获取其他分支,则必须更改此行,或添加更多行。

其次,如果你使用--single-branch,而你克隆的是一个标签,Git 会放入一个相当奇怪的fetch 行。例如,git clone --single-branch -b v2.1 ... 我得到:

fetch = +refs/tags/v2.1:refs/tags/v2.1

这意味着您将获得 no 分支,除非有人移动了标签,否则4git fetch什么都不做

第三,由于git clonegit fetch获取标签的方式,默认的标签行为有点奇怪。请记住,标签只是对一个特定提交的引用,就像分支和所有其他引用一样。不过,分支和标签之间有两个主要区别:分支是预计 可以移动(而标签不是),而分支是重命名(而标签不会)。

请记住,在上述所有内容中,我们不断发现另一个(上游)Git 的master 变成了我们的origin/master,等等。这是重命名过程的示例。我们还通过fetch = 行简要地了解了如何重命名工作:我们的Git 使用他们的refs/heads/master 并将其更改为我们的refs/remotes/origin/master。这个名字不仅不同-看起来 (origin/master),而且实际上不能与我们的任何分支机构相同。如果我们创建一个名为origin/master 的分支,5 这个分支的“全名”实际上是refs/heads/origin/master,这与另一个全名refs/remotes/origin/master 不同。只有当 Git 使用较短的名称时,我们才有一个(常规的、本地的)分支名为 origin/master 和另一个不同的(远程跟踪)分支名为 origin/master。 (这很像在a group where everyone is named Bruce。)

标签不会经历这一切。标签 v2.1 刚刚命名为 refs/tags/v2.1。这意味着无法将“他们的”标签与“您的”标签分开。您可以拥有自己的标签,也可以拥有他们的标签。只要没有人移动一个标签,这没关系:如果你两个都有标签,它必须指向同一个对象。 (如果有人开始移动标签,事情就会变得很糟糕。)

无论如何,Git 通过一个简单的规则实现“正常”的标签获取:6当 Git 已经有提交时,如果某些标签 names该提交时,Git 也会复制标签。 对于普通克隆,第一个克隆会获取所有标签,然后后续的 git fetch 操作会获取 new 标签。然而,根据定义,浅层克隆会省略一些提交,即图中任何移植点以下的所有内容。这些提交不会获取标签。他们不能:要拥有标签,您需要提交。不允许 Git(除了通过浅层移植)在没有实际提交的情况下拥有提交的 ID。


3您可以在命令行上给git fetch 一些参考规范,这些参考规范将覆盖默认值。这仅适用于默认提取。您也可以在配置中使用多个fetch = 行,例如,仅获取一组特定的分支,尽管“取消限制”初始单分支克隆的正常方法是放回通常的+refs/heads/*:refs/remotes/origin/*取线。

4由于标签不应该移动,我们可以说“这没有任何作用”。但是,如果它们确实移动了,则 refspec 中的 + 表示强制标志,因此标签最终会移动。

5不要这样做。这很令人困惑。 Git 可以很好地处理它——本地分支在本地名称空间中,而远程跟踪分支在远程跟踪名称空间中——但这真的很混乱。

6此规则与文档不符。我针对 Git 2.10.1 版本进行了测试;较旧的 Git 可能使用不同的方法。从 2.26 开始的 Git 也可以使用不同的规则,因为有一个更新的、更高级的协议供 git fetchgit push 使用。如果您关心标签的精确行为,您可能需要在您的特定 Git 版本上对其进行测试。

【讨论】:

  • 很好的答案!您能否在顶部发布一个 tl;dr,突出显示为浅克隆大师运行的命令?
  • 是否有任何推荐的命令来删除任何剩余的 git 文件,例如git reflog expire --all 或 git gc --prune=all ?
  • @racitup:我不会建议在这里做任何事情,因为这有点像建议您将汽车的所有安全和舒适设备都去掉这样它就可以跑得更快(这确实有效——一辆更轻的汽车跑得更快,在限制范围内——但有明显的缺点......)。不过,您实际上可以运行这些命令。为无法访问的 reflog 条目添加短的(例如,“现在”)到期。这应该会稍微缩小.git 目录,这取决于很多事情。但是,有时重新打包只会使.git 目录变胖。 (这不是可能,但它确实发生了。)
  • @torek 我所说的场景是更新不需要存储库的生产服务器,因为没有理由进行任何开发。你只想要最新的稳定代码
  • @racitup:对于这种情况,我宁愿有某种部署软件,根本不涉及在服务器上保留 Git 存储库。 (可能是什么部署软件……嗯,那个更难。)
【解决方案2】:

关于浅层克隆更新过程本身,请参阅 commit 649b0c3 表格 Git 2.12(2017 年第一季度)。
该提交是以下内容的一部分:

Commit 649b0c3commit f2386c6commit 6bc3d8ccommit 0afd307(2016 年 12 月 6 日)Nguyễn Thái Ngọc Duy (pclouds)。 请参阅commit 1127b3ccommit 381aa8e(2016 年 12 月 6 日)Rasmus Villemoes (ravi-prevas)(于 2016 年 12 月 21 日由 Junio C Hamano -- gitster -- 合并于 commit 3c9979b

shallow.c

paint_down()58babff (shallow.c: the 8 steps to select new commits for .git/shallow - 2013-12-05) 第 6 步的一部分。
当我们从浅存储库中获取时,我们需要知道新的/更新的 ref 之一是否需要 .git/shallow 中的新“浅提交”(因为我们没有足够的这些 ref 的历史记录)以及哪一个。

第 6 步的问题是,需要哪些(新的)浅提交 其他以保持整个存储库的可访问性没有 缩短我们的历史?
为了回答,我们用 UNINTERESTING ("rev-list --not --all") 标记从现有 refs 可访问的所有提交,用 BOTTOM 标记浅提交,然后对于每个新/更新的 refs,遍历提交图,直到我们点击 UNINTERESTING 或 BOTTOM,标记在我们走路时参考提交。

所有遍历完成后,我们检查新的浅提交。要是我们 还没有看到在新的浅层提交上标记了任何新的 ref,我们都知道 仅使用我们的历史记录和 .git/shallow 即可访问新的/更新的参考。
有问题的浅提交是不需要的,可以丢弃。

所以,代码。

这里的循环(遍历提交)基本上是:

  1. 从队列中获取一个提交
  2. 忽略它是否可见或不感兴趣
  3. 标记它
  4. 通过所有的父母和..
    • 5.a 如果之前从未标记,请标记它
    • 5.b 放回队列中

我们在这个补丁中所做的是放弃第 5a 步,因为它不是 必要的。
在 5a 标记的提交被放回队列中,并且 将在下一次迭代的第 3 步标记。唯一会的情况 未标记是提交已被标记为 UNINTERESTING (5a 不检查这个),这将在第 2 步被忽略。

【讨论】:

    【解决方案3】:

    如果目标是在不获取整个历史记录的情况下更新浅层克隆(但允许获取较短的历史记录),那么使用现代版本 git (>= 2.11.1) 的替代方法可以使用:

    • --shallow-since=... 仅获取早于给定日期的提交
    • --shallow-exclude=... 获取而不获取作为给定提交的祖先的提交

    【讨论】:

    • 你的回答错过了问题的关键部分:一旦我有了一个浅克隆,如何用你的标志获得一个更新的克隆。
    猜你喜欢
    • 2020-06-26
    • 1970-01-01
    • 1970-01-01
    • 2016-06-09
    • 2015-02-21
    • 1970-01-01
    • 2013-10-11
    • 2011-06-23
    相关资源
    最近更新 更多