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

名称

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

概要

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

描述

将远程仓库的更改并入当前分支。如果当前分支落后于远程分支,则默认情况下会快进当前分支以匹配远程分支。如果当前分支和远程分支已分歧,用户需要通过 --rebase--no-rebase (或 pull.rebase 中相应的配置选项)来指定如何协调分歧的分支。

更精确地说,git pull 会使用给定的参数运行 git fetch,然后根据配置选项或命令行标志,调用 git rebasegit merge 来协调分歧的分支。

<repository> 应该是传递给 git-fetch[1] 的远程仓库名称。<refspec> 可以指定任意远程引用(例如,标签的名称),甚至是一组带有相应远程跟踪分支的引用(例如,refs/heads/*:refs/remotes/origin/*),但通常它是远程仓库中分支的名称。

<repository> 和 <branch> 的默认值是从通过 git-branch[1] --track 设置的当前分支的“remote”和“merge”配置中读取的。

假设存在以下历史记录,并且当前分支是“master

	  A---B---C master on origin
	 /
    D---E---F---G master
	^
	origin/master in your repository

然后“git pull”将从远程 master 分支拉取并重放自本地 master 分支(即 E)分歧以来的更改,直到其当前提交(C),然后将其记录在一个新提交中,并附带两个父提交的名称以及用户描述更改的日志消息。

	  A---B---C origin/master
	 /         \
    D---E---F---G---H master

有关详细信息,包括冲突的呈现和处理方式,请参阅 git-merge[1]

在 Git 1.7.0 或更高版本中,要取消冲突的合并,请使用 git reset --merge。**警告**:在旧版本的 Git 中,不鼓励在有未提交更改的情况下运行 *git pull*:尽管可能,但在发生冲突时,它会使你处于一个可能难以回退的状态。

如果任何远程更改与本地未提交的更改重叠,合并将自动取消,并且工作树保持不变。通常最好在拉取之前整理好任何本地更改,或者使用 git-stash[1] 将它们暂存起来。

选项

-q
--quiet

此选项会传递给底层的 git-fetch 以抑制传输期间的报告,并传递给底层的 git-merge 以抑制合并期间的输出。

-v
--verbose

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

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

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

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

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

--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 附注。签名的含义取决于你所提交的项目。例如,它可能证明提交者有权在项目许可下提交作品,或者同意某些贡献者声明,例如开发者原创证明(Developer Certificate of Origin)。(请参阅 https://developercertificate.org 了解 Linux 内核和 Git 项目使用的证明。)请查阅你所贡献的项目的文档或领导层,以了解该项目中签名的用途。

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

--stat
-n
--no-stat

在合并结束时显示差异统计。差异统计也受配置选项 merge.stat 控制。

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

--squash
--no-squash

生成工作树和索引状态,就像发生了实际合并一样(除了合并信息),但实际上不进行提交,不移动 HEAD,也不记录 $GIT_DIR/MERGE_HEAD(以使下一个 git commit 命令创建合并提交)。这允许你在当前分支之上创建一个单独的提交,其效果与合并另一个分支(或在八爪鱼合并情况下合并更多分支)相同。

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

使用 --squash 时,不允许使用 --commit,并且会失败。

仅在合并时有用。

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

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

仅在合并时有用。

--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 而不是合并,请参阅 git-config[1] 中的 pull.rebasebranch.<name>.rebasebranch.autoSetupRebase

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

这是 --rebase=false 的简写。

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

当 *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.*.fetch 配置变量的值。向 --refmap 选项提供空 *<refspec>* 会导致 Git 忽略配置的引用规范,并完全依赖作为命令行参数提供的引用规范。有关详细信息,请参阅“配置的远程跟踪分支”部分。

-t
--tags

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

-j
--jobs=<n>

用于所有形式拉取的并行子进程数量。

如果指定了 --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 进行通信时,将给定字符串传输到服务器。给定字符串不得包含 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 URL 部分)或远程名称(请参阅下面的 远程仓库 部分)。

<refspec>

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

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

一个 <refspec> 可以在其 <src> 中包含一个 * 来指示简单的模式匹配。这样的 refspec 像一个全局模式,匹配任何符合该模式的引用。一个模式 <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] 推送时不同,在引用规范中没有 +(或 --force)的情况下,refs/{tags,heads}/* 之外的任何更新都将被接受,无论是例如用一个 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* 将创建一次“八爪鱼合并”(Octopus merge)。另一方面,如果你在命令行上没有列出任何显式 <refspec> 参数,*git pull* 将拉取它在 remote.<repository>.fetch 配置中找到的所有 <refspec>,并且只将找到的第一个 <refspec> 合并到当前分支中。这是因为从远程引用创建八爪鱼合并的情况很少见,而通过一次拉取多个来跟踪多个远程头部通常很有用。

GIT URL

通常,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。

远程仓库

以下之一的名称可以作为 <repository> 参数来代替 URL 使用:

  • Git 配置文件中的远程仓库:$GIT_DIR/config

  • $GIT_DIR/remotes 目录中的文件,或

  • $GIT_DIR/branches 目录中的文件。

所有这些也允许你省略命令行中的引用规范,因为它们各自包含一个 Git 将默认使用的引用规范。

配置文件中的命名远程仓库

你可以选择提供之前使用 git-remote[1]git-config[1] 配置的远程仓库名称,甚至可以通过手动编辑 $GIT_DIR/config 文件来配置。此远程仓库的 URL 将用于访问仓库。当你未在命令行上提供引用规范时,此远程仓库的引用规范将作为默认值使用。配置文件中的条目将如下所示:

	[remote "<name>"]
		url = <URL>
		pushurl = <pushurl>
		push = <refspec>
		fetch = <refspec>

<pushurl> 仅用于推送。它是可选的,默认为 <URL>。推送到远程会影响所有已定义的 pushurl 或所有已定义的 url(如果没有定义 pushurl)。但是,如果定义了多个 url,拉取将只从第一个定义的 url 拉取。

$GIT_DIR/remotes 中的命名文件

你可以选择提供 $GIT_DIR/remotes 中的文件名称。此文件中的 URL 将用于访问仓库。当你未在命令行上提供引用规范时,此文件中的引用规范将作为默认值使用。此文件应具有以下格式:

	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 将使用以下引用规范之一。<branch>$GIT_DIR/branches 中此文件的名称,<head> 默认为 master

git fetch 使用

	refs/heads/<head>:refs/heads/<branch>

git push 使用

	HEAD:refs/heads/<head>

合并策略

合并机制(git mergegit pull 命令)允许使用 -s 选项选择后端*合并策略*。某些策略也可以接受自己的选项,这些选项可以通过向 git merge 和/或 git pull 提供 -X<option> 参数来传递。

ort

这是拉取或合并一个分支时的默认合并策略。此策略只能使用三向合并算法解决两个头部。当存在多个可用于三向合并的共同祖先时,它会创建共同祖先的合并树,并将其用作三向合并的参考树。根据对 Linux 2.6 内核开发历史中实际合并提交进行的测试报告,这会导致更少的合并冲突,而不会引起合并错误。此外,此策略可以检测和处理涉及重命名的合并。它不使用检测到的复制。此算法的名称是一个缩写(“表面上的递归的双胞胎”),因为它被编写为替代之前的默认算法 recursive

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

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

ours

此选项强制通过偏向于*我们的*版本来干净地自动解决冲突的 hunk。来自另一个树的更改(与我们这边的更改不冲突)会反映在合并结果中。对于二进制文件,整个内容取自我们这边。

这不应与 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)

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

subtree[=<path>]

此选项是 *subtree* 策略的一种更高级形式,该策略猜测在合并时如何移动两棵树以使其相互匹配。相反,指定的路径被添加前缀(或从开头删除),以使两棵树的形状匹配。

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 部分中描述的引用规范格式外,你还可以有类似这样的全局引用规范:

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

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

确定拉取后合并哪个远程分支的规则有些复杂,以避免破坏向后兼容性。

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

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

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

  2. 如果引用规范是全局匹配的,则不进行合并。

  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 X,并向 X 发送一个引用,但不需要发送 X 的内容,因为受害者已经拥有它。现在受害者认为攻击者拥有 X,并稍后将 X 的内容发回给攻击者。(这种攻击对于客户端在服务器上执行最直接,即在客户端有权访问的命名空间中创建指向 X 的引用,然后拉取它。服务器在客户端上执行它的最可能方式是将 X “合并”到一个公共分支中,并希望用户在此分支上进行额外工作并将其推回服务器而没有注意到合并。)

  2. 与 #1 中类似,攻击者选择要窃取的对象 ID X。受害者发送攻击者已有的对象 Y,攻击者虚假地声称拥有 X 而不是 Y,因此受害者将 Y 作为针对 X 的增量发送。此增量向攻击者揭示了 X 中与 Y 相似的区域。

BUG

目前,使用 --recurse-submodules 只能拉取已检出子模块中的新提交。例如,当上游在刚刚拉取的超级项目提交中添加了一个新子模块时,该子模块本身无法被拉取,导致以后无法在不再次拉取的情况下检出该子模块。预计这将在未来的 Git 版本中修复。

GIT

Git[1] 套件的一部分

scroll-to-top