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

名称

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

概要

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

描述

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

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

集成远程分支的四种主要选项

  1. git pull --ff-only 只执行“快进”更新:如果你的本地分支与远程分支发生分歧,则失败。这是默认设置。

  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。有关如何配置上游的更多信息,请参阅下面的 UPSTREAM BRANCHES

<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

在进行变基而非合并时,指定在被合并的历史已经是当前历史的后代时如何处理合并。如果请求合并,--ff 是默认设置,除非合并的是一个带注释(可能已签名)的标签,但该标签未存储在 refs/tags/ 层级结构中的自然位置,在这种情况下,假定为 --no-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 选项。

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

默认情况下,会运行 pre-merge 和 commit-msg 钩子。当给出 --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[=(false|true|merges|interactive)]

当为 true 时,在获取后将当前分支变基到上游分支之上。如果存在一个与上游分支对应的远程跟踪分支,并且上游分支自上次获取以来已被变基,则变基将利用该信息来避免变基非本地更改。

当设置为 merges 时,使用 git rebase --rebase-merges 进行变基,以便本地合并提交包含在变基中(有关详细信息,请参阅 git-rebase[1])。

当为 false 时,将上游分支合并到当前分支。

当设置为 interactive 时,启用变基的交互模式。

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

注意
这是一个可能**危险**的操作模式。它会重写历史,当您已经发布了该历史时,这并不理想。除非您仔细阅读了 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 会向服务器报告所有本地引用的可达提交,以查找共同的提交,从而尝试减小要接收的 packfile 的大小。如果指定,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 配置选项。

-f
--force

当使用 <src>:<dst> refspec 调用*git fetch* 时,它可能会拒绝更新本地分支,如 git-fetch[1] 文档的*<refspec>* 部分所述。此选项将覆盖该检查。

-k
--keep

保留下载的 pack 文件。

--prefetch

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

-p
--prune

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

--no-tags

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

--refmap=<refspec>

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

-t
--tags

除了其他任何将被获取的内容之外,还从远程获取所有标签(即,将远程标签 refs/tags/* 获取到具有相同名称的本地标签)。单独使用此选项不会使标签被修剪,即使使用了 --prune(尽管如果标签是显式 refspec 的目标,它们仍可能被修剪;请参阅 --prune)。

-j
--jobs=<n>

所有形式获取使用的并行子进程数量。

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

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

--set-upstream

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

--upload-pack <upload-pack>

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

--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 部分)。

<refspec>

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

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

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

如果一个 refspec 以 ^ 开头,它将被解释为负面 refspec。与其指定要获取的引用或要更新的本地引用,不如说这样的 refspec 将指定要排除的引用。如果一个引用至少匹配一个正面 refspec 且不匹配任何负面 refspec,则该引用将被视为匹配。负面 refspec 可用于限制模式 refspec 的范围,使其不包含特定引用。负面 refspec 本身可以是模式 refspec。但是,它们只能包含一个 <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/* 的更新都将被接受,而无需在 refspec 中添加 +(或 --force)。在获取时,我们粗略地将来自远程的所有标签更新都视为强制获取。自 Git 版本 2.20 起,更新 refs/tags/* 的获取方式与推送时相同。也就是说,任何更新都将在没有在 refspec 中添加 +(或 --force)的情况下被拒绝。

与使用 git-push[1] 进行推送不同,refs/tags/{heads}/* 之外的任何更新都将被接受,而无需在 refspec 中添加 +(或 --force),无论是交换例如一个树对象为一个 blob,还是一个提交为一个不以前一个提交为祖先的提交等。

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

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

注意
当你想获取的远程分支已知会定期回溯和变基时,它期望其新的尖端不是其之前尖端的后代(如上次获取时在你的远程跟踪分支中存储的)。你会想使用 + 符号来表示需要对这样的分支进行非快进更新。没有办法确定或声明一个分支将在具有此行为的仓库中可用;拉取用户只需知道这是该分支的预期使用模式。
注意
在 `git pull` 命令行的直接列出多个 `` 和在配置中为 `` 设置多个 `remote..fetch` 条目,然后运行不带任何显式 `` 参数的 `git pull` 命令之间存在区别。在命令行中显式列出的 `` 在抓取(fetching)后总是会被合并到当前分支。换句话说,如果你列出多个远程引用,`git pull` 将创建一个 Octopus 合并。另一方面,如果你在命令行中不带任何显式的 `` 参数,`git pull` 将抓取它在 `remote..fetch` 配置中找到的所有 ``,并且只将找到的第一个 `` 合并到当前分支。这是因为从远程引用进行 Octopus 合并很少发生,而通过一次抓取多个远程 HEAD 来跟踪它们通常很有用。

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 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:` 行的值。

为了确定在不带任何 refspec 参数运行命令时抓取哪些远程分支(并可选择地存储在远程跟踪分支中),会查找配置变量 `remote.<origin>.fetch` 的值,如果不存在,则会查找 `$GIT_DIR/remotes/<origin>` 并使用其 `Pull:` 行。除了选项部分描述的 refspec 格式外,你还可以使用如下形式的 globbing refspec:

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

globbing refspec 必须有一个非空的 RHS(即必须存储在远程跟踪分支中抓取的内容),并且其 LHS 和 RHS 必须以 `/*` 结尾。上面的例子指定了所有远程分支都使用 `refs/remotes/origin/` 层级下的同名远程跟踪分支进行跟踪。

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

如果在 `git pull` 命令的命令行上提供了显式 refspec,则它们都会被合并。

当命令行上没有提供 refspec 时,`git pull` 使用配置或 `$GIT_DIR/remotes/<origin>` 中的 refspec。在这种情况下,适用以下规则:

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

  2. 如果 refspec 是 globbing 的,则不合并任何内容。

  3. 否则,合并第一个 refspec 的远程分支。

示例

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

    $ git pull
    $ git pull origin

    通常合并的分支是远程仓库的 HEAD,但选择由 `branch.<name>.remote` 和 `branch.<name>.merge` 选项决定;有关详细信息,请参见 `git-config[1]`。

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

    $ git pull origin next

    这会在 FETCH_HEAD 中留下 `next` 的一个临时副本,并更新远程跟踪分支 `origin/next`。通过调用 fetch 和 merge 也可以完成同样的操作:

    $ git fetch origin
    $ git merge origin/next

如果你尝试了一个导致复杂冲突的 pull,并且想重新开始,可以使用 `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` 目前只能抓取已经签出的子模块中的新提交。当例如上游在超级项目中刚刚抓取的提交中添加了一个新的子模块时,子模块本身无法被抓取,这使得在不再次执行 fetch 的情况下无法签出该子模块。这预计将在未来的 Git 版本中得到修复。

GIT

Git[1] 套件的一部分