简体中文 ▾ 主题 ▾ 最新版本 ▾ git-fetch 最后更新于 2.48.0

名称

git-fetch - 从另一个仓库下载对象和引用

概要

git fetch [<options>] [<repository> [<refspec>…​]]
git fetch [<options>] <group>
git fetch --multiple [<options>] [(<repository> | <group>)…​]
git fetch --all [<options>]

描述

从一个或多个其他仓库抓取分支和/或标签(统称为“引用”),以及完成其历史所需的其他对象。远程跟踪分支将被更新(请参阅下文 <refspec> 的描述以了解如何控制此行为)。

默认情况下,任何指向所抓取历史的标签也会被抓取;其效果是抓取指向您感兴趣的分支的标签。此默认行为可以通过使用 --tags--no-tags 选项或配置 remote.<name>.tagOpt 来更改。通过使用显式抓取标签的 refspec,您也可以抓取不指向您感兴趣的分支的标签。

git fetch 可以从单个命名仓库或 URL 抓取,也可以同时从多个仓库抓取,如果给定 <group> 并且配置文件中有 remotes.<group> 条目。(请参阅 git-config[1])。

未指定远程仓库时,默认使用 origin 远程仓库,除非当前分支已配置上游分支。

抓取到的引用名称及其指向的对象名称将写入 .git/FETCH_HEAD。此信息可用于脚本或其他 Git 命令,例如 git-pull[1]

选项

--[no-]all

抓取所有远程仓库,除了那些设置了 remote.<name>.skipFetchAll 配置变量的仓库。这会覆盖配置变量 fetch.all

-a
--append

将抓取到的引用的名称和对象名称追加到 .git/FETCH_HEAD 的现有内容中。不使用此选项,.git/FETCH_HEAD 中的旧数据将被覆盖。

--atomic

使用原子事务更新本地引用。要么所有引用都更新,要么出错时,不更新任何引用。

--depth=<depth>

将抓取限制为每个远程分支历史尖端指定数量的提交。如果抓取到使用 git clone--depth=<depth> 选项创建的浅克隆仓库(参见 git-clone[1]),则将历史记录加深或缩短到指定数量的提交。加深提交的标签不会被抓取。

--deepen=<depth>

类似于 --depth,但它指定的是从当前浅克隆边界开始的提交数量,而不是从每个远程分支历史的尖端开始。

--shallow-since=<date>

深化或缩短浅克隆仓库的历史记录,以包含 <date> 之后所有可达的提交。

--shallow-exclude=<ref>

深化或缩短浅克隆仓库的历史记录,以排除从指定远程分支或标签可达的提交。此选项可以多次指定。

--unshallow

如果源仓库是完整的,则将浅克隆仓库转换为完整仓库,移除浅克隆仓库施加的所有限制。

如果源仓库是浅克隆仓库,则尽可能多地抓取,以便当前仓库与源仓库具有相同的历史记录。

--update-shallow

默认情况下,当从浅克隆仓库抓取时,git fetch 会拒绝需要更新 .git/shallow 的引用。此选项会更新 .git/shallow 并接受此类引用。

--negotiation-tip=<commit|glob>

默认情况下,Git 会向服务器报告所有本地引用可达的提交,以查找共同提交,从而尝试减少要接收的包文件大小。如果指定此选项,Git 将仅报告给定尖端可达的提交。当用户知道哪个本地引用可能与正在抓取的上游引用有共同提交时,这有助于加快抓取速度。

此选项可以多次指定;如果这样,Git 将报告从任何给定提交可达的提交。

此选项的参数可以是引用名称的 glob 模式、一个引用,或提交的(可能是缩写的)SHA-1。指定 glob 模式等同于多次指定此选项,每次对应一个匹配的引用名称。

另请参阅 git-config[1] 中记录的 fetch.negotiationAlgorithmpush.negotiate 配置变量,以及下方的 --negotiate-only 选项。

--negotiate-only

不从服务器抓取任何内容,而是打印与服务器共同拥有的、由提供的 --negotiation-tip=* 参数指定的祖先。

这与 --recurse-submodules=[yes|on-demand] 不兼容。在内部,此选项用于实现 push.negotiate 选项,请参阅 git-config[1]

--dry-run

显示将要执行的操作,但不进行任何更改。

--porcelain

以易于脚本解析的格式将输出打印到标准输出。详情请参阅 git-fetch[1] 中的 OUTPUT 部分。

这与 --recurse-submodules=[yes|on-demand] 不兼容,并优先于 fetch.output 配置选项。

--[no-]write-fetch-head

将抓取的远程引用列表直接写入 $GIT_DIR 下的 FETCH_HEAD 文件。这是默认行为。从命令行传递 --no-write-fetch-head 会告诉 Git 不写入此文件。在 --dry-run 选项下,该文件永远不会写入。

-f
--force

git fetch<src>:<dst> `refspec` 一起使用时,它可能会拒绝更新本地分支,如下面 <refspec> 部分所讨论的。此选项会覆盖该检查。

-k
--keep

保留下载的包。

--multiple

允许指定多个 <repository><group> 参数。不能指定 <refspec>

--[no-]auto-maintenance
--[no-]auto-gc

在最后运行 git maintenance run --auto 以在需要时执行自动仓库维护。(--[no-]auto-gc 是同义词。)此功能默认启用。

--[no-]write-commit-graph

抓取后写入提交图。这会覆盖配置设置 fetch.writeCommitGraph

--prefetch

修改配置的 refspec,将所有引用放置到 refs/prefetch/ 命名空间中。请参阅 git-maintenance[1] 中的 prefetch 任务。

-p
--prune

在抓取之前,删除远程仓库中不再存在的任何远程跟踪引用。如果标签仅因默认的标签自动跟踪或 --tags 选项而被抓取,则它们不受修剪。但是,如果标签是由于显式 refspec(无论是命令行上还是远程配置中,例如如果远程仓库是用 --mirror 选项克隆的)而被抓取,那么它们也受修剪。提供 --prune-tags 是提供标签 refspec 的简写。

详情请参阅下面的 PRUNING 部分。

-P
--prune-tags

在抓取之前,如果启用了 --prune,则删除远程仓库中不再存在的任何本地标签。此选项应更谨慎使用,与 --prune 不同,它将删除所有已创建的本地引用(本地标签)。此选项是与 --prune 一起提供显式标签 refspec 的简写,请参阅其文档中的相关讨论。

详情请参阅下面的 PRUNING 部分。

-n
--no-tags

默认情况下,指向从远程仓库下载的对象的标签会被抓取并本地存储。此选项禁用此自动标签跟踪。远程仓库的默认行为可以通过 remote.<name>.tagOpt 设置指定。请参阅 git-config[1]

--refetch

此选项不是与服务器协商以避免传输本地已存在的提交和相关对象,而是像全新克隆一样抓取所有对象。当过滤器定义更改时,使用此选项可以重新应用配置中的部分克隆过滤器或使用 --filter=。自动抓取后维护将执行对象数据库包合并以删除任何重复对象。

--refmap=<refspec>

当抓取命令行上列出的引用时,使用指定的 refspec(可以多次给定)将引用映射到远程跟踪分支,而不是使用远程仓库的 remote.*.fetch 配置变量的值。向 --refmap 选项提供一个空的 <refspec> 会使 Git 忽略已配置的 refspec,并完全依赖作为命令行参数提供的 refspec。详情请参阅“已配置的远程跟踪分支”部分。

-t
--tags

除了其他将被抓取的内容之外,从远程仓库抓取所有标签(即,将远程标签 refs/tags/* 抓取到本地同名标签中)。单独使用此选项不会使标签受到修剪,即使使用了 --prune 也是如此(尽管如果标签也是显式 refspec 的目标,则无论如何都可能修剪标签;请参阅 --prune)。

--recurse-submodules[=(yes|on-demand|no)]

此选项控制是否以及在何种条件下也应抓取子模块的新提交。当递归遍历子模块时,git fetch 总是尝试抓取“已更改”的子模块,即,一个子模块包含被新抓取的超项目提交引用但在本地子模块克隆中缺失的提交。只要子模块在本地存在(例如在 $GIT_DIR/modules/ 中)(参见 gitsubmodules[7]),就可以抓取已更改的子模块;如果上游添加了新的子模块,则该子模块在通过例如 git submodule update 克隆之前无法抓取。

当设置为 on-demand 时,只抓取已更改的子模块。当设置为 yes 时,抓取所有已填充的子模块,并且抓取未填充但已更改的子模块。当设置为 no 时,永不抓取子模块。

未指定时,如果设置了 fetch.recurseSubmodules,则使用其值(参见 git-config[1]),如果未设置则默认为 on-demand。当此选项不带任何值使用时,默认为 yes

-j
--jobs=<n>

用于所有形式抓取的并行子进程数量。

如果指定了 --multiple 选项,则不同的远程仓库将并行抓取。如果抓取多个子模块,它们将并行抓取。要独立控制它们,请使用配置设置 fetch.parallelsubmodule.fetchJobs(参见 git-config[1])。

通常,并行递归和多远程抓取会更快。默认情况下,抓取是按顺序执行的,而不是并行。

--no-recurse-submodules

禁用子模块的递归抓取(这与使用 --recurse-submodules=no 选项效果相同)。

--set-upstream

如果远程仓库成功抓取,则添加上游(跟踪)引用,供无参数的 git-pull[1] 和其他命令使用。更多信息,请参阅 git-config[1] 中的 branch.<name>.mergebranch.<name>.remote

--submodule-prefix=<path>

在“正在抓取子模块 foo”等信息性消息中打印的路径前加上 <path>。此选项在递归遍历子模块时内部使用。

--recurse-submodules-default=[yes|on-demand]

此选项在内部用于临时为 --recurse-submodules 选项提供一个非负的默认值。所有其他配置抓取子模块递归的方法(例如 gitmodules[5]git-config[1] 中的设置)都会覆盖此选项,直接指定 --[no-]recurse-submodules 也是如此。

-u
--update-head-ok

默认情况下 git fetch 拒绝更新与当前分支对应的 HEAD。此标志禁用该检查。这纯粹是 git pullgit fetch 通信的内部使用,除非您正在实现自己的 Porcelain 命令,否则不应使用它。

--upload-pack <upload-pack>

当给定此选项,并且要从中抓取的仓库由 git fetch-pack 处理时,--exec=<upload-pack> 将传递给命令,以指定在另一端运行的命令的非默认路径。

-q
--quiet

--quiet 传递给 git-fetch-pack 并静默所有其他内部使用的 Git 命令。进度不会报告到标准错误流。

-v
--verbose

启用详细输出。

--progress

默认情况下,当标准错误流连接到终端时,会报告进度状态,除非指定了 -q。此标志强制报告进度状态,即使标准错误流未定向到终端。

-o <option>
--server-option=<option>

使用协议版本 2 进行通信时,将给定字符串传输到服务器。给定字符串不得包含 NUL 或 LF 字符。服务器对服务器选项(包括未知选项)的处理是服务器特定的。当给定多个 --server-option=<option> 时,它们将按照命令行中列出的顺序全部发送到另一端。当命令行没有给定 --server-option=<option> 时,将使用配置变量 remote.<name>.serverOption 的值。

--show-forced-updates

默认情况下,Git 会在抓取期间检查分支是否被强制更新。这可以通过 fetch.showForcedUpdates 禁用,但 --show-forced-updates 选项保证会进行此检查。请参阅 git-config[1]

--no-show-forced-updates

默认情况下,Git 会在抓取期间检查分支是否被强制更新。传递 --no-show-forced-updates 或将 fetch.showForcedUpdates 设置为 false 以出于性能原因跳过此检查。如果在 git-pull 期间使用,--ff-only 选项在尝试快进更新之前仍会检查强制更新。请参阅 git-config[1]

-4
--ipv4

仅使用 IPv4 地址,忽略 IPv6 地址。

-6
--ipv6

仅使用 IPv6 地址,忽略 IPv4 地址。

<repository>

“远程”仓库,它是抓取或拉取操作的来源。此参数可以是 URL(请参阅下面的 GIT URLS 部分)或远程仓库的名称(请参阅下面的 REMOTES 部分)。

<group>

在配置文件中,指代作为 remotes.<group> 值的仓库列表的名称。(请参阅 git-config[1])。

<refspec>

指定要抓取的引用以及要更新的本地引用。当命令行上没有 <refspec> 时,要抓取的引用将从 remote.<repository>.fetch 变量中读取(请参阅下面的 已配置的远程跟踪分支)。

<refspec> 参数的格式是可选的加号 +,后跟源 <src>,后跟冒号 :,再后跟目标 <dst>。当 <dst> 为空时可以省略冒号。<src> 通常是一个引用,或者带有单个 * 的 glob 模式,用于匹配一组引用,但它也可以是一个完整的十六进制对象名称。

一个 <refspec> 可以在其 <src> 中包含 * 以表示简单的模式匹配。这样的 refspec 功能类似于匹配任何符合该模式的引用的 glob 模式。一个模式 <refspec> 必须在 <src><dst> 中都只有一个 *。它将通过将 * 替换为源中匹配的内容来将引用映射到目标。

如果一个 refspec 以 ^ 为前缀,它将被解释为负 refspec。这样的 refspec 不指定要抓取哪些引用或要更新哪些本地引用,而是指定要排除的引用。如果一个引用至少匹配一个正 refspec 并且不匹配任何负 refspec,则认为它匹配。负 refspec 对于限制模式 refspec 的范围很有用,使其不包含特定引用。负 refspec 本身可以是模式 refspec。但是,它们只能包含 <src> 并且不指定 <dst>。也不支持完整的十六进制对象名称。

tag <tag>refs/tags/<tag>:refs/tags/<tag> 的含义相同;它请求抓取直到给定标签的所有内容。

匹配 <src> 的远程引用被抓取,如果 <dst> 不是空字符串,则尝试更新匹配它的本地引用。

不使用 --force 是否允许该更新取决于它被抓取到的引用命名空间、被抓取的对象类型,以及该更新是否被视为快进。通常,抓取时适用与推送时相同的规则,有关这些规则,请参阅 git-push[1]<refspec>... 部分。下面注明了 git fetch 特有的规则例外。

在 Git 2.20 版本之前,与使用 git-push[1] 推送不同,对 refs/tags/* 的任何更新都将在 refspec 中不带 +(或 --force)的情况下被接受。抓取时,我们随意地将远程仓库的所有标签更新视为强制抓取。从 Git 2.20 版本开始,抓取以更新 refs/tags/* 的工作方式与推送时相同。即,任何更新都将在 refspec 中不带 +(或 --force)的情况下被拒绝。

与使用 git-push[1] 推送不同,refs/{tags,heads}/* 之外的任何更新都将在 refspec 中不带 +(或 --force)的情况下被接受,无论是将树对象替换为 blob,还是将提交替换为另一个不将前一个提交作为祖先的提交等。

与使用 git-push[1] 推送不同,没有配置会修改这些规则,也没有类似于 pre-receive 钩子的 pre-fetch 钩子。

与使用 git-push[1] 推送一样,上述所有关于不允许更新的规则都可以通过在 refspec 前添加可选的引导 +(或使用 --force 命令行选项)来覆盖。唯一的例外是,无论如何强制,refs/heads/* 命名空间都不会接受非提交对象。

注意
当已知您要抓取的远程分支会定期回滚和变基时,其新尖端预计不会是其先前尖端(上次抓取时存储在您的远程跟踪分支中)的后代。您会希望使用 + 符号来指示此类分支需要非快进更新。无法确定或声明一个仓库中的分支将具有此行为;拉取用户只需知道这是该分支的预期使用模式。
--stdin

除了作为参数提供的 refspec 外,还从标准输入中逐行读取 refspec。“tag <name>”格式不受支持。

GIT URLS

通常,URL 包含有关传输协议、远程服务器地址和仓库路径的信息。根据传输协议,其中一些信息可能不存在。

Git 支持 ssh、git、http 和 https 协议(此外,ftp 和 ftps 也可用于获取,但这效率低下且已弃用;请勿使用它们)。

原生传输(即 git:// URL)不进行身份验证,在不安全的网络上应谨慎使用。

可以使用以下语法:

  • ssh://[<user>@]<host>[:<port>]/<path-to-git-repo>

  • git://<host>[:<port>]/<path-to-git-repo>

  • http[s]://<host>[:<port>]/<path-to-git-repo>

  • ftp[s]://<host>[:<port>]/<path-to-git-repo>

ssh 协议还可以使用另一种类似 scp 的语法:

  • [<user>@]<host>:/<path-to-git-repo>

只有在第一个冒号前没有斜杠时才识别此语法。这有助于区分包含冒号的本地路径。例如,本地路径 foo:bar 可以指定为绝对路径或 ./foo:bar,以避免被错误地解释为 SSH URL。

ssh 和 git 协议还支持 ~<username> 扩展

  • ssh://[<user>@]<host>[:<port>]/~<user>/<path-to-git-repo>

  • git://<host>[:<port>]/~<user>/<path-to-git-repo>

  • [<user>@]<host>:~<user>/<path-to-git-repo>

对于 Git 本身也支持的本地仓库,可以使用以下语法

  • /path/to/repo.git/

  • file:///path/to/repo.git/

这两种语法大部分是等效的,除了在克隆时,前者意味着 --local 选项。有关详细信息,请参阅 git-clone[1]

git clonegit fetchgit pull(但 git push 不支持)也会接受合适的捆绑文件。请参阅 git-bundle[1]

当 Git 不知道如何处理某个传输协议时,它会尝试使用 remote-<transport> 远程辅助程序(如果存在)。要显式请求远程辅助程序,可以使用以下语法:

  • <transport>::<address>

其中 <address> 可以是路径、服务器和路径,或者是特定远程辅助工具可识别的任意类 URL 字符串。有关详细信息,请参阅 gitremote-helpers[7]

如果存在大量名称相似的远程仓库,并且您想为它们使用不同的格式(以便您使用的 URL 将被重写为可用的 URL),您可以创建以下形式的配置节:

	[url "<actual-url-base>"]
		insteadOf = <other-url-base>

例如,有了这个:

	[url "git://git.host.xz/"]
		insteadOf = host.xz:/path/to/
		insteadOf = work:

“work:repo.git”或“host.xz:/path/to/repo.git”这样的 URL 在任何接受 URL 的上下文中都将被重写为“git://git.host.xz/repo.git”。

如果只想重写推送的 URL,可以创建以下形式的配置节:

	[url "<actual-url-base>"]
		pushInsteadOf = <other-url-base>

例如,有了这个:

	[url "ssh://example.org/"]
		pushInsteadOf = git://example.org/

像“git://example.org/path/to/repo.git”这样的 URL 将被重写为“ssh://example.org/path/to/repo.git”用于推送,但拉取仍将使用原始 URL。

远程仓库

以下之一的名称可以作为 <repository> 参数来代替 URL 使用:

  • Git 配置文件中的远程仓库:$GIT_DIR/config

  • $GIT_DIR/remotes 目录中的文件,或

  • $GIT_DIR/branches 目录中的文件。

所有这些也允许你省略命令行中的引用规范,因为它们各自包含一个 Git 将默认使用的引用规范。

配置文件中的命名远程仓库

您可以选择提供之前使用 git-remote[1]git-config[1] 配置过的远程仓库名称,甚至可以通过手动编辑 $GIT_DIR/config 文件来配置。此远程仓库的 URL 将用于访问仓库。当您未在命令行提供 refspec 时,此远程仓库的 refspec 将默认使用。配置文件中的条目将显示如下:

	[remote "<name>"]
		url = <URL>
		pushurl = <pushurl>
		push = <refspec>
		fetch = <refspec>

<pushurl> 仅用于推送。它是可选的,默认为 <URL>。推送到远程仓库会影响所有已定义的 pushurl,如果未定义 pushurl 则影响所有已定义的 url。但是,如果定义了多个 url,抓取只会从第一个定义的 url 抓取。

$GIT_DIR/remotes 中的命名文件

您可以选择提供 $GIT_DIR/remotes 中的文件名。此文件中的 URL 将用于访问仓库。当您未在命令行提供 refspec 时,此文件中的 refspec 将默认使用。此文件应具有以下格式:

	URL: one of the above URL formats
	Push: <refspec>
	Pull: <refspec>

Push: 行由 git push 使用,Pull: 行由 git pullgit fetch 使用。可以指定多个 Push:Pull: 行以进行额外的分支映射。

$GIT_DIR/branches 中的命名文件

你可以选择提供 $GIT_DIR/branches 中的文件名称。此文件中的 URL 将用于访问仓库。此文件应具有以下格式:

	<URL>#<head>

<URL> 是必需的;#<head> 是可选的。

根据操作,如果您未在命令行提供 refspec,Git 将使用以下 refspec 之一。<branch>$GIT_DIR/branches 中此文件的名称,<head> 默认为 master

git fetch 使用

	refs/heads/<head>:refs/heads/<branch>

git push 使用

	HEAD:refs/heads/<head>

已配置的远程跟踪分支

您经常通过定期反复从同一个远程仓库抓取来与它交互。为了跟踪此类远程仓库的进度,git fetch 允许您配置 remote.<repository>.fetch 配置变量。

通常此类变量可能如下所示:

[remote "origin"]
	fetch = +refs/heads/*:refs/remotes/origin/*

此配置有两种使用方式:

  • 当不带命令行参数指定要抓取的分支和/或标签运行 git fetch 时(例如 git fetch origingit fetch),remote.<repository>.fetch 的值将用作 refspec——它们指定要抓取哪些引用以及要更新哪些本地引用。上面的示例将抓取 origin 中存在的所有分支(即匹配该值左侧 refs/heads/* 的任何引用),并更新 refs/remotes/origin/* 层次结构中相应的远程跟踪分支。

  • 当在命令行上运行 git fetch 并显式指定要抓取的分支和/或标签时(例如 git fetch origin master),命令行上给定的 <refspec> 决定要抓取什么(例如示例中的 master,它是 master: 的简写,后者又意味着“抓取 master 分支,但我没有在命令行上明确说明要用它更新哪个远程跟踪分支”),并且示例命令将抓取 master 分支。remote.<repository>.fetch 的值决定哪个远程跟踪分支(如果有)被更新。以这种方式使用时,remote.<repository>.fetch 的值在决定抓取什么时没有任何作用(即,当命令行列出 refspec 时,这些值不作为 refspec 使用);它们仅通过充当映射来决定抓取到的引用存储在哪里。

remote.<repository>.fetch 值的后一种用法可以通过在命令行上提供 --refmap=<refspec> 参数来覆盖。

修剪

Git 默认倾向于保留数据,除非明确丢弃;这延伸到保留对远程仓库上已删除分支的本地引用。

如果任其累积,这些陈旧的引用可能会导致在分支变动频繁的大型繁忙仓库中性能下降,并且例如使 git branch -a --contains <commit> 等命令的输出变得不必要的冗长,还会影响任何处理所有已知引用的操作。

这些远程跟踪引用可以一次性删除,使用以下任一命令:

# While fetching
$ git fetch --prune <name>

# Only prune, don't fetch
$ git remote prune <name>

要在您的正常工作流程中修剪引用而无需记住运行它,请在配置中全局设置 fetch.prune,或为每个远程仓库设置 remote.<name>.prune。请参阅 git-config[1]

这里事情变得棘手且更具体。修剪功能实际上不关心分支,而是根据远程仓库的 refspec 来修剪本地 ←→ 远程引用(请参阅上面的 <refspec>已配置的远程跟踪分支)。

因此,如果远程仓库的 refspec 包含例如 refs/tags/*:refs/tags/*,或者您手动运行例如 git fetch --prune <name> "refs/tags/*:refs/tags/*",那么被删除的将不是陈旧的远程跟踪分支,而是远程仓库上不存在的任何本地标签。

这可能不是您所期望的,即您想修剪远程仓库 <name>,但又显式地从它抓取标签,因此当您从它抓取时,您会删除所有本地标签,其中大部分可能最初并非来自远程仓库 <name>

因此,当与 refs/tags/*:refs/tags/* 或任何其他可能将多个远程仓库的引用映射到同一本地命名空间的 refspec 一起使用时,请务必小心。

由于保持与远程仓库的分支和标签同步是一个常见用例,因此可以 साथ --prune 选项与 --prune-tags 选项一起提供,以修剪远程仓库上不存在的本地标签,并强制更新不同的标签。标签修剪也可以通过配置中的 fetch.pruneTagsremote.<name>.pruneTags 启用。请参阅 git-config[1]

--prune-tags 选项等同于在远程仓库的 refspec 中声明 refs/tags/*:refs/tags/*。这可能导致一些看似奇怪的交互:

# These both fetch tags
$ git fetch --no-tags origin 'refs/tags/*:refs/tags/*'
$ git fetch --no-tags --prune-tags origin

之所以不带 --prune 或其配置版本提供时不会报错,是为了配置版本的灵活性,并保持命令行标志与配置版本功能之间的 1:1 映射。

例如,在 ~/.gitconfig 中配置 fetch.pruneTags=true,以便在每次运行 git fetch --prune 时都修剪标签,而不会使每次不带 --prune 运行 git fetch 都产生错误,这是合理的。

使用 --prune-tags 修剪标签在抓取 URL 而不是命名远程仓库时也有效。这些都将修剪在 origin 上未找到的标签:

$ git fetch origin --prune --prune-tags
$ git fetch origin --prune 'refs/tags/*:refs/tags/*'
$ git fetch <url-of-origin> --prune --prune-tags
$ git fetch <url-of-origin> --prune 'refs/tags/*:refs/tags/*'

输出

git fetch”的输出取决于所使用的传输方法;本节描述通过 Git 协议(本地或通过 ssh)和智能 HTTP 协议抓取时的输出。

抓取状态以表格形式输出,每行代表一个引用的状态。每行的格式为:

 <flag> <summary> <from> -> <to> [<reason>]

当使用 --porcelain 时,输出格式旨在供机器解析。与人类可读的输出格式相比,它因此打印到标准输出而不是标准错误。每行的格式为:

<flag> <old-object-id> <new-object-id> <local-reference>

只有在使用 --verbose 选项时,才会显示最新引用的状态。

在紧凑输出模式下(由配置变量 fetch.output 指定),如果 entire <from>entire <to> 中的任一个在另一个字符串中找到,它将用 * 替换另一个字符串中的该部分。例如,master -> origin/master 变为 master -> origin/*

flag

一个字符,指示引用的状态:

(空格)

表示成功抓取的快进;

+

表示成功的强制更新;

-

表示成功修剪的引用;

t

表示成功的标签更新;

*

表示成功抓取的新引用;

!

表示被拒绝或未能更新的引用;以及

=

表示已是最新且无需抓取的引用。

summary

对于成功抓取的引用,摘要以适合作为 git log 参数的形式显示引用的旧值和新值(在大多数情况下是 <old>..<new>,对于强制的非快进更新则是 <old>...<new>)。

from

正在抓取的远程引用的名称,不包括其 refs/<type>/ 前缀。在删除的情况下,远程引用的名称是“(none)”。

to

正在更新的本地引用的名称,不包括其 refs/<type>/ 前缀。

reason

人类可读的解释。对于成功抓取的引用,无需解释。对于失败的引用,会描述失败原因。

示例

  • 更新远程跟踪分支

    $ git fetch origin

    上述命令将远程 refs/heads/ 命名空间中的所有分支复制并存储到本地 refs/remotes/origin/ 命名空间中,除非使用 remote.<repository>.fetch 选项指定了非默认 refspec。

  • 显式使用 refspec

    $ git fetch origin +seen:seen maint:tmp

    这通过分别从远程仓库的 seenmaint 分支抓取,来更新(或在必要时创建)本地仓库中的 seentmp 分支。

    seen 分支即使不是快进也会被更新,因为它带有加号前缀;tmp 则不会。

  • 查看远程分支,无需在本地仓库中配置远程仓库

    $ git fetch git://git.kernel.org/pub/scm/git/git.git maint
    $ git log FETCH_HEAD

    第一个命令从 git://git.kernel.org/pub/scm/git/git.git 仓库抓取 maint 分支,第二个命令使用 FETCH_HEAD 通过 git-log[1] 检查该分支。抓取到的对象最终将由 Git 的内置维护程序移除(参见 git-gc[1])。

安全性

抓取和推送协议并非旨在防止一方从另一方仓库窃取不打算共享的数据。如果您有需要保护免受恶意对等方侵害的私有数据,最佳选择是将其存储在另一个仓库中。这适用于客户端和服务器。特别是,服务器上的命名空间对于读取访问控制无效;您应该只向信任其拥有整个仓库读取访问权限的客户端授予对命名空间的读取访问权限。

已知的攻击向量如下:

  1. 受害者发送“have”行,宣传其拥有的、不明确打算共享但如果对等方也有则可用于优化传输的对象 ID。攻击者选择要窃取的目标对象 ID X 并向 X 发送一个引用,但不需要发送 X 的内容,因为受害者已经拥有它。现在受害者认为攻击者拥有 X,并且随后将 X 的内容发回给攻击者。(这种攻击对于客户端在服务器上执行最直接,通过在客户端有权访问的命名空间中创建指向 X 的引用,然后抓取它。服务器在客户端上执行的最可能方式是“合并”X 到公共分支,并希望用户在此分支上进行额外工作并将其推送回服务器而没有注意到合并。)

  2. 与 #1 类似,攻击者选择要窃取的目标对象 ID X。受害者发送攻击者已有的对象 Y,攻击者虚假声称拥有 X 而没有 Y,因此受害者将 Y 作为相对于 X 的增量发送。此增量向攻击者揭示了 X 中与 Y 相似的区域。

配置

本节中以下所有内容均从 git-config[1] 文档中选择性地包含。内容与彼处相同:

fetch.recurseSubmodules

此选项控制 git fetch(以及 git pull 中的底层抓取)是否会递归抓取到已填充的子模块中。此选项可以设置为布尔值或 on-demand。将其设置为布尔值会更改抓取和拉取的行为:设置为 true 时无条件递归到子模块中,设置为 false 时完全不递归。当设置为 on-demand 时,抓取和拉取将只会在其超项目检索到更新子模块引用的提交时递归到已填充的子模块中。默认为 on-demand,如果设置了 submodule.recurse,则默认为 submodule.recurse 的值。

fetch.fsckObjects

如果设置为 truegit-fetch-pack 将检查所有抓取到的对象。有关检查内容,请参阅 transfer.fsckObjects。默认为 false。如果未设置,则使用 transfer.fsckObjects 的值。

fetch.fsck.<msg-id>

作用类似于 fsck.<msg-id>,但由 git-fetch-pack[1] 而非 git-fsck[1] 使用。详情请参阅 fsck.<msg-id> 文档。

fetch.fsck.skipList

作用类似于 fsck.skipList,但由 git-fetch-pack[1] 而非 git-fsck[1] 使用。详情请参阅 fsck.skipList 文档。

fetch.unpackLimit

如果通过 Git 原生传输抓取的对象数量低于此限制,则这些对象将被解包为松散对象文件。但是,如果接收到的对象数量等于或超过此限制,则接收到的包将作为包存储,并在添加任何缺失的增量基础后。从推送存储包可以使推送操作更快完成,特别是在慢速文件系统上。如果未设置,则使用 transfer.unpackLimit 的值。

fetch.prune

如果为 true,抓取将自动表现为在命令行上给出了 --prune 选项。另请参阅 remote.<name>.prunegit-fetch[1] 的 PRUNING 部分。

fetch.pruneTags

如果为 true,如果尚未设置,抓取将自动表现为在修剪时提供了 refs/tags/*:refs/tags/* refspec。这允许同时设置此选项和 fetch.prune,以维护与上游引用的 1:1 映射。另请参阅 remote.<name>.pruneTagsgit-fetch[1] 的 PRUNING 部分。

fetch.all

如果为 true,抓取将尝试更新所有可用的远程仓库。此行为可以通过传递 --no-all 或显式指定一个或多个要从中抓取的远程仓库来覆盖。默认为 false

fetch.output

控制引用更新状态的打印方式。有效值为 fullcompact。默认值为 full。详情请参阅 git-fetch[1] 的 OUTPUT 部分。

fetch.negotiationAlgorithm

控制在协商服务器要发送的包文件内容时,如何发送关于本地仓库中提交的信息。设置为 "consecutive" 以使用一种算法,该算法遍历连续的提交并检查每个提交。设置为 "skipping" 以使用一种算法,该算法跳过提交以努力更快地收敛,但这可能导致包文件大于必要的大小;或者设置为 "noop" 以完全不发送任何信息,这几乎肯定会导致包文件大于必要的大小,但会跳过协商步骤。设置为 "default" 以覆盖之前所做的设置并使用默认行为。默认通常是 "consecutive",但如果 feature.experimentaltrue,则默认为 "skipping"。未知值将导致 git fetch 出错。

另请参阅 git-fetch[1]--negotiate-only--negotiation-tip 选项。

fetch.showForcedUpdates

设置为 false 以在 git-fetch[1]git-pull[1] 命令中启用 --no-show-forced-updates。默认为 true

fetch.parallel

指定同时并行运行的最大抓取操作数(子模块,或当 git-fetch[1]--multiple 选项生效时的远程仓库)。

值为 0 将给出一些合理的默认值。如果未设置,则默认为 1。

对于子模块,此设置可以使用 submodule.fetchJobs 配置设置来覆盖。

fetch.writeCommitGraph

设置为 true,以便在每次从远程下载包文件的 git fetch 命令后写入提交图。使用 --split 选项,大多数执行将在现有提交图文件之上创建一个非常小的提交图文件。偶尔,这些文件会合并,写入可能需要更长时间。拥有更新的提交图文件有助于许多 Git 命令的性能,包括 git merge-basegit push -fgit log --graph。默认为 false

fetch.bundleURI

此值存储一个 URI,用于在从原始 Git 服务器执行增量抓取之前,从捆绑 URI 下载 Git 对象数据。这类似于 git-clone[1]--bundle-uri 选项的行为。如果提供的捆绑 URI 包含为增量抓取组织的捆绑列表,git clone --bundle-uri 将设置 fetch.bundleURI 值。

如果您修改此值且您的仓库有 fetch.bundleCreationToken 值,则在从新的捆绑 URI 抓取之前,请删除该 fetch.bundleCreationToken 值。

fetch.bundleCreationToken

当使用 fetch.bundleURI 从使用“creationToken”启发式方法的捆绑列表中增量抓取时,此配置值存储已下载捆绑的最大 creationToken 值。此值用于防止将来下载捆绑,如果发布的 creationToken 不严格大于此值。

creationToken 值由提供特定捆绑 URI 的提供者选择。如果您修改 fetch.bundleURI 的 URI,则请务必在抓取之前删除 fetch.bundleCreationToken 的值。

BUG

使用 --recurse-submodules 只能抓取本地存在的子模块(例如在 $GIT_DIR/modules/ 中)中的新提交。如果上游添加了一个新的子模块,该子模块在通过 git submodule update 克隆之前无法被抓取。这预计将在未来的 Git 版本中修复。

另请参阅

GIT

Git[1] 套件的一部分

scroll-to-top