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

名称

git-pull - 从另一个仓库或本地分支获取并整合

概要

git pull [<options>] [<repository> [<refspec>…​]]

描述

将远程仓库的更改整合到当前分支中。

首先,git pull 运行 git fetch 并使用相同的参数(合并选项除外)来获取远程分支。然后它决定整合哪个远程分支:如果你在不带参数的情况下运行 git pull,它默认为当前分支的上游(upstream)分支。最后,它将该分支整合到当前分支中。

整合远程分支主要有 4 种选项

  1. git pull --ff-only 将只执行“快进(fast-forward)”更新:如果你的本地分支与远程分支发生了偏离,它将失败。这是默认设置。

  2. git pull --rebase 运行 git rebase

  3. git pull --no-rebase 运行 git merge

  4. git pull --squash 运行 git merge --squash

你也可以设置配置选项 pull.rebasepull.squashpull.ff 来设定你偏好的行为。

如果在合并或变基过程中出现了你不想处理的合并冲突,你可以使用 git merge --abortgit rebase --abort 安全地中止操作。

选项

<repository>

要从中拉取的“远程”仓库。这可以是一个 URL(见下文 GIT URLS 一节)或远程仓库的名称(见下文 REMOTES 一节)。

默认为当前分支配置的上游,或 origin。有关如何配置上游的更多信息,请参阅下文的 上游分支

<refspec>

要获取并整合到当前分支的指定分支或其他引用,例如 git pull origin main 中的 main。默认为当前分支配置的上游分支。

这可以是一个分支、标签或其他引用集合。有关完整语法,请参阅下文“与获取相关的选项”中的 <refspec>,以及下文的 默认行为,了解 git pull 如何使用此参数确定要整合哪个远程分支。

-q
--quiet

此选项会传递给底层的 git-fetch 以在传输过程中压制报告,并传递给底层的 git-merge 以在合并过程中压制输出。

-v
--verbose

--verbose 传递给 git-fetch 和 git-merge。

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

此选项控制是否应获取已填充子模块的新提交,以及是否应更新活跃子模块的工作树(请参阅 git-fetch[1]git-config[1]gitmodules[5])。

如果检出是通过变基完成的,本地子模块提交也会被变基。

如果更新是通过合并完成的,子模块冲突将得到解决并检出。

--commit
--no-commit

执行合并并提交结果。此选项可用于覆盖 --no-commit。仅在合并时有效。

使用 --no-commit 时,执行合并并在创建合并提交之前停止,以便给用户一个检查并进一步调整合并结果的机会,然后再提交。

注意,快进更新不会创建合并提交,因此无法使用 --no-commit 停止这些合并。因此,如果你想确保你的分支不被合并命令更改或更新,请结合 --no-ff--no-commit 使用。

--edit
-e
--no-edit

在成功进行自动合并之前调用编辑器,以便进一步编辑自动生成的合并信息,这样用户可以解释和证明合并的理由。--no-edit 选项可用于接受自动生成的信息(通常不建议这样做)。

较旧的脚本可能依赖于不允许用户编辑合并日志信息的历史行为。当他们运行 git merge 时会看到编辑器打开。为了更容易将此类脚本调整为更新后的行为,可以在脚本开头将环境变量 GIT_MERGE_AUTOEDIT 设置为 no

--cleanup=<mode>

此选项决定了在提交之前如何清理合并信息。详见 git-commit[1]。此外,如果 <mode> 被赋予 scissors 值,在合并冲突的情况下,提交信息在传递给提交机制之前,会在 MERGE_MSG 中追加剪刀符号。

--ff-only

只有在没有分歧的本地历史记录时,才更新到新历史记录。这是当未提供调节分歧历史记录的方法(通过 --rebase 标志)时的默认设置。

--ff
--no-ff

在合并而非变基时,指定当被合并的历史记录已经是当前历史记录的后代时,如何处理合并。如果请求合并,除非合并的是未存储在 refs/tags/ 层级中其自然位置的标注(且可能已签名)标签(此时假定为 --no-ff),否则 --ff 是默认设置。

使用 --ff 时,尽可能将合并解析为快进(仅更新分支指针以匹配合并的分支;不创建合并提交)。当无法做到时(当被合并的历史记录不是当前历史记录的后代时),则创建一个合并提交。

使用 --no-ff 时,在所有情况下都创建一个合并提交,即使合并本可以解析为快进。

-S[<key-id>]
--gpg-sign[=<key-id>]
--no-gpg-sign

对结果合并提交进行 GPG 签名。<key-id> 参数是可选的,默认为提交者身份;如果指定,它必须紧贴选项且不带空格。--no-gpg-sign 用于撤销 commit.gpgSign 配置变量和之前的 --gpg-sign

--log[=<n>]
--no-log

除了分支名称外,用最多 <n> 个实际被合并提交的单行描述来填充日志信息。另请参阅 git-fmt-merge-msg[1]。仅在合并时有效。

使用 --no-log 时,不列出实际被合并提交的单行描述。

--signoff
--no-signoff

在提交日志消息的末尾添加提交者的 Signed-off-by 尾部。Signoff 的含义取决于您正在提交到的项目。例如,它可能证明提交者有权在项目的许可证下提交工作,或者同意某些贡献者表示,例如开发者证书(请参阅 https://developercertificate.org 获取 Linux 内核和 Git 项目使用的证书)。请查阅您贡献项目的文档或领导层,以了解该项目如何使用 Signoff。

可以使用 --no-signoff 选项来抵消命令行中较早的 --signoff 选项。

Git 现在没有(将来也不会有)用于默认启用 --signoff 命令行选项的配置变量;详见 gitfaq[7] 中的 commit.signoff 条目。

--stat
-n
--no-stat

在合并结束时显示 diffstat。diffstat 也由配置选项 merge.stat 控制。

使用 -n--no-stat 时,不在合并结束时显示 diffstat。

--compact-summary

在合并结束时显示紧凑摘要。

--squash
--no-squash

生成工作树和索引状态,就像发生了真正的合并(合并信息除外),但不实际进行提交,不移动 HEAD,也不记录 $GIT_DIR/MERGE_HEAD(这将导致下一次 git commit 命令创建合并提交)。这允许你在当前分支之上创建一个单一的提交,其效果与合并另一个分支(如果多个分支则为章鱼合并)相同。

使用 --no-squash 时,执行合并并提交结果。此选项可用于覆盖 --squash

使用 --squash 时,不允许使用 --commit,否则会失败。

仅在合并时有效。

--verify
--no-verify

默认情况下,运行预合并和提交信息钩子。当给出 --no-verify 时,这些会被绕过。另请参阅 githooks[5]。仅在合并时有效。

-s <strategy>
--strategy=<strategy>

使用指定的合并策略;可以多次提供以指定尝试它们的顺序。如果没有 -s 选项,则使用内置策略列表(合并单个头部时使用 ort,否则使用 octopus)。

-X <option>
--strategy-option=<option>

将合并策略特定的选项传递给合并策略。

--verify-signatures
--no-verify-signatures

验证正在合并的侧分支的尖端提交是否使用有效密钥签名,即具有有效 UID 的密钥:在默认信任模型中,这意味着签名密钥已由受信任的密钥签名。如果侧分支的尖端提交未由有效密钥签名,则合并中止。

仅在合并时有效。

--summary
--no-summary

--stat--no-stat 的同义词;这些已被弃用,将来会被移除。

--autostash
--no-autostash

在操作开始前自动创建一个临时暂存条目,将其记录在引用 MERGE_AUTOSTASH 中,并在操作结束后应用它。这意味着你可以在工作树脏的情况下运行该操作。但请谨慎使用:成功合并后应用最终暂存可能会导致非平凡的冲突。

--allow-unrelated-histories

默认情况下,git merge 命令拒绝合并没有共同祖先的历史记录。此选项可用于在合并两个独立开始的项目历史记录时覆盖此安全机制。由于这是非常罕见的情况,因此不存在也不会添加默认启用此功能的配置变量。

仅在合并时有效。

-r
--rebase[=(true|merges|false|interactive)]
true

在获取后,将当前分支变基到上游分支之上。如果存在对应于上游分支的远程跟踪分支,并且上游分支自上次获取以来已变基,则变基会利用该信息以避免变基非本地的更改。这是默认设置。

merges

使用 git rebase --rebase-merges 进行变基,以便本地合并提交被包含在变基中(详见 git-rebase[1])。

false

将上游分支合并到当前分支中。

interactive

启用变基的交互模式。

如果你想让 git pull 始终使用 --rebase 而非合并,请参阅 git-config[1] 中的 pull.rebasebranch.<name>.rebasebranch.autoSetupRebase

+

注意
这是一种潜在危险的操作模式。它会重写历史记录,如果你已经发布了该历史记录,这并不好。除非你仔细阅读了 git-rebase[1],否则不要使用此选项。
--no-rebase

这是 --rebase=false 的简写。

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

此选项可以指定多次;如果是这样,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 配置选项。

--filter=<filter-spec>

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

如果使用了 --filter=auto,则通过结合服务器为客户端接受的承诺远程(promisor remotes)所通告的过滤器规范来自动确定过滤器规范(请参阅 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。

-f
--force

git fetch<src>:<dst> 引用规格一起使用时,它可能会拒绝更新本地分支,如 git-fetch[1] 文档的 <refspec> 部分所讨论的那样。此选项覆盖该检查。

-k
--keep

保留下载的包。

--prefetch

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

-p
--prune

在获取之前,移除远程上不再存在的任何远程跟踪引用。如果仅因默认标签自动跟随或由于 --tags 选项而获取标签,则标签不受修剪影响。但是,如果由于明确的引用规格(无论是在命令行还是在远程配置中,例如如果远程是使用 --mirror 选项克隆的)而获取了标签,则它们也受修剪影响。提供 --prune-tags 是提供标签引用规格的简写。

--no-tags

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

--refmap=<refspec>

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

-t
--tags

从远程获取所有标签(即,将远程标签 refs/tags/* 获取到具有相同名称的本地标签中),除了否则会获取的内容之外。仅使用此选项不会使标签受到修剪,即使使用了 --prune 也是如此(尽管如果标签也是明确引用规格的目标,它们可能无论如何都会被修剪;请参阅 --prune)。

-j <n>
--jobs=<n>

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

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

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

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

--set-upstream

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

--upload-pack <upload-pack>

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

--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>

作为获取或拉取操作源的“远程”仓库。此参数可以是 URL(见下文 GIT URLS 一节)或远程仓库的名称(见下文 REMOTES 一节)。

<refspec>

指定要获取哪些引用以及要更新哪些本地引用。当命令行上没有出现 <refspec> 时,将改为从 remote.<repository>.fetch 变量读取要获取的引用(请参阅 git-fetch[1] 中的“已配置的远程跟踪分支”一节)。

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

<refspec> 可以在其 <src> 中包含一个 * 以表示简单的模式匹配。这样的引用规格就像一个 glob,匹配任何符合该模式的引用。模式 <refspec><src><dst> 中必须有且只能有一个 *。它将通过用从源匹配的内容替换 *,将引用映射到目标。

如果引用规格以 ^ 为前缀,它将被解释为负引用规格。这样的引用规格不会指定要获取哪些引用或更新哪些本地引用,而是指定要排除的引用。如果一个引用匹配至少一个正引用规格且不匹配任何负引用规格,则认为它匹配。负引用规格可用于限制模式引用规格的范围,使其不包含特定引用。负引用规格本身也可以是模式引用规格。但是,它们只能包含 <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/* 命名空间都不会接受非提交对象。

注意
当你想获取的远程分支已知会定期倒退和变基时,预期的结果是其新的尖端将不是其先前尖端(即你上次获取时存储在远程跟踪分支中的内容)的后代。对于此类分支,你需要使用 + 号来表示将需要非快进更新。没有办法确定或声明一个分支将在具有此行为的仓库中以这种方式提供;拉取的用户只需知道这是分支的预期使用模式即可。
注意
git pull 命令行上直接列出多个 <refspec> 与在配置中为 <repository> 拥有多个 remote.<repository>.fetch 条目并运行没有明确 <refspec> 参数的 git pull 命令之间存在区别。明确列在命令行上的 <refspec> 在获取后总是会被合并到当前分支。换句话说,如果你列出多个远程引用,git pull 将创建一个章鱼合并。另一方面,如果你在命令行上没有列出任何明确的 <refspec> 参数,git pull 将获取它在 remote.<repository>.fetch 配置中找到的所有 <refspec>,并仅将找到的第一个 <refspec> 合并到当前分支。这是因为从远程引用制作章鱼合并很少见,而通过一次获取多个远程分支来跟踪它们通常很有用。

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 mergegit pull 命令)允许使用 -s 选项选择后端合并策略。一些策略还可以接受自己的选项,这些选项可以通过向 git merge 和/或 git pull 传递 -X<option> 参数来传递。

ort

这是拉取或合并一个分支时的默认合并策略。该策略只能使用三向合并算法来解析两个头。当存在多个可用于三向合并的共同祖先时,它会创建一个共同祖先的合并树,并将其用作三向合并的参考树。根据从 Linux 2.6 内核开发历史中提取的实际合并提交进行的测试,这可以减少合并冲突,而不会导致错误合并。此外,该策略可以检测和处理涉及重命名的合并。它不利用检测到的复制。该算法的名称是一个首字母缩略词(“Ostensibly Recursive’s Twin”),源于它是作为先前默认算法 recursive 的替代品而编写的。

在路径是子模块的情况下,如果合并一方使用的子模块提交是合并另一方使用的子模块提交的后代,Git 会尝试快进到后代。否则,Git 会将这种情况视为冲突,并建议一个与冲突的子模块提交的后代作为解决方案(如果存在)。

ort 策略可以接受以下选项:

ours

此选项强制冲突的块自动干净地解决,优先采用我们的版本。来自另一棵树但与我们这方没有冲突的更改会反映在合并结果中。对于二进制文件,整个内容将来自我们这边。

这不应与 ours 合并策略混淆,后者根本不查看另一棵树包含的内容。它丢弃了另一棵树所做的所有更改,声称我们的历史包含了发生的所有事件。

theirs

这与 ours 相反;请注意,与 ours 不同,没有 theirs 合并策略来混淆此合并选项。

ignore-space-change
ignore-all-space
ignore-space-at-eol
ignore-cr-at-eol

在进行三向合并时,将指定类型的空白字符更改的行视为未更改。混合了其他更改的行的空白更改不会被忽略。另请参阅 git-diff[1]-b-w--ignore-space-at-eol--ignore-cr-at-eol

  • 如果*他们的*版本只引入了行的空白符更改,则使用*我们的*版本;

  • 如果*我们的*版本引入了空白符更改但*他们的*版本包含了实质性更改,则使用*他们的*版本;

  • 否则,合并按常规方式进行。

renormalize

这将对任何需要三向合并的文件执行虚拟签出和签入所有三个阶段。此选项用于合并具有不同签入/签出属性的分支。有关详细信息,请参阅 gitattributes[5] 中的“合并具有不同签入/签出属性的分支”。

no-renormalize

禁用 renormalize 选项。这会覆盖 merge.renormalize 配置变量。

find-renames[=<n>]

启用重命名检测,可选地设置相似度阈值。这是默认设置。此选项会覆盖 merge.renames 配置变量。另请参阅 git-diff[1]--find-renames

rename-threshold=<n>

已弃用的 find-renames=<n> 同义词。

no-renames

关闭重命名检测。这会覆盖 merge.renames 配置变量。另请参阅 git-diff[1] --no-renames

histogram

已弃用的 diff-algorithm=histogram 同义词。

patience

已弃用的 diff-algorithm=patience 同义词。

diff-algorithm=(histogram|minimal|myers|patience)

在合并时使用不同的 diff 算法,这有助于避免由于不重要的匹配行(例如来自不同函数的括号)而导致的错误合并。另请参阅 git-diff[1]--diff-algorithm。请注意,ort 默认为 diff-algorithm=histogram,而常规 diff 目前默认为 diff.algorithm 配置设置。

subtree[=<path>]

此选项是子目录策略的高级形式,在该策略中,合并时策略会猜测两个树必须如何偏移才能匹配。相反,指定的路径会作为前缀(或从开头剥离)以使两个树的形状匹配。

recursive

这现在是 ort 的同义词。它直到 v2.49.0 都是一个替代实现,但在 v2.50.0 中被重定向为 ort。之前的 recursive 策略是从 Git v0.99.9k 到 v2.33.0 的默认策略。

resolve

这只能使用三向合并算法解决两个头部(即当前分支和你拉取的另一个分支)。它尝试仔细检测交叉合并歧义。它不处理重命名。

octopus

这可以解决多于两个头的情况,但拒绝进行需要手动解决的复杂合并。它主要用于将主题分支头捆绑在一起。当拉取或合并多个分支时,这是默认的合并策略。

ours

这可以解决任意数量的头,但合并结果树始终是当前分支头的内容,实际上会忽略所有其他分支的所有更改。它用于取代侧分支的旧开发历史。请注意,这与 ort 合并策略的 -Xours 选项不同。

subtree

这是 ort 策略的修改版本。当合并树 A 和 B 时,如果 B 对应于 A 的子目录,则 B 首先会调整以匹配 A 的树结构,而不是在同一级别读取树。这种调整也适用于共同祖先树。

在使用三向合并(包括默认的 ort)的策略中,如果在两个分支上都进行了更改,但之后在一个分支上撤销了该更改,那么该更改将保留在合并结果中;有些人认为这种行为令人困惑。这是因为在执行合并时,只考虑了头和合并基,而没有考虑单个提交。因此,合并算法将撤销的更改视为没有更改,而是用更改后的版本替换。

默认行为

通常人们使用 git pull 而不给出任何参数。传统上,这等同于说 git pull origin。但是,当在分支 <name> 上存在配置 branch.<name>.remote 时,该值将用于代替 origin

为了确定使用哪个 URL 进行获取,将查询配置 remote.<origin>.url 的值;如果没有这样的变量,则使用 $GIT_DIR/remotes/<origin>URL: 行上的值。

为了确定当命令在没有任何引用规格参数的情况下在命令行上运行时要获取(并可选地存储在远程跟踪分支中)哪些远程分支,将查询配置变量 remote.<origin>.fetch 的值;如果没有,将查询 $GIT_DIR/remotes/<origin> 并使用其 Pull: 行。除了 OPTIONS 部分中描述的引用规格格式外,你还可以拥有如下所示的 glob 引用规格

refs/heads/*:refs/remotes/origin/*

glob 引用规格必须具有非空的 RHS(即必须将获取的内容存储在远程跟踪分支中),并且其 LHS 和 RHS 必须以 /* 结尾。上述指定了所有远程分支都使用 refs/remotes/origin/ 层级中相同名称的远程跟踪分支进行跟踪。

为了不破坏向后兼容性,确定获取后要合并哪个远程分支的规则有点复杂。

如果在 git pull 的命令行上给出了明确的引用规格,它们都将被合并。

当命令行上没有给出引用规格时,git pull 使用来自配置或 $GIT_DIR/remotes/<origin> 的引用规格。在这种情况下,适用以下规则

  1. 如果存在当前分支 <name>branch.<name>.merge 配置,则这就是合并时远程站点上的分支名称。

  2. 如果引用规格是 glob 类型的,则不合并任何内容。

  3. 否则,合并第一个引用规格的远程分支。

示例

  • 更新你克隆来源仓库的远程跟踪分支,然后将其中一个合并到你的当前分支

    $ git pull
    $ git pull origin

    通常合并进来的分支是远程仓库的 HEAD,但选择由 branch.<name>.remotebranch.<name>.merge 选项决定;详见 git-config[1]

  • 将远程分支 next 合并到当前分支

    $ git pull origin next

    这会将 next 的副本临时留在 FETCH_HEAD 中,并更新远程跟踪分支 origin/next。同样可以通过调用 fetch 和 merge 来完成

    $ git fetch origin
    $ git merge origin/next

如果你尝试了一次拉取,但结果产生了复杂的冲突,并且想要重新开始,你可以使用 git reset 恢复。

安全性

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 相似的区域。

BUG

目前,使用 --recurse-submodules 只能在已经检出的子模块中获取新的提交。例如,当上游在超级项目刚获取的提交中添加了新的子模块时,无法获取子模块本身,从而导致以后无法检出该子模块,除非重新进行获取。预计这将在 Git 的未来版本中得到修复。

GIT

Git[1] 套件的一部分