简体中文 ▾ 主题 ▾ 最新版本 ▾ git-fetch 上次更新于 2.52.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>

将抓取限制在每个远程分支历史记录的尖端(tip)的指定提交数。如果抓取到由 `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 会向服务器报告本地所有引用可达的提交,以查找共同的提交,从而尝试减小要接收的 packfile 的大小。如果指定,Git 只会报告给定尖端(tip)可达的提交。当用户知道哪个本地引用可能与正在抓取的上游引用有共同提交时,这有助于加快抓取速度。

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

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

另请参阅 git-config[1] 中记录的 `fetch.negotiationAlgorithm` 和 `push.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 一起使用时,它可能会拒绝更新本地分支,如下面的 `<refspec>` 部分所述。此选项会覆盖该检查。

-k
--keep

保留下载的 pack。

--multiple

允许指定多个 `` 和 `` 参数。不允许指定任何 ``。

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

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

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

抓取后写入 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` 不同,它会删除已创建的任何本地引用(本地标签)。此选项是提供显式标签 refspec 连同 `--prune` 的简写,请参阅其文档中的相关讨论。

有关更多详细信息,请参阅下面的 PRUNING 部分。

-n
--no-tags

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

--refetch

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

--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.parallel` 和 `submodule.fetchJobs` 配置设置(请参阅 git-config[1])。

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

--no-recurse-submodules

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

--set-upstream

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

--submodule-prefix=<path>

将 <path> 添加到信息性消息(如“Fetching submodule foo”)中打印的路径前面。此选项在递归遍历子模块时内部使用。

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

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

-u
--update-head-ok

默认情况下,`git fetch` 会拒绝更新对应当前分支的 head。此标志会禁用该检查。这纯粹是供 `git pull` 与 `git 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` 变量中读取(请参阅下面的 CONFIGURED REMOTE-TRACKING BRANCHES)。

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

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

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

`tag <tag>` 相当于 `refs/tags/<tag>:refs/tags/<tag>`;它请求抓取给定标签之前的所有内容。

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

是否允许在没有 `--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` hook 的 `pre-fetch` hook。

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

注意
当您想要抓取的远程分支已知会经常被重置和 rebase 时,预期它的新尖端(tip)不会是您上次抓取时存储在上游跟踪分支中的前一个尖端的后代。您会想要使用 `+` 符号来指示此类分支需要非快进更新。没有办法确定或声明一个分支将在具有此行为的仓库中可用;拉取用户只需知道这是该分支的预期使用模式。
--stdin

从 stdin 读取 refspecs,每行一个,除了作为参数提供的那些。不支持“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 作为 `` 参数

  • 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>`。推送到一个远程仓库会影响所有定义的 pushurls 或所有定义的 url(如果未定义 pushurls)。但是,抓取只会从第一个定义的 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 pull` 和 `git fetch` 使用。可以指定多个 `Push:` 和 `Pull:` 行以进行额外的分支映射。

$GIT_DIR/branches 中的命名文件

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

	<URL>#<head>

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

根据操作,Git 将使用以下 refspec 之一,如果您不在命令行上提供的话。`<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 origin` 或 `git fetch`,`remote.`<repository>`.fetch` 的值将用作 refspec—它们指定要抓取的引用以及要更新的本地引用。上面的示例将抓取 `origin` 中存在的所有分支(即,任何与值左侧 `refs/heads/*` 匹配的引用),并更新 `refs/remotes/origin/*` 层级结构中相应的远程跟踪分支。

  • 当 `git fetch` 运行时指定了命令行上的显式分支和/或标签,例如 `git fetch origin master`,命令行上提供的 `` 决定了要抓取的内容(例如,示例中的 `master`,它是 `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>` 和上面的 CONFIGURED REMOTE-TRACKING BRANCHES)来修剪本地↔远程引用。

因此,如果远程仓库的 refspec 包含例如 `refs/tags/*:refs/tags/*`,或者您手动运行例如 `git fetch --prune <name> "refs/tags/*:refs/tags/*"`,则不会删除过时的远程跟踪分支,而是会删除任何不存在于远程仓库中的本地标签。

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

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

由于跟踪远程仓库的两个分支和标签是常见用例,因此可以将 --prune-tags 选项与 --prune 一起使用,以剪除本地不存在于远程仓库的标签,并强制更新有差异的标签。标签剪除也可以通过配置 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 或其配置版本的情况下不报错,是为了配置版本的灵活性,以及保持命令行标志的作用与配置版本的作用之间的一一对应关系。

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

当从 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 协议获取时的输出。

获取状态以表格形式输出,每行代表一个 ref 的状态。每行都具有以下格式:

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

使用 --porcelain 时,输出格式旨在机器可解析。与人类可读的输出格式相反,它会打印到标准输出而不是标准错误。每行具有以下格式:

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

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

在紧凑输出模式下,通过配置变量 fetch.output 指定,如果 <from><to> 中的任何一个字符串在另一个字符串中找到,则会在另一个字符串中用 * 替换。例如,master -> origin/master 会变成 master -> origin/*

标志

一个表示 ref 状态的单个字符。

(空格)

表示成功获取的 fast-forward;

+

表示成功的强制更新;

-

表示成功剪除的 ref;

t

表示成功的标签更新;

*

表示成功获取的新 ref;

!

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

=

表示已更新且不需要获取的 ref。

摘要

对于成功获取的 ref,摘要显示 ref 的旧值和新值,格式适合用作 git log 命令的参数(在大多数情况下为 <old>..<new>,对于强制的非 fast-forward 更新为 <old>...<new>)。

来源

要从中获取的远程 ref 的名称,减去其 refs/<type>/ 前缀。在删除的情况下,远程 ref 的名称为 "(none)"。

目标

要更新的本地 ref 的名称,减去其 refs/<type>/ 前缀。

原因

人类可读的解释。对于成功获取的 ref,不需要解释。对于失败的 ref,会描述失败的原因。

示例

  • 更新远程跟踪分支

    $ git fetch origin

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

  • 显式使用 refspecs

    $ git fetch origin +seen:seen maint:tmp

    通过从远程仓库的 (分别为) seenmaint 分支获取,来更新(或根据需要创建)本地仓库中的 seentmp 分支。

    由于 seen 分支以加号 (+) 开头,即使它不是 fast-forward,也会被更新;而 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)是否将递归地获取已填充的子模块。此选项可以设置为布尔值或“按需”。将其设置为布尔值时,当设置为 true 时,fetch 和 pull 会无条件地递归到子模块;当设置为 false 时,则不递归。设置为“按需”时,fetch 和 pull 只会在其超级项目检索更新子模块引用的提交时递归到已填充的子模块。默认为“按需”,或者如果设置了 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 原生传输获取的对象数量低于此限制,则对象将被解包为松散的对象文件。但是,如果接收到的对象数量等于或超过此限制,则接收到的 pack 将被存储为一个 pack,并在添加任何缺失的 delta 基项后。存储来自 push 的 pack 可以使 push 操作更快完成,尤其是在慢速文件系统上。如果未设置,则使用 transfer.unpackLimit 的值。

fetch.prune

如果为 true,fetch 将自动表现得好像在命令行中提供了 --prune 选项。另请参阅 remote.<name>.prunegit-fetch[1] 的 PRUNING 部分。

fetch.pruneTags

如果为 true,当进行剪除时,fetch 将自动表现得好像提供了 refs/tags/*:refs/tags/* refspec,如果尚未设置。这允许同时设置此选项和 fetch.prune 以与上游 refs 保持一对一的映射。另请参阅 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.experimental 为 true,则默认值为“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 以在每次从远程下载 pack 文件的 git fetch 命令之后写入 commit-graph。使用 --split 选项,大多数执行将创建一个非常小的 commit-graph 文件,叠加在现有的 commit-graph 文件之上。偶尔,这些文件会合并,写入可能需要更长时间。拥有更新的 commit-graph 文件有助于许多 Git 命令的性能,包括 git merge-basegit push -fgit log --graph。默认为 false。

fetch.bundleURI

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

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

fetch.bundleCreationToken

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

creation token 值由提供特定 bundle URI 的提供者选择。如果您修改 fetch.bundleURI 的 URI,请务必在获取之前移除 fetch.bundleCreationToken 的值。

BUG

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

另请参阅

GIT

Git[1] 套件的一部分