Git
简体中文 ▾ Topics ▾ Latest version ▾ git-pull last updated in 2.44.0

名称

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

概述

git pull [<选项>] [<仓库> [<引用规范>…​]]

描述

将远程版本库的修改并入当前分支。 如果当前分支落后于远程分支,那么默认情况下,它将快速合并当前分支以匹配远程分支。 如果当前分支和远程分支有分歧,用户需要用 --rebase--no-rebase(或 pull.rebase 中的相应配置选项)来指定如何调和分歧的分支。

更确切地说,git pull 运行 git fetch 并给出参数,然后根据配置选项或命令行标志,调用 git rebasegit merge 来协调不同的分支。

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

<仓库> 和 < 分支 > 的默认值是从 git-branch[1] --track 设置的当前分支的 "远程" 和 "合并" 配置中读取。

假设存在以下历史,且当前分支为"master":

	  A---B---C master on origin
	 /
    D---E---F---G master
	^
	你仓库中的 origin/master

然后,"git pull" 将从远程的 master 分支获取并重放自它与本地 master(即 E)分歧以来的变化,直到它在 master 之上的当前提交(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])。

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

如果更新是通过合并完成的,子模块的冲突就会被解决并被检查出来。

与合并有关的选项

--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[<keyid>]
--gpg-sign[=<键 ID>]
--no-gpg-sign

对合并后的提交进行 GPG 签名。keyid 参数是可选的,默认为提交者的身份;如果指定,它必须与选项连在一起,不能有空格。--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 "预告片。 签名的意义取决于你所提交的项目。 例如,它可以证明提交者有权利在项目许可下提交作品,或者同意一些贡献者的陈述,如开发者的原产地证书。 关于Linux内核和Git项目使用的证书,请参见http://developercertificate.org)。 请查阅你要贡献的项目的文档或领导层,以了解该项目如何使用签名。

--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 事件hook。 当给定 `--no-verify`时,这些将不会执行。 参见 githooks[5]。 只有在合并的时候才有用。

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

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

-X <选项>
--strategy-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]

为真时,在获取后将当前分支变基到上游分支之上。如果有一个远程跟踪的分支与上游分支相对应,并且上游分支在上次获取后被重新建立了基础,那么变基就会使用该信息以避免重新建立非本地的变化。

当设置为 merges 时,使用 git rebase --rebase-merges 进行重建,这样本地的合并提交就会包含在重建中(详见 git-rebase[1])。

如果为false,则将上游分支合并到当前分支中。

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

如果你想让 git pull 总是使用 --rebase 而不是合并,请参见 git-config[1] 中的 pull.rebase, branch.< 分支名 >.rebasebranch.autoSetupRebase

Note
这是一种潜在的「危险的」操作模式。 它重写了历史,当你已经发布了这些历史时,这并不是一个好兆头。 除非你仔细阅读了git-rebase[1],否则请「不要」使用这个选项。
--no-rebase

这是对 --rebase=false 的简写。

与获取有关的选项

--[no-]all

获取所有远程控制。这将覆盖配置变量 fetch.all

-a
--append

.git/FETCH_HEAD 的现有内容中添加获取的引用名称和对象名称。 如果没有这个选项,.git/FETCH_HEAD 中的旧数据将被覆盖。

--atomic

使用一个原子事务来更新本地索引。要么所有的引用都被更新,要么在出错时,没有引用被更新。

--depth=<深度>

限制从每个远程分支历史的顶端获取指定数量的提交。如果获取的是由 git clone 创建的 浅层 仓库,并使用 --depth=<depth> 选项(见 git-clone[1]),则加深或缩短历史,达到指定数量的提交。深化后的提交的标签不会被获取。

--deepen=<深度>

与—​depth类似,只是它指定了从当前浅层边界开始的提交数量,而不是从每个远程分支历史的顶端开始。

--shallow-since=<日期>

加深或缩短浅层仓库的历史,包括<日期>之后所有可触及的提交。

--shallow-exclude=<修订版本>

深化或缩短浅层版本库的历史,以排除从指定的远程分支或标记中可以到达的提交。 这个选项可以指定多次。

--unshallow

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

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

--update-shallow

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

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

默认情况下,Git 会向服务器报告从所有本地引用中可触及的提交,以寻找共同的提交,试图减少待接收的打包文件的大小。如果指定的话,Git将只报告从给定提示中的可达提交。 当用户知道哪个本地引用可能与被获取的上游引用有共同的提交时,这会加快抓取文件的速度。

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

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

参见 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] 中的输出部分。

这与 --recurse-submodules=[yes|on-demand] 选项不兼容,并且优先于 fetch.output 配置选项。

-f
--force

正如讨论的那样,当 git fetch<源>:<目标> 引用规范一起使用时,它可能会拒绝更新本地分支 在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
--jobs=<n>

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

如果指定了 --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进行通信时,将给定的字符串传输到服务器。给定的字符串不得包含NUL或LF字符。服务器对服务器选项(包括未知选项)的处理是取决于服务器。当给出多个`--server-option=<option>`时,它们都按照命令行中列出的顺序发送到另一端。

--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 地址。

<仓库>

作为获取或拉动操作的来源的 "remote" 仓库。 这个参数可以是一个 URL(见下面 GIT URLS 一节),也可以是一个远程仓库的名称(见下面 远程 一节)。

<引用规范>

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

<引用规范> 参数的格式是一个可选的加号 + ,后面是源 <src>,后面是冒号 :,后面是目标引用 <dst>。 当 <dst> 为空时,冒号可以被省略。 <src> 通常是一个引用,但它也可以是一个完全拼写的十六进制对象名称。

一个 <引用规范> 可以在其<src>中包含一个`*'来表示一个简单的模式匹配。这样的 refspec 的功能就像一个 glob,可以匹配任何具有相同前缀的 ref。匹配 <引用规范> 必须在 <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),无论是将目录树对象换成二进制文件,还是将一个提交换成另一个没有前一个提交作为祖先的提交等等。

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

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

Note
当你想获取的远程分支已知会被定期回溯和重定向时,预计它的新提示不会是其先前提示的后代(如你上次获取时存储在远程跟踪分支中的提示)。 你应该使用 + 号来表示对这类分支需要进行非快速合并式更新。 没有办法确定或声明一个分支将以这种行为在仓库中提供;拉取的用户只是必须知道这是一个分支的预期使用模式。
Note
git pull 命令行上直接列出多个 <引用规范> 和在 <仓库> 的配置中拥有多个`remote.<仓库>.fetch` 条目以及在没有任何明确的 <引用规范> 参数的情况下运行 git pull 命令是有区别的。 在命令行上明确列出的 <引用规范> 在获取后总是被合并到当前分支。 换句话说,如果你列出一个以上的远程引用,git pull 将创建一个多路合并。 另一方面,如果你没有在命令行中列出任何明确的 <引用规范> 参数,git pull 将获取它在 remote.<仓库>.fetch 配置中发现的所有 <引用规范>,并且只将发现的第一个<引用规范> 合并到当前分支。 这是因为很少有人从远程引用中多路合并,而通过获取多个远程头来一次性跟踪多个远程头往往是有用的。

GIT 地址

通常,地址包含有关传输协议,远程服务器的地址以及仓库路径的信息。对于某些传输协议,一些信息可能会缺失。

Git 支持 ssh,git,http 和 https 协议(此外,可以使用 ftp 和 ftps 进行抓取,但这效率低下且不建议使用;请勿使用)。

本地传输(即 git:// URL)不进行身份验证,在不安全的网络上应谨慎使用。

以下是上述几个传输协议的格式:

  • ssh://[user@]host.xz[:port]/path/to/repo.git/

  • git://host.xz[:port]/path/to/repo.git/

  • http[s]://host.xz[:port]/path/to/repo.git/

  • ftp[s]://host.xz[:port]/path/to/repo.git/

ssh 协议也可以使用类似 scp 的语法:

  • [user@]host.xz:path/to/repo.git/

仅当第一个冒号之前没有斜杠时才能识别此语法。这有助于区分包含冒号的本地路径。例如,可以将本地路径 foo:bar 指定为绝对路径,或者将 ./foo:bar 指定为绝对路径,以避免被误识别为 ssh url。

ssh 和 git 协议还支持 ~username 扩展:

  • ssh://[user@]host.xz[:port]/~[user]/path/to/repo.git/

  • git://host.xz[:port]/~[user]/path/to/repo.git/

  • [user@]host.xz:/~[user]/path/to/repo.git/

对于本地仓库(Git 本身也支持),可以使用以下语法:

  • /path/to/repo.git/

  • file:///path/to/repo.git/

这两种语法几乎是等效的,除了在克隆时,前者暗含 --local 选项。有关详细信息,请参阅 git-clone[1]

git clonegit fetchgit pull(但不包括 git push)也会接受合适的捆绑包文件。参见 git-bundle[1]

当 Git 不知道如何处理某种传输协议时,它会尝试使用 remote-<传输方式> 远程帮助程序(如果存在)。要显式请求远程帮助程序,可以使用以下语法:

  • <传送>::<地址>

其中,<地址> 可以是路径,服务器与路径,也可以是可被调用的特定远程帮助程序识别的类似于网页地址的任意字符串。有关详细信息,请参阅 gitremote-helpers[7]

如果存在大量类似名称的远程仓库,并且您要为其使用不同的格式(这样,您使用的地址将被重写为有效的地址),则可以创建以下形式的配置:

	[url "<实际基础网址>"]
		insteadOf = <其他基础网址>

例如,有如下:

	[url "git://git.host.xz/"]
		insteadOf = host.xz:/path/to/
		insteadOf = work:

诸如 "work:repo.git" 或 "host.xz:/path/to/repo.git" 的地址会在任何类似于 "git://git.host.xz/repo" 地址的上下文中重写。

如果要重写仅用于推送的地址,可以创建表单的配置部分:

	[url "<实际基础网址>"]
		pushInsteadOf = <其他基础网址>

例如,有如下:

	[url "ssh://example.org/"]
		pushInsteadOf = git://example.org/

类似于 "git://example.org/path/to/repo.git" 的地址会被重写为 "ssh://example.org/path/to/repo.git",用于推送。但拉取代码时仍然使用原始的地址。

REMOTES

可以用下面的一个名称代替URL作为`<repository>`的参数:

  • 一个远端的配置文件在此仓库的git配置文件: $GIT_DIR/config

  • 这个文件在`$GIT_DIR/remotes`目录下,或者

  • 这个文件在`$GIT_DIR/branches`目录下。

所有这些也允许你从命令行中省略refspec,因为它们都包含一个git默认使用的refspec。

在配置文件中命名为 remote

你可以选择提供你之前用 git-remote[1]、linkgit:git-config[1] 或甚至通过手动编辑 $GIT_DIR/config 文件配置的远程名称。 这个远程的 URL 将被用来访问仓库。 当你没有在命令行上提供引用规范时,这个远程仓库的引用规范将被默认使用。 配置文件中的条目会像这样:

	[remote "<名称>"]
		url = <地址>
		pushurl = <推送地址>
		push = <引用规范>
		fetch = <引用规范>

<推送地址> 仅用于推送。它是可选的,默认为 <URL>。向远程推送会影响所有定义的推送urls,如果没有定义推送urls,则推送到所有定义的url。然而,如果定义了多个 URL,fetch 将只从第一个定义的 URL 获取。

$GIT_DIR/remotes 中的命名文件

你可以选择提供 $GIT_DIR/remotes 中的文件名。 这个文件中的 URL 将被用来访问仓库。 当你没有在命令行上提供引用规范时,该文件中的引用规范将被作为默认使用。 这个文件应该有以下格式:

	URL: one of the above URL format
	Push: <引用规范>
	Pull: <引用规范>

Push: 行被 git push 使用,Pull: 行被 git pullgit fetch 使用。 可以为额外的分支映射指定多个 Push:Pull: 行。

$GIT_DIR/branches 中的命名文件

你可以选择提供 $GIT_DIR/branches 中的文件名。 这个文件中的 URL 将被用来访问仓库。 这个文件应该有以下格式:

	<URL>#<head>

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

根据不同的操作,如果你没有在命令行上提供一个引用规范,git 会使用以下其中一个。 <分支> 是该文件在 $GIT_DIR/branches 中的名称,<头分支> 默认为 master

git fetch 使用:

	refs/heads/<头分支>:refs/heads/<分支>。

git push 使用:

	HEAD:refs/heads/<头分支>。

合并战略

合并机制( git mergegit pull 命令)允许用 -s 选项来选择后端’合并策略'。 一些策略也可以采取自己的选项,可以通过给 git merge 和/或 git pull-X<选项> 参数来传递。

ort 策略

这是拉取或合并一个分支时的默认合并策略。 这个策略只能使用三方合并算法解决两个头。 当有一个以上的共同祖先可用于三方合并时,它会创建一个共同祖先的合并树,并将其作为三方合并的参考树。 据报道,通过对Linux 2.6内核开发历史中的实际合并提交的测试,这导致了较少的合并冲突,而不会引起错误的合并。 此外,这个策略可以检测并处理涉及重命名的合并。 它并不使用检测到的副本。 这个算法的名字是一个缩写("Ostensibly Recursive’s Twin"),来自于它是作为以前的默认算法`recursive`的替代而编写的。

ort 策略可以采取以下选项:

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> 的同义词。

subtree[=<路径>]

这个选项是 子树 策略的更高级形式,该策略对两棵树在合并时必须如何移位以相互匹配进行猜测。 相反,指定的路径是前缀(或从开始剥离),以使两棵树的形状相匹配。

recursive

这只能用三方合并算法解决两个头。 当有一个以上的共同祖先可用于三方合并时,它会创建一个共同祖先的合并树,并使用它作为三方合并的参考树。 据报道,通过对Linux 2.6内核开发历史中的实际合并提交的测试,这导致了较少的合并冲突,而不会引起错误的合并。 此外,它可以检测并处理涉及重命名的合并。 它并不使用检测到的副本。 从Git v0.99.9k到v2.33.0,这是解决双头的默认策略。

recursive 策略采用与 ort 相同的选项。 然而,有三个 ort 忽略的额外选项(上面没有记录),对 recursive 策略有潜在的作用:

patience

废弃的,diff-algorithm=patience 的同义词。

diff-algorithm=[patience|minimal|histogram|myers]

在合并时使用不同的差异算法,这可以帮助避免由于不重要的匹配行(比如不同函数的大括号)而发生的错误合并。 参见git-diff[1] --diff-algorithm。 注意,ort 特定 diff-algorithm=histogram,而`recursive`默认为`diff.algorithm`配置设置。

no-renames

关闭重名检测。这覆盖了 merge.renames 的配置变量。 参见git-diff[1] --no-renames

resolve

这只能用三方合并算法解决两个头(即当前分支和你拉来的另一个分支)。 它试图仔细检测纵横交错的合并歧义。 它不处理重名。

octopus

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

ours

这可以解决任何数量的头,但合并的结果总是当前分支头的树,有效地忽略了所有其他分支的变化。 它是用来取代侧边分支的旧开发历史的。 注意,这与 recursive 合并策略的-Xours选项不同。

subtree

这是一个修正的 ort 策略。当合并树A和B时,如果B对应于A的子树,B首先被调整为与A的树结构相匹配,而不是在同一级别读取树。这种调整也是针对共同祖先树进行的。

对于使用三方合并的策略(包括默认的 ort 策略),如果在两个分支上都做了修改,但后来在其中一个分支上被撤销,那么这个修改就会出现在合并后的结果中;有些人觉得这种行为令人困惑。 出现这种情况是因为在执行合并时只考虑头部和合并基数,而不是单个提交。 因此,合并算法认为被恢复的修改根本就没有变化,而是用被修改的版本来代替。

默认行为

人们经常使用 git pull 而不给任何参数。 传统上,这等同于说 git pull origin。 然而,当配置 branch.<分支名>.remote 在分支 < 分支名 > 上出现时,该值会被用来代替 origin

为了确定使用什么 URL 来获取,将查询配置 remote.<远程名>.url 的值,如果没有这样的变量,将使用 $GIT_DIR/remotes/< 远程名 >URL: 一行的值。

当命令行上没有任何引用规范参数时,为了确定要获取哪些远程分支(并可选择存储在远程跟踪分支中),会查询配置变量 remote.<远程名>.fetch 的值,如果没有,会查询 $GIT_DIR/remotes/< 远程名 > 并使用其 Pull: 行。 除了在『选项』部分描述的引用规范格式之外,你还可以有一个看起来像这样的引用规范通配符:

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

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

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

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

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

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

  2. 如果引用规范是全局的, 则不合并任何信息。

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

实例

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

    $ git pull
    $ git pull origin

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

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

    $ git pull origin next

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

    $ git fetch origin
    $ git merge origin/next

如果你尝试了一次拉取,导致了复杂的冲突,想重新开始,你可以用 git reset 来恢复。

安全

获取和推送协议并不是为了防止一方从另一个版本库窃取不打算共享的数据。如果你有需要保护的私人数据不被恶意的同行窃取,你最好的选择是把它存储在另一个资源库中。这同时适用于客户端和服务器。特别是,服务器上的命名空间对于读取访问控制是无效的;你应该只将命名空间的读取访问权授予那些你信任的可以读取整个版本库的客户。

已知的攻击媒介如下:

  1. 受害者发送 "have" 行,宣传它所拥有的对象的 ID,这些对象并没有明确地打算被共享,但如果对等体也有这些对象,就可以用来优化传输。攻击者选择了一个对象 ID X 来窃取,并向 X 发送了一个引用,但不需要发送 X 的内容,因为受害者已经拥有它。现在,受害者认为攻击者拥有 X,它稍后将 X 的内容发回给攻击者。(这种攻击对于客户端来说在服务器上执行是最直接的,通过在客户端可以访问的命名空间中创建一个 X 的引用,然后获取它。服务器最可能在客户端执行的方式是将 X "合并" 到一个公共分支,并希望用户在这个分支上做额外的工作,然后在没有注意到合并的情况下将其推回给服务器。)

  2. 和 #1 一样,攻击者选择了一个对象 ID X 来偷窃。受害者发送了一个攻击者已经拥有的对象 Y,攻击者谎称拥有 X 而没有 Y,因此受害者发送 Y 作为对 X 的d elta,delta 向攻击者显示了 X 中与 Y 相似的区域。

漏洞

使用 --recurse-submodules 现在只能获取已经签出的子模块的新提交。例如,当上游在刚刚获取的超级项目的提交中添加了一个新的子模块时,子模块本身不能被获取,这使得以后不需要再次获取就能签出该子模块。这个问题有望在未来的 Git 版本中被修复。

GIT

属于 git[1] 文档

scroll-to-top