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

名称

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

概要

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

描述

将远程仓库的更改集成到当前分支中。

首先,git pull 会运行带有相同参数(不包括合并选项)的 git fetch 来获取远程分支。然后它决定集成哪个远程分支:如果你运行不带参数的 git pull,默认会使用当前分支的上游分支。接着,它将该分支集成到当前分支中。

集成远程分支有 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 安全地终止它。

选项

<仓库>

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

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

<引用规范>

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

这可以是一个分支、标签或其他引用集合。完整的语法请参见下面“与获取相关的选项”中的 <引用规范>,以及下面关于 git pull 如何使用此参数确定要集成的远程分支的 DEFAULT BEHAVIOUR

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

如果是通过变基(rebase)进行检出,本地子模组的提交也会一同被变基。

如果是通过合并(merge)进行更新,子模组的冲突会被解决并检出。

--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=<模式>

此选项决定了在提交之前如何清理合并信息。更多细节请参见 git-commit[1]。此外,如果 <模式> 的值被设为 scissors,在发生合并冲突时,剪刀线(scissors)将被附加到 MERGE_MSG,然后传递给提交机制。

--ff-only

仅在没有分叉的本地历史时才更新到新的历史。如果在未提供解决分叉历史的方法(通过 --rebase 标志)时的默认行为。

--ff
--no-ff

当进行合并而不是变基时,指定当被合并的历史已经是当前历史的后代时,如何处理合并。如果请求合并,--ff 是默认行为,除非合并的附注(且可能已签名)标签未存储在 refs/tags/ 层级结构中的自然位置,在这种情况下会假定使用 --no-ff

使用 --ff 时,在可能的情况下,将合并解析为快进(仅更新分支指针以匹配被合并的分支;不创建合并提交)。在不可能的情况下(当合并进来的历史不是当前历史的后代时),创建一个合并提交。

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

-S[<密钥-id>]
--gpg-sign[=<密钥-id>]
--no-gpg-sign

对生成的合并提交进行 GPG 签名。<密钥-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)。差异统计也受配置选项 merge.stat 控制。

使用 -n--no-stat 时,不显示合并结束时的差异统计。

--compact-summary

在合并结束时显示紧凑摘要(compact-summary)。

--squash
--no-squash

产生工作区和暂存区状态,就像发生了一次真实的合并(除了合并信息之外),但不实际进行提交、不移动 HEAD,也不记录 $GIT_DIR/MERGE_HEAD(否则会导致下一个 git commit 命令创建合并提交)。这使你能够在当前分支之上创建一个单独的提交,其效果与合并另一个分支(如果是章鱼合并,则是多个分支)相同。

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

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

仅在合并时有用。

--verify
--no-verify

默认情况下会运行 pre-merge 和 commit-msg 钩子。指定 --no-verify 时,这些钩子将被绕过。参见 githooks[5]。仅在合并时有用。

-s <策略>
--strategy=<策略>

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

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

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

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

验证正在合并的旁支(side branch)的末梢提交(tip commit)是否使用有效密钥签名,即具有有效 uid 的密钥:在默认信任模型中,这意味着签名密钥已被受信任的密钥签名。如果旁支的末梢提交未使用有效密钥签名,则合并将被中止。

仅在合并时有用。

--summary
--no-summary

--stat--no-stat 的同义词;这些选项已被弃用,并将在未来移除。

--autostash
--no-autostash

在操作开始前自动创建一个临时储藏(stash)条目,记录在引用 MERGE_AUTOSTASH 中,并在操作结束之后应用它。这意味着你可以在脏工作区上运行该操作。但请谨慎使用:在成功合并后最终应用储藏可能会导致复杂的冲突。

--allow-unrelated-histories

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

仅在合并时有用。

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

在获取(fetch)后,将当前分支变基到上游分支之上。如果存在与上游分支对应的远程跟踪分支,且上游分支自上次获取以来已被变基,则变基操作会使用该信息以避免对非本地更改进行变基。这是默认行为。

merges

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

false

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

interactive

启用交互式变基模式。

如果你希望让 git pull 总是使用 --rebase 而不是合并,请参阅 git-config[1] 中的 pull.rebasebranch.<名称>.rebasebranch.autoSetupRebase

+

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

这是 --rebase=false 的简写。

--all
--no-all

获取所有远程仓库,但设置了 remote.<名称>.skipFetchAll 配置变量的远程仓库除外。这会覆盖 fetch.all 配置变量。

-a
--append

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

--atomic

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

--depth=<深度>

将获取限制为从每个远程分支历史的末梢起指定的提交次数。如果获取到通过带有 --depth=<深度> 选项的 git clone 创建的 浅(shallow) 仓库中(参见 git-clone[1]),则加深或缩短历史到指定的提交次数。不会获取加深提交的标签。

--deepen=<深度>

类似于 --depth,但它指定了从当前浅边界(shallow boundary)开始的提交次数,而不是从每个远程分支历史的末梢开始。

--shallow-since=<日期>

加深或缩短浅仓库的历史,以包含指定 <日期> 之后所有可达的提交。

--shallow-exclude=<引用>

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

--unshallow

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

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

--update-shallow

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

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

默认情况下,Git 会向服务器报告可从所有本地引用到达的提交,以查找共同的提交,从而尝试减小要接收的包文件的大小。如果指定了此选项,Git 将仅报告可从给定末梢(tips)到达的提交。当用户知道哪个本地引用可能与要获取的上游引用具有共同的提交时,这对于加快获取速度非常有用。

--negotiation-restrict 是此选项的首选名称;--negotiation-tip 被接受为同义词。

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

该选项的参数可以是引用名称上的通配符(glob)、引用,或者提交的(可能缩写的)SHA-1。指定通配符相当于多次指定此选项,每个匹配的引用名称各指定一次。

另见 git-config[1] 中说明的 fetch.negotiationAlgorithmpush.negotiate 配置变量,以及下面的 --negotiate-only 选项。

--negotiation-include=(<提交>|<通配符>)

确保在获取协商期间,给定末梢处的提交始终作为 “have” 行发送,无论协商算法如何选择。这对于保证始终考虑从特定引用可达的共同历史很有用,即使在 --negotiation-restrict 限制了末梢集合,或者协商算法在其他情况下会跳过它们时。

可以多次指定此选项;如果是这样,每个提交都会无条件发送。

该参数可以是一个精确的引用名(例如 refs/heads/release)、对象哈希,或者通配符模式(例如 refs/heads/release/{asterisk})。模式语法与 --negotiation-restrict 的语法相同。

如果使用了 --negotiation-restrict,则 have 集合首先受到该选项的限制,然后扩大以包含 --negotiation-include 指定的末梢。

如果在命令行中未指定此选项,则将改用当前远程仓库的任何 remote.<名称>.negotiationInclude 配置值。

--negotiate-only

不从服务器获取任何内容,而是打印提供的 --negotiation-restrict= 参数的祖先,即我们与服务器共同拥有的祖先。

这与 --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 时,提供的 <过滤器规范> 将用于部分获取。

如果使用 --filter=auto,过滤器规范将通过合并服务器为客户端接受的承诺者(promisor)远程仓库公布的过滤器规范来自动确定(参见 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] 文档中 <引用规范> 部分所述。此选项将覆盖该检查。

-k
--keep

保留下载的包。

--prefetch

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

-p
--prune

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

--no-tags

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

--refmap=<引用规范>

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

--upload-pack <upload-pack>

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

--progress

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

-o <选项>
--server-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 地址。

<仓库>

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

<引用规范>

指定要获取的引用以及要更新的本地引用。当命令行中没有出现 <引用规范> 时,要获取的引用将改为从 remote.<仓库>.fetch 变量中读取(参见 git-fetch[1] 中的“配置的远程跟踪分支”部分)。

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

一个 <引用规范> 可以在其 <src> 中包含一个 * 来指示简单的模式匹配。这种引用规范的作用就像一个通配符,可以匹配符合该模式的任何引用。模式 <引用规范><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)的情况下被接受,无论是将树对象替换为二进制大对象(blob),还是将一个提交替换为不以先前提交为祖先的另一个提交等。

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

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

注意
当已知你要获取的远程分支会定期倒回和变基时,可以预料它的新末梢将不会是其旧末梢的后代(如上次获取时存储在远程跟踪分支中的内容)。对于此类分支,你需要使用 + 符号来表示需要进行非快进更新。无法确定或声明某个分支将在具有此行为的仓库中可用;进行拉取操作的用户只需要知道这是该分支的预期使用模式。
注意
直接在 git pull 命令行中列出多个 <引用规范>,与在配置中针对某个 <仓库> 拥有多个 remote.<仓库>.fetch 条目并在不带任何显式 <引用规范> 参数的情况下运行 git pull 命令是有区别的。在命令行上显式列出的 <引用规范> 在获取后总是会被合并到当前分支中。换句话说,如果你列出了多个远程引用, git pull 将创建一个章鱼合并(Octopus merge)。另一方面,如果你在命令行上没有列出任何显式的 <引用规范> 参数,git pull 将获取它在 remote.<仓库>.fetch 配置中找到的所有 <引用规范>,且仅将找到的第一个 <引用规范> 合并到当前分支中。这是因为很少有人会基于远程引用进行章鱼合并,而通过一次获取多个远程分支来跟踪它们往往非常有用。

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。然而,当处于分支 <名称> 时如果配置了 branch.<名称>.remote,则将使用该值而不是 origin

为了确定要从哪个 URL 进行获取,会参考配置 remote.<origin>.url 的值,如果没有该变量,则使用 $GIT_DIR/remotes/<origin>URL: 行的值。

为了在命令行没有运行任何引用规范参数时,确定要获取哪些远程分支(并可选地存储在远程跟踪分支中),会参考配置变量 remote.<origin>.fetch 的值,如果没有,则参考 $GIT_DIR/remotes/<origin> 并使用其 Pull: 行。除了 OPTIONS 章节中描述的引用规范格式外,你还可以拥有一个类似这样的通配符引用规范

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

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

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

如果在 git pull 的命令行中给出了显式的引用规范,它们都将被合并。

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

  1. 如果当前分支 <名称> 存在 branch.<名称>.merge 配置,那就是远程端要合并的分支名称。

  2. 如果引用规范是通配符,则不进行任何合并。

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

示例

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

    $ git pull
    $ git pull origin

    通常情况下,合并进来的分支是远程仓库的 HEAD,但该选择由 branch.<名称>.remotebranch.<名称>.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 只能在已检出的子模组中获取新提交。例如,当上游在刚刚获取的父项目(superproject)提交中添加了新的子模组时,子模组本身无法被获取,导致以后无法在不重新获取的情况下检出该子模组。这有望在未来的 Git 版本中得到解决。

GIT

Git[1] 套件的一部分