简体中文 ▾ 主题 ▾ 最新版本 ▾ git-fetch 上次更新于 2.53.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])使用。

选项

--all
--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 将仅报告从给定端点 (tips) 可达的提交。当用户知道哪个本地引用可能与正在获取的上游引用有共同提交时,这对于加速获取非常有用。

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

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

另请参阅 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 配置选项。

--write-fetch-head
--no-write-fetch-head

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

-f
--force

git fetch<src>:<dst> 引用规范一起使用时,它可能会拒绝更新本地分支,如下文 <refspec> 部分所述。此选项会强制覆盖该检查。

-k
--keep

保留下载的包。

--multiple

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

--auto-maintenance
--no-auto-maintenance
--auto-gc
--no-auto-gc

在结束时运行 git maintenance run --auto,以便在需要时执行自动仓库维护。此功能默认启用。

--write-commit-graph
--no-write-commit-graph

在获取后编写提交图 (commit-graph)。这会覆盖配置设置 fetch.writeCommitGraph

--prefetch

修改配置好的引用规范,将所有引用放入 refs/prefetch/ 命名空间。参见 git-maintenance[1] 中的 prefetch 任务。

-p
--prune

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

更多详情请参阅下文的修剪 (PRUNING) 部分。

-P
--prune-tags

在获取之前,如果启用了 --prune,则删除远程仓库上已不存在的任何本地标签。应谨慎使用此选项,与 --prune 不同,它会删除已创建的任何本地引用(本地标签)。此选项是同时提供显式标签引用规范和 --prune 的简写,请参阅其文档中的讨论。

更多详情请参阅下文的修剪 (PRUNING) 部分。

-n
--no-tags

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

--refetch

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

--refmap=<refspec>

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

-t
--tags

从远程获取所有标签(即,将远程标签 refs/tags/* 获取到同名的本地标签中),此外还获取其他原本会被获取的内容。单独使用此选项不会使标签被修剪,即使使用了 --prune(但如果标签也是明确引用规范的目标,它们仍可能被修剪;参见 --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 <n>
--jobs=<n>

并行执行各种形式的获取,每次最多 <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>

在提示信息(如“Fetching submodule foo”)中显示的路径前加上 <path>。此选项在递归子模块时供内部使用。

--recurse-submodules-default=(yes|on-demand)

此选项在内部用于临时为 --recurse-submodules 选项提供一个非负的默认值。所有其他配置 fetch 子模块递归的方法(例如 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

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

-v
--verbose

显示详细信息。

--progress

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

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

使用协议版本 2 通信时,将给定的字符串传输到服务器。给定的字符串不得包含 NULLF 字符。服务器对服务器选项的处理(包括未知选项)取决于服务器。当给出多个 --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>

作为 fetch 或 pull 操作来源的“远程”仓库。此参数可以是 URL(参见下文的 GIT URLS 部分)或远程仓库的名称(参见下文的 REMOTES 部分)。

<group>

一个名称,对应配置文件中 remotes.<group> 的值所引用的仓库列表。(参见 git-config[1])。

<refspec>

指定要获取哪些引用以及更新哪些本地引用。当命令行中没有出现 <refspec> 时,将从 remote.<repository>.fetch 变量中读取要获取的引用(参见下文的 配置远程跟踪分支)。

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

<refspec><src> 中可能包含一个 *,表示简单的模式匹配。这种引用规范就像一个能匹配任何符合该模式引用的通配符。模式 <refspec><src><dst> 中必须且只能包含一个 *。它会通过将 <dst> 中的 * 替换为 <src> 匹配到的内容,来将引用映射到目标位置。

如果引用规范前缀为 ^,它将被解释为负向引用规范。这种引用规范不是指定要获取或更新哪些引用,而是指定要排除哪些引用。如果一个引用至少匹配一个正向引用规范,且不匹配任何负向引用规范,则认为该引用匹配。负向引用规范在限制模式引用规范的范围时非常有用,可以排除特定的引用。负向引用规范本身也可以是模式引用规范。但是,它们只能包含 <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/* 的任何更新都会在没有引用规范中的 +(或 --force)的情况下被接受。在获取时,我们曾宽容地将所有来自远程的标签更新视为强制获取。从 Git 2.20 版本开始,获取以更新 refs/tags/* 的方式与推送相同。即,如果没有引用规范中的 +(或 --force),任何更新都会被拒绝。

与使用 git-push[1] 推送不同,refs/{tags,heads}/* 之外的任何更新都会在没有引用规范中的 +(或 --force)的情况下被接受,无论是将树对象换成 Blob 对象,还是将一个提交换成另一个不以旧提交为祖先的提交等。

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

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

注意
当你想要获取的远程分支已知会定期回滚并重置 (rebased) 时,预期的结果是它的新顶端将不再是其旧顶端的后代(如你上次获取时存储在远程跟踪分支中的那样)。在这种情况下,你应该使用 + 号来表示此类分支需要非快进更新。没有办法确定或声明某个分支会以这种行为在仓库中提供;用户在拉取时必须知道这是该分支的预期使用模式。
--stdin

除了作为参数提供的引用规范外,还从标准输入中读取引用规范,每行一个。不支持 "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)也将接受一个合适的 bundle 文件。参见 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。

远程仓库

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

  • 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> 是可选的。

根据操作的不同,如果你在命令行中没有提供引用规范,git 将使用以下引用规范之一。<branch> 是此文件在 $GIT_DIR/branches 中的名称,而 <head> 默认为 master

git fetch 使用

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

git push 使用

	HEAD:refs/heads/<head>

上游分支

Git 中的分支可以选择性地拥有一个上游远程分支。Git 默认使用上游分支进行远程操作,例如

  • 它是 `git pull` 或无参数的 `git fetch` 的默认设置。

  • 它是无参数的 `git push` 的默认设置,但有一些例外。例如,您可以使用 `branch.<name>.pushRemote` 选项将推送到与您拉取的远程仓库不同的仓库,并且默认情况下使用 `push.default=simple`,您配置的上游分支名称必须相同。

  • 各种命令,包括 `git checkout` 和 `git status`,将显示自您从当前分支分叉以来,您的当前分支和上游分支分别增加了多少提交,例如“Your branch and *origin/main* have diverged, and have 2 and 3 different commits each respectively”。

上游存储在 .git/config 的 “remote” 和 “merge” 字段中。例如,如果 main 的上游是 origin/main

[branch "main"]
   remote = origin
   merge = refs/heads/main

您可以使用 `git push --set-upstream <remote> <branch>` 显式设置上游分支,但 Git 经常会自动为您设置上游分支,例如

  • 当您克隆一个仓库时,Git 会自动为默认分支设置上游分支。

  • 如果您的 `push.autoSetupRemote` 配置选项已设置,`git push` 将在您第一次推送分支时自动设置上游分支。

  • 使用 `git checkout <branch>` 检出远程跟踪分支将自动创建一个同名本地分支,并将其上游设置为远程分支。

注意
上游分支有时被称为“跟踪信息”,例如“设置分支的跟踪信息”。

配置远程跟踪分支

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

通常,这样的变量可能看起来像这样

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

此配置以两种方式使用

  • 当运行 git fetch 且未在命令行中指定要获取的分支和/或标签时(例如 git fetch origingit fetch),remote.<repository>.fetch 的值被用作引用规范——它们指定要获取哪些引用以及更新哪些本地引用。上述示例将获取 origin 中存在的所有分支(即匹配值左侧 refs/heads/* 的任何引用),并更新 refs/remotes/origin/* 层级中对应的远程跟踪分支。

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

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

修剪 (PRUNING)

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>配置远程跟踪分支)。

因此,如果远程仓库的引用规范包含(例如)refs/tags/*:refs/tags/*,或者你手动运行了(例如)git fetch --prune <name> "refs/tags/*:refs/tags/*",那么被删除的将不是过时的远程跟踪分支,而是任何在远程仓库中不存在的本地标签。

这可能不是你预期的结果。例如,你想要修剪远程仓库 <name>,但也显式地从中获取标签,结果当你从中获取时,你删除了所有的本地标签,而这些标签中的大多数最初可能根本不是来自 <name> 远程仓库。

所以在使用像 refs/tags/*:refs/tags/* 这样的引用规范,或者任何可能将来自多个远程仓库的引用映射到同一个本地命名空间的引用规范时,要格外小心。

由于同时保持远程分支和标签的最新状态是一个常见的用例,因此可以在使用 --prune 的同时提供 --prune-tags 选项,以修剪远程不存在的本地标签,并强制更新那些不同的标签。也可以通过配置中的 fetch.pruneTagsremote.<name>.pruneTags 来启用标签修剪。参见 git-config[1]

--prune-tags 选项等同于在远程引用规范中声明了 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(或其配置版本)的情况下使用此选项不会报错,这是为了配置版本的灵活性,并保持命令行标志的行为与配置版本的行为之间的一一对应关系。

例如,在 ~/.gitconfig 中配置 fetch.pruneTags=true 是合理的,这样每当运行 git fetch --prune 时都会修剪标签,而不会使每次不带 --prunegit fetch 调用都报错。

在使用 URL 而非命名远程仓库获取时,使用 --prune-tags 修剪标签同样有效。以下操作都将修剪在 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)和 Smart HTTP 协议获取时的输出。

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

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

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

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

仅当使用 --verbose 选项时,才会显示已是最新的 (up-to-date) 引用的状态。

在紧凑输出模式(通过配置变量 fetch.output 指定)下,如果 <from><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 选项来指定非默认的引用规范。

  • 显式使用引用规范

    $ 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])。

安全性

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

已知的攻击向量如下:

  1. 受害者发送“have”行,广告它拥有但未明确打算共享的对象 ID,这些对象 ID 可用于优化传输,前提是对方也拥有它们。攻击者选择一个对象 ID X 来窃取并发送一个指向 X 的 ref,但不需要发送 X 的内容,因为受害者已经拥有它。现在受害者认为攻击者拥有 X,并且之后会将 X 的内容发送回攻击者。(此攻击最容易由客户端对服务器执行,通过在客户端有权访问的命名空间中创建指向 X 的 ref,然后获取它。服务器对客户端执行此操作的最可能方式是“合并”X 到一个公共分支,并希望用户在此分支上进行更多工作并将其推回服务器,而不会注意到合并。)

  2. 与 #1 类似,攻击者选择一个对象 ID X 来窃取。受害者发送一个攻击者已拥有的对象 Y,攻击者谎称拥有 X 而不是 Y,因此受害者将 Y 作为 X 的增量发送。增量向攻击者揭示了 X 中与 Y 相似的区域。

配置

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

fetch.recurseSubmodules

此选项控制 git fetch(以及 git pull 中底层的 fetch)是否会递归地获取到已检出的子模块中。此选项可以设置为布尔值或 on-demand。设置为 true 时,fetch 和 pull 会无条件地递归进入子模块;设置为 false 则完全不递归。设置为 on-demand 时,仅当主项目检索到更新子模块引用的提交时,fetch 和 pull 才会递归进入已检出的子模块。默认为 on-demand,如果设置了 submodule.recurse,则默认为该值。

fetch.fsckObjects

如果设置为 true,git-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 原生传输获取的对象数量低于此限制,则对象将被解包为松散的对象文件。但是,如果接收到的对象数量达到或超过此限制,则在添加任何缺失的 delta 基准后,接收到的包将作为包文件存储。存储来自推送的包可以使推送操作更快完成,尤其是在慢速文件系统上。如果未设置,则改用 transfer.unpackLimit 的值。

fetch.prune

如果为 true,fetch 的行为将自动等同于在命令行中给出了 --prune 选项。另请参见 remote.<name>.prunegit-fetch[1] 的 PRUNING 部分。

fetch.pruneTags

如果为 true,且尚未设置,则 fetch 在修剪时将自动等同于提供了 refs/tags/*:refs/tags/* 引用规范。这允许同时设置此选项和 fetch.prune 以保持与上游引用的一一对应。另请参见 remote.<name>.pruneTagsgit-fetch[1] 的 PRUNING 部分。

fetch.all

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

fetch.output

控制如何打印引用更新状态。有效值为 full(完整)和 compact(紧凑)。默认值为 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 命令后编写提交图 (commit-graph)。使用 --split 选项后,大多数执行将在现有提交图文件之上创建一个非常小的提交图文件。偶尔这些文件会合并,写入时间可能会更长。拥有更新的提交图文件有助于提高许多 Git 命令的性能,包括 git merge-basegit push -fgit log --graph。默认为 false

fetch.bundleURI

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

如果你修改了此值且你的仓库具有 fetch.bundleCreationToken 值,请在从新 bundle URI 获取之前移除该 fetch.bundleCreationToken 值。

fetch.bundleCreationToken

当使用 fetch.bundleURI 从使用“creationToken”启发式的 bundle 列表中进行增量获取时,此配置值存储已下载 bundle 的最大 creationToken 值。此值用于防止在未来通告的 creationToken 不严格大于此值时下载 bundle。

创建令牌值由提供特定 bundle URI 的服务商选择。如果你修改了 fetch.bundleURI 处的 URI,请务必在获取前移除 fetch.bundleCreationToken 的值。

BUG

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

另请参阅

GIT

Git[1] 套件的一部分