简体中文 ▾ Topics ▾ Latest version ▾ git-fetch last updated in 2.54.0

名称

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

概述

git fetch' [<选项>] [<仓库> [<引用规范>…​]]
git fetch' [<选项>] <组>
git fetch' --multiple [<选项>] [(<仓库> | <组>)…​]
git fetch' --all [<选项>]

描述

从一个或多个其它仓库获取分支和/或标签(统称为 "refs"),以及完成其历史所需的对象。 远程跟踪的分支会被更新(关于控制这种行为的方法,请参见下面 <引用规范> 的描述)。

默认情况下,任何指向被获取的历史的标签也会被获取;其效果是获取指向你感兴趣的分支的标签。 这个默认行为可以通过使用 --tags 或 --no-tags 选项或者配置 remote.<远程仓库名称>.tagOpt 来改变。 通过使用明确获取标签的引用规范,你也可以获取那些没有指向你感兴趣的分支的标签。

git fetch 可以从一个命名的仓库或 URL 中获取,或者如果给定了 <组> 并且在配置文件中有 remotes.<组> 项,则可以同时从几个仓库获取。 (参见 git-config[1])。

当没有指定远程仓库时,默认情况下将使用 origin 远程仓库,除非有一个上游分支配置在当前分支上。

被获取的引用名称,以及它们所指向的对象名称,被写到 .git/FETCH_HEAD。 这些信息可以被脚本或其他 git 命令使用,比如git-pull[1]

选项

--all
--no-all

获取所有远程控制。这将覆盖配置变量 fetch.all

-a
--append

.git/FETCH_HEAD 的现有内容中添加获取的引用名称和对象名称。 如果没有这个选项,.git/FETCH_HEAD 中的旧数据将被覆盖。

--atomic

使用一个原子事务来更新本地索引。要么所有的引用都被更新,要么在出错时,没有引用被更新。

--depth <深度>

限制从每个远程分支历史的顶端获取指定数量的提交。如果获取的是由 git clone 创建的 浅层 仓库,并使用 --depth=<depth> 选项(见 git-clone[1]),则加深或缩短历史,达到指定数量的提交。深化后的提交的标签不会被获取。

--deepen=<深度>

与—​depth类似,只是它指定了从当前浅层边界开始的提交数量,而不是从每个远程分支历史的顶端开始。

--shallow-since=<日期>

加深或缩短浅层仓库的历史,包括<日期>之后所有可触及的提交。

--shallow-exclude=<引用>

深化或缩短浅层仓库的历史,以排除从指定的远程分支或标签中可以到达的提交。 这个选项可以指定多次。

--unshallow

如果源仓库是完整的,将浅层资源库转换为完整的仓库,消除浅层仓库带来的所有限制。

如果源仓库是浅层的,尽可能多的获取,使当前仓库的历史与源仓库相同。

--update-shallow

默认情况下,当从浅层仓库获取时,git fetch 会拒绝需要更新 .git/shallow 的引用。这个选项更新了 .git/shallow 并接受这样的引用。

--negotiation-tip=<提交|通配符>

默认情况下,Git 会向服务器报告从所有本地引用中可触及的提交,以寻找共同的提交,试图减少待接收的打包文件的大小。如果指定的话,Git将只报告从给定提示中的可达提交。 当用户知道哪个本地引用可能与被获取的上游引用有共同的提交时,这会加快获取文件的速度。

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

这个选项的参数可以是一个引用名称的通配符,一个引用,或者一个提交的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] 中的输出部分。

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

--filter=<过滤规范>

使用部分克隆功能,请求服务器根据给定的对象过滤器发送可达对象的子集。使用 --filter 时,提供的 <filter-spec> 用于部分获取。

如果使用 --filter=auto,过滤规格将通过合并服务器为客户端接受的承诺远程仓库所通告的过滤规格来自动确定(参见 gitprotocol-v2[5]git-config[1] 中的 promisor.acceptFromServer 配置选项)。

有关所有其他可用过滤规格的详细信息,请参见 git-rev-list[1] 中的 --filter=<filter-spec> 选项。

例如,--filter=blob:none 将过滤掉所有 blob(文件内容)直到 Git 需要它们。另外,--filter=blob:limit=<size> 将过滤掉大小至少为 <size> 的所有 blob。

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

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

-f
--force

正如讨论的那样,当 git fetch<源>:<目标> 引用规范一起使用时,它可能会拒绝更新本地分支 这个选项覆盖了该检查。

-k
--keep

保存下载的包。

--multiple

允许指定几个 <仓库> 和 <group> 参数。不可以指定 <引用规范>。

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

在最后运行 git maintenance run --auto,以在需要时执行自动仓库维护。(与 "--[no-]auto-gc" 选项效果一样。)这个功能默认启用。

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

在获取后写一个提交图。这会覆盖 fetch.writeCommitGraph 配置选项。

--prefetch

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

-p
--prune

在获取之前,删除任何不再存在于远程的远程跟踪引用。 如果只是因为默认的标签自动跟踪或者因为 --tags 选项而获取标签,则不需要剪枝。 然而,如果标签是由于明确的引用规范(无论是在命令行还是在远程配置中,例如,如果远程是用 --mirror 选项克隆的)而被获取的,那么它们也会被剪除。提供 --prune-tags 是提供标签引用规范的速记方法。

更多细节见下面的 剪枝 部分。

-P
--prune-tags

在获取之前,如果 --prune 被启用,则删除任何不再存在于远程的本地标签。这个选项应该更谨慎使用,与`--prune`不同,它将删除任何已经创建的本地引用(本地标签)。这个选项是与`--prune`一起提供明确的标签引用规范的速记形式,见其文档中关于这个的讨论。

更多细节见下面的 剪枝 部分。

-n
--no-tags

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

--refetch

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

--refmap=<引用规范>

当获取命令行上列出的引用时,使用指定的引用规范(可以是多个)来映射引用到远程跟踪分支,而不是远程仓库的 remote.*.fetch 配置变量的值。 为 --refmap 选项提供一个空的 <引用规范> 会导致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>

将所有形式的 fetch 并行化,每次最多运行 <n> 个任务。

值为 0 将使用某个合理的默认值。

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

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

--no-recurse-submodules

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

--set-upstream

如果远程被成功获取,添加上游(跟踪)引用,由无参数的 git-pull[1] 和其他命令使用。更多信息,见 git-config[1] 中的 branch.<名称>.mergebranch.<名称>.remote

--submodule-prefix=<路径>

将 <路径> 添加到信息性消息中打印的路径,例如“获取子模块 foo”。递归子模块时在内部使用此选项。

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

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

-u
--update-head-ok

默认情况下,"git fetch" 拒绝更新与当前分支相对应的头部。 这个标志禁用了这种检查。 这纯粹是为了让 git pullgit fetch 沟通的内部使用,除非你正在实现你自己的上层命令,否则你不应该使用它。

--upload-pack <upload-pack>

当给出时,并且要获取的仓库是由 git fetch-pack 处理的,--exec=<upload-pack> 被传递到命令中,为另一端运行的命令指定非默认路径。

-q
--quiet

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

-v
--verbose

详细日志。

--progress

当标准错误流连接到终端时,除非指定了 -q,否则默认情况下会在标准错误流上报告进展状态。即使标准错误流没有指向终端,这个标志也会强制显示进度状态。

-X <选项>
--server-option=<选项>

使用协议版本2进行通信时,将给定的字符串传输到服务器。给定的字符串不得包含NUL或LF字符。服务器对服务器选项(包括未知选项)的处理是取决于服务器。当给出多个`--server-option=<option>`时,它们都按照命令行中列出的顺序发送到另一端。

--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 地址。

<仓库>

作为获取或拉动操作的来源的 "remote" 仓库。 这个参数可以是一个 URL(见下面 GIT URLS 一节),也可以是一个远程仓库的名称(见下面 远程 一节)。

<组>

指向仓库列表的名称,作为配置文件中 remotes.<组> 的值。 (参见 git-config[1])。

<引用规范>

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

<引用规范> 参数的格式是一个可选的加号 + ,后面是源 <src>,后面是冒号 :,后面是目标引用 <dst>。 当 <dst> 为空时,冒号可以被省略。 <src> 通常是一个引用,但它也可以是一个完全拼写的十六进制对象名称。

一个 <引用规范> 可以在其<src>中包含一个`*'来表示一个简单的模式匹配。这样的 refspec 的功能就像一个 glob,可以匹配任何具有相同前缀的 ref。匹配 <引用规范> 必须在 <src> 和 <dst> 中都有一个 *。它将通过把 * 替换成从源头匹配的内容来把引用映射到目的地。

如果一个 引用规范的前缀是 ^,它将被解释为一个负向引用规范。这样的引用规范不是指定要获取哪些引用或更新哪些本地引用,而是指定要排除的引用。如果一个引用至少与一个正向引用规范匹配,并且不与任何负向引用规范匹配,那么该引用将被视为匹配。负向引用规范可以用来限制引用规范匹配的范围,使其不包括特定的引用。 负向引用规范本身可以是模式引用规范。然而,它们可能只包含一个 <src>,而不指定一个 <dst>。完全拼出的十六进制对象名称也不被支持。

tag <标签>`的意思与`refs/tags/<标签>:refs/tags/<标签> 相同;它要求获取到给定标签的所有内容。

获取与 <src> 相匹配的远程引用,如果 <dst> 不是一个空字符串,就会尝试更新与之相匹配的本地引用。

该更新是否允许不使用 --force,取决于它被获取的引用命名空间、被获取的对象的类型,以及该更新是否被认为是一个快速合并。一般来说,获取的规则与推送的规则相同,参见 git-push[1]<引用规范>...' 部分。以下是 `git fetch 特殊规则的例外情况。

在 Git 2.20 版本之前,与使用 git-push[1] 推送时不同,任何对 refs/tags/* 的更新都会被接受,在引用规范中没有 +(或`--force`)。在获取的时候,我们把所有来自远程的标签更新都视为强制获取。 从 Git 2.20 版本开始,获取更新 refs/tags/* 的方式与推送时相同。也就是说,任何在引用规范中没有 + 的更新都会被拒绝(或`--force`)。

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

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

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

Note
当你想获取的远程分支已知会被定期回溯和重定向时,预计它的新提示不会是其先前提示的后代(如你上次获取时存储在远程跟踪分支中的提示)。 你应该使用 + 号来表示对这类分支需要进行非快速合并式更新。 没有办法确定或声明一个分支将以这种行为在仓库中提供;拉取的用户只是必须知道这是一个分支的预期使用模式。
--stdin

从stdin中读取引用规范,每行一个,除了作为参数提供的那些之外。不支持 "标签 <名称>" 格式。

GIT 地址

通常,地址包含有关传输协议,远程服务器的地址以及仓库路径的信息。对于某些传输协议,一些信息可能会缺失。

Git 支持 ssh,git,http 和 https 协议(此外,可以使用 ftp 和 ftps 进行获取,但这效率低下且不建议使用;请勿使用)。

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

以下是上述几个传输协议的格式:

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

  • git://<主机地址>[:<端口>]/<Git 仓库路径>

  • http[s]://<主机地址>[:<端口>]/<Git 仓库路径>

  • ftp[s]://<主机地址>[:<端口>]/<Git 仓库路径>

ssh 协议也可以使用类似 scp 的语法:

  • [<用户名>@]<主机地址>:/<Git 仓库路径>

仅当第一个冒号之前没有斜杠时才能识别此语法。这有助于区分包含冒号的本地路径。例如,可以将本地路径 foo:bar 指定为绝对路径,或者将 ./foo:bar 指定为绝对路径,以避免被误识别为 ssh url。

ssh 和 git 协议还支持 ~<用户名> 扩展:

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

  • git://<主机地址>[:<端口>]/~<用户名>/<Git 仓库路径>

  • [<用户名>@]<主机地址>:~<用户名>/<Git 仓库路径>

对于本地仓库(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-<传输方式> 远程帮助程序(如果存在)。要显式请求远程帮助程序,可以使用以下语法:

  • <传送>::<地址>

其中,<地址> 可以是路径,服务器与路径,也可以是可被调用的特定远程帮助程序识别的类似于网页地址的任意字符串。有关详细信息,请参阅 gitremote-helpers[7]

如果存在大量类似名称的远程仓库,并且您要为其使用不同的格式(这样,您使用的地址将被重写为有效的地址),则可以创建以下形式的配置:

	[url "<实际基础网址>"]
		insteadOf = <其他基础网址>

例如,有如下:

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

诸如 "work:repo.git" 或 "host.xz:/path/to/repo.git" 的地址会在任何类似于 "git://git.host.xz/repo" 地址的上下文中重写。

如果要重写仅用于推送的地址,可以创建表单的配置部分:

	[url <实际基础网址>"]
		pushInsteadOf = <其他基础网址>

例如,有如下:

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

类似于 "git://example.org/path/to/repo.git" 的地址会被重写为 "ssh://example.org/path/to/repo.git",用于推送。但拉取代码时仍然使用原始的地址。

REMOTES

可以用下面的一个名称代替URL作为`<repository>`的参数:

  • 一个远程的配置文件在此仓库的git配置文件: $GIT_DIR/config

  • 这个文件在`$GIT_DIR/remotes`目录下,或者

  • 这个文件在`$GIT_DIR/branches`目录下。

所有这些也允许你从命令行中省略refspec,因为它们都包含一个git默认使用的refspec。

在配置文件中命名为 remote

你可以选择提供你之前用 git-remote[1]git-config[1] 或甚至通过手动编辑 $GIT_DIR/config 文件配置的远程名称。 这个远程的 URL 将被用来访问仓库。 当你没有在命令行上提供引用规范时,这个远程仓库的引用规范将被默认使用。 配置文件中的条目会像这样:

	[remote "<名称>"]
		url = <地址>
		pushurl = <推送地址>
		push = <引用规范>
		fetch = <引用规范>

<推送地址> 仅用于推送。它是可选的,默认为 <URL>。向远程推送会影响所有定义的推送urls,如果没有定义推送urls,则推送到所有定义的url。然而,如果定义了多个 URL,fetch 将只从第一个定义的 URL 获取。

$GIT_DIR/remotes 中的命名文件

你可以选择提供 $GIT_DIR/remotes 中的文件名。 这个文件中的 URL 将被用来访问仓库。 当你没有在命令行上提供引用规范时,该文件中的引用规范将被作为默认使用。 这个文件应该有以下格式:

	URL: one of the above URL format
	Push: <引用规范>
	Pull: <引用规范>

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

$GIT_DIR/branches 中的命名文件

你可以选择提供 $GIT_DIR/branches 中的文件名。 这个文件中的 URL 将被用来访问仓库。 这个文件应该有以下格式:

	<URL>#<head>

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

根据不同的操作,如果你没有在命令行上提供一个引用规范,git 会使用以下其中一个。 <分支> 是该文件在 $GIT_DIR/branches 中的名称,<头分支> 默认为 master

git fetch 使用:

	refs/heads/<头分支>:refs/heads/<分支>。

git push 使用:

	HEAD:refs/heads/<头分支>。

上游分支

Git 中的分支可以选择关联一个上游远程分支。对于远程操作,Git 默认会使用该上游分支,例如:

  • 它是无参数执行 git pullgit fetch 时的默认目标。

  • 除少数例外情况外,它也是无参数执行 git push 时的默认目标。例如,你可以使用 branch.<name>.pushRemote 选项,将代码推送到与拉取时不同的远程;并且在默认的 push.default=simple 模式下,你所配置的上游分支必须与当前分支同名。

  • 包括 git checkoutgit 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> 检出远程跟踪分支时,会自动创建同名本地分支,并将该远程分支设置为其上游。

Note
上游分支有时也被称为 “tracking information”(跟踪信息),例如“set the branch’s tracking information”。

配置的远程跟踪分支

你通过经常定期和重复地从同一个远程仓库取东西来与之互动。 为了跟踪这种远程仓库的进度,git fetch 允许你配置 remote.<仓库>.fetch 配置变量。

一般来说,这种变量可能看起来像这样:

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

这种配置有两种使用方式:

  • git fetch 运行时,没有在命令行中指定要取哪些分支和/或标签,例如 git fetch origingit fetchremote.<仓库>.fetch 值被用作引用规范——它们指定要取哪些引用和要更新哪些本地引用。 上面的例子将获取所有存在于 origin 中的分支(即任何与数值左边的`refs/heads/*相匹配的引用),并更新 `refs/remotes/origin/* 层次结构中相应的远程跟踪的分支。

  • git fetch 运行时,命令行上有明确的要取的分支和/或标签,例如 git fetch origin master,命令行上给出的所有 <引用规范> 决定了要取的是什么(例如例子中的 mastermaster: 的简称,意思是 "获取 master 分支,但我没有明确说要在命令行中更新哪个远程跟踪分支"),而这个例子的命令将「只」获取 master 分支。 remote.<仓库>.fetch`值决定了哪个远程跟踪分支(如果有的话)被更新。 当以这种方式使用时,`remote.<仓库>.fetch 值对决定获取什么没有任何影响(即当命令行列出引用规范时,这些值不会被用作引用规范);它们只是通过作为一个映射来决定获取的引用被存储在哪里。

后者对 remote.<仓库>.fetch 值的使用可以通过在命令行中给出 --refmap=<引用规范> 参数去覆盖。

剪枝

Git默认保留数据,除非它被明确地扔掉;这延伸到保留对远程分支的本地引用,而这些分支本身已经被删除。

如果任其积累,这些陈旧的引用可能会使大型繁忙仓库的性能变差,例如,使 git branch -a --contains <提交> 等命令的输出不必要地冗长,以及影响其他任何与完整的已知引用有关的工作。

这些远程跟踪引用可以通过以下两种方式一次性删除:

# 在获取的时候
$ git fetch --prune <名称>

# 只修剪,不获取
$ git remote prune <名称>

要把修剪引用作为正常工作流程的一部分,而不需要记住运行该程序,可以在全局设置 fetch.prune,或者在配置中设置 remote.<名称>.prune,为每个远程仓库进行设置。见git-config[1]

这里是事情变得棘手和更具体的地方。修剪功能实际上并不关心分支,相反,它将修剪本地←→远程引用,作为远程的引用规范的函数(见上面的`<引用规范>`和上面的配置远程跟踪分支)。

因此,如果远程的引用规范包括例如 refs/tags/*:refs/tags/*`这样的规范,或者你手动运行例如 `git fetch --prune <名称> "refs/tags/*:refs/tags/*",那么被删除的就不是过时的远程跟踪分支,而是远程上不存在的任何本地标签。

这可能不是你所期望的,即你想修剪远程的 <名称>,但也明确地从它那里获取标签,所以当你从它那里获取时,你会删除所有的本地标签,其中大部分可能首先不是来自远程的 <名称>

因此,当与 refs/tags/*:refs/tags/* 这样的引用规范一起使用时要小心,或者任何其他可能将多个远程的引用映射到同一本地命名空间的引用规范。

由于在远程保持最新的分支和标签是一个常见的使用情况,--prune-tags 选项可以和 --prune 一起使用,以修剪在远程不存在的本地标签,并强制更新那些不同的标签。标签修剪也可以通过配置中的 fetch.pruneTagsremote.<名称>.pruneTags 启用。见git-config[1]

--prune-tags 选项相当于在远程的引用规范中声明 refs/tags/*:refs/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 时修剪标签,这是很合理的,不会使每次调用 git fetch 而没有 --prune 时都出现错误。

使用 --prune-tags 修剪标签,在获取一个URL而不是一个命名的远程时也能发挥作用。这些都会修剪在原点没有发现的标签:

$ git fetch origin --prune --prune-tags
$ git fetch origin --prune 'refs/tags/*:refs/tags/*'
$ git fetch <origin 的地址> --prune --prune-tags
$ git fetch <origin 的 地址> --prune 'refs/tags/*:refs/tags/*'

输出

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

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

 <标志> <概述> <起始> -> <结束> [<原因>]

当使用 --porcelain 时,输出格式的目的是让机器可以解析。与人类可读的输出格式不同,它将打印到标准输出而不是标准错误。每一行都是这样的形式:

<标志> <旧对象ID> <新对象ID> <本地引用>

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

在紧凑输出模式下,通过配置变量 fetch.output 指定,如果在另一个字符串中发现整个 <起点><终点>,它将被替换成另一个字符串中的 *。例如,master -> origin/master 变成 master -> origin/*

标志

表示引用状态的单个字符:

(空格)

表示成功的快速合并;

+

表示一个成功的强制更新;

-

表示成功修剪引用;

t

表示成功更新标签;

*

表示成功获取新引用;

!

表示被拒绝或更新失败的引用;以及

=

表示一个最新的、不需要获取的引用。

概述

对于一个成功获取的引用,摘要以适合作为 git log 参数的形式显示该引用的新旧值(在大多数情况下是 <旧>..<新>,对于强制非快速合并是 <旧>...<新>)。

起始

被获取的远程引用的名称,减去其`refs/<类型>/`前缀。在删除的情况下,远程引用的名称是 "(none)"。

结束

被更新的本地引用的名称,去掉其 refs/<类型>/ 前缀。

原因

一个人类可读的解释。如果是成功获取的引用,不需要解释。对于失败的引用,将描述失败的原因。

实例

  • 更新远程追踪的分支:

    $ git fetch origin

    上述命令从远程的 refs/heads/ 命名空间复制所有分支,并存储到本地的 refs/remotes/origin/ 命名空间,除非使用 remote.<仓库>.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 的仓库中获取 maint 分支,第二条命令使用 FETCH_HEADgit-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 的d elta,delta 向攻击者显示了 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 基对象之后,会将收到的 pack 作为 pack 存储。将 push 收到的 pack 直接存储为 pack 可使 push 更快完成,尤其是在较慢的文件系统上。如果未设置,则改用 transfer.unpackLimit 的值。

fetch.prune

如果为 true,fetch 会自动表现得如同命令行提供了 --prune 选项。另见 remote.<name>.prunegit-fetch[1] 的 PRUNING 章节。

fetch.pruneTags

如果为 true,且尚未设置相关 refspec,则 fetch 在 prune 时会自动表现得如同提供了 refs/tags/*:refs/tags/* 这个 refspec。这样可以同时设置该选项和 fetch.prune,以保持与上游 ref 的 1:1 映射。另见 remote.<name>.pruneTagsgit-fetch[1] 的 PRUNING 章节。

fetch.all

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

fetch.output

控制 ref 更新状态的打印方式。有效值为 fullcompact。默认值为 full。详情参见 git-fetch[1] 的 OUTPUT 章节。

fetch.negotiationAlgorithm

控制在协商服务器要发送的 packfile 内容时,如何发送本地仓库中提交的信息。设为 consecutive 时,使用遍历连续提交并逐个检查的算法。设为 skipping 时,使用跳过部分提交以更快收敛的算法,但可能产生比必要更大的 packfile;设为 noop 则完全不发送任何信息,这几乎肯定会导致 packfile 大于必要大小,但会跳过协商步骤。设为 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

指定一次可并行运行的最大 fetch 操作数(对子模块,或在 git-fetch[1]--multiple 选项生效时对远程)。

值为 0 时会给出某个合理的默认值。若未设置,则默认值为 1。

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

fetch.writeCommitGraph

设为 true 时,在每次 git fetch 从远程下载 pack-file 后都写入 commit-graph。使用 --split 选项时,大多数执行只会在现有 commit-graph 文件之上创建一个很小的 commit-graph 文件。偶尔这些文件会合并,写入时间可能更长。保持 commit-graph 文件为最新有助于提升许多 Git 命令的性能,包括 git merge-basegit push -fgit log --graph。默认值为 false

fetch.bundleURI

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

如果你修改了此值,且仓库中存在 fetch.bundleCreationToken 值,那么在从新的 bundle URI 获取之前,请先删除该 fetch.bundleCreationToken 值。

fetch.bundleCreationToken

当使用 fetch.bundleURI 从采用 "creationToken" 启发式的 bundle 列表进行增量获取时,该配置值会保存已下载 bundle 的最大 creationToken 值。如果后续通告的 creationToken 不严格大于该值,则会利用此值阻止再次下载这些 bundle。

creation token 的值由提供该 bundle URI 的服务方决定。如果你修改了 fetch.bundleURI 中的 URI,那么在获取之前务必删除 fetch.bundleCreationToken 的值。

漏洞

使用 --recurse-submodules 只能获取本地存在的子模块中的新提交,例如在 $GIT_DIR/modules/。如果上游添加了一个新的子模块,该子模块不能被获取,直到它被克隆,例如,通过`git submodule update`。这个问题有望在未来的 Git 版本中被修复。

参见

GIT

属于 git[1] 文档