English ▾ 主题 ▾ 最新版本 ▾ git-pull 最后更新于 2.49.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> 的默认值是从当前分支的 "remote" 和 "merge" 配置中读取的,由 git-branch[1] --track 设置。

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

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

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

	  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。

如果通过 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=<mode>

此选项确定在提交之前如何清理合并消息。有关更多详细信息,请参阅 git-commit[1]。此外,如果 <mode> 的值为 scissors,则在发生合并冲突的情况下,scissors 将附加到 MERGE_MSG,然后传递给提交机制。

--ff-only

仅当没有不同的本地历史记录时才更新到新的历史记录。这是在未提供协调不同历史记录的方法(通过 --rebase=* 标志)时的默认设置。

--ff
--no-ff

当合并而不是 rebase 时,指定当合并的历史记录已经是当前历史记录的后代时,如何处理合并。如果请求合并,则除非合并未存储在其自然位置的带注释(可能已签名)的标签 refs/tags/ 层次结构中,否则 --ff 是默认设置,在这种情况下,假定为 --no-ff

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

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

-S[<keyid>]
--gpg-sign[=<keyid>]
--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 项目使用的证书,请参阅 https://developercertificate.org。)请查阅你正在贡献的项目的文档或领导层,以了解如何在该项目中使用签名。

--no-signoff 选项可用于反击命令行上的早期 --signoff 选项。

--stat
-n
--no-stat

在合并结束时显示一个 diffstat。 diffstat 也可以通过配置选项 merge.stat 控制。

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

--squash
--no-squash

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

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

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

仅在合并时有用。

--[no-]verify

默认情况下,将运行 pre-merge 和 commit-msg 钩子。 当给出 --no-verify 时,这些钩子将被绕过。 另请参阅 githooks[5]。 仅在合并时有用。

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

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

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

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

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

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

仅在合并时有用。

--summary
--no-summary

与 --stat 和 --no-stat 同义; 这些已被弃用,将来将被删除。

--autostash
--no-autostash

在操作开始之前自动创建一个临时储藏条目,将其记录在 ref MERGE_AUTOSTASH 中,并在操作结束后应用它。 这意味着您可以在一个脏的工作树上运行该操作。 但是,请谨慎使用:成功合并后的最终储藏应用程序可能会导致非显而易见的冲突。

--allow-unrelated-histories

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

仅在合并时有用。

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

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

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

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

当为 interactive 时,启用 rebase 的交互模式。

如果您希望 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

将已获取的 ref 的 ref 名称和对象名称附加到 .git/FETCH_HEAD 的现有内容中。 如果没有此选项,.git/FETCH_HEAD 中的旧数据将被覆盖。

--atomic

使用原子事务更新本地 refs。 所有 refs 要么都被更新,要么在出错时,没有 refs 被更新。

--depth=<depth>

将获取限制为每个远程分支历史记录的 tip 中指定的提交数量。 如果获取到使用 git clone--depth=<depth> 选项创建的存储库(请参见 git-clone[1]),则加深或缩短历史记录到指定的提交数量。 不会获取加深提交的标签。

--deepen=<depth>

与 --depth 类似,不同之处在于它指定了从当前浅边界开始的提交数量,而不是从每个远程分支历史记录的 tip 开始的提交数量。

--shallow-since=<date>

加深或缩短浅存储库的历史记录,以包括 <date> 之后的所有可达提交。

--shallow-exclude=<ref>

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

--unshallow

如果源存储库是完整的,则将浅存储库转换为完整的存储库,从而消除浅存储库施加的所有限制。

如果源存储库是浅的,则尽可能多地获取,以便当前存储库与源存储库具有相同的历史记录。

--update-shallow

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

--negotiation-tip=<commit|glob>

默认情况下,Git 会将从所有本地 refs 可达的提交报告给服务器,以查找共同提交,从而尝试减小要接收的 packfile 的大小。 如果指定,Git 将仅报告从给定 tips 可达的提交。 当用户知道哪个本地 ref 可能与正在获取的上游 ref 具有共同提交时,这对于加速获取非常有用。

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

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

另请参见 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> refspec 一起使用时,它可能会拒绝更新本地分支,如 git-fetch[1] 文档的 <refspec> 部分中所讨论的那样。 此选项会覆盖该检查。

-k
--keep

保留下载的 pack。

--prefetch

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

-p
--prune

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

--no-tags

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

--refmap=<refspec>

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

-t
--tags

从远程获取所有标签(即,将远程标签 refs/tags/* 获取到具有相同名称的本地标签中),以及其他将被获取的内容。 仅使用此选项不会使标签受到修剪,即使使用了 --prune(尽管如果标签也是显式 refspec 的目标,则无论如何都可以修剪标签;请参见 --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 URLS 部分)或远程名称(参见下面的 REMOTES 部分)。

<refspec>

指定要抓取的引用以及要更新的本地引用。 如果命令行上没有出现 <refspec>,则改为从 remote.<repository>.fetch 变量中读取要抓取的引用(参见 git-fetch[1] 中的“CONFIGURED REMOTE-TRACKING BRANCHES”部分)。

<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* 命令行上列出多个 <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>

另一种类似于 scp 的语法也可以与 ssh 协议一起使用

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

REMOTES

可以使用以下任一项的名称,而不是 URL 作为 <repository> 参数:

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

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

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

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

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

你可以选择提供一个远程仓库的名称,这个远程仓库是你之前使用 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,如果没有定义 pushurls,则会影响所有定义的 urls。 但是,如果定义了多个 urls,则抓取只会从第一个定义的 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> 是可选的。

根据操作的不同,如果你没有在命令行上提供 refspec,git 将使用以下 refspec 之一。 <branch> 是该文件在 $GIT_DIR/branches 中的名称,<head> 默认为 master

git fetch 使用

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

git push 使用

	HEAD:refs/heads/<head>

合并策略

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

ort

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

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

_ort_ 策略可以采用以下选项:

ours

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

这不应与 _ours_ 合并策略混淆,该策略甚至根本不查看另一个树包含的内容。 它会丢弃另一个树所做的一切,并声明 _our_ 历史记录包含其中发生的一切。

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

  • 如果 _their_ 版本仅对行引入空白更改,则使用 _our_ 版本;

  • 如果 _our_ 版本引入空白更改,但 _their_ 版本包含实质性更改,则使用 _their_ 版本;

  • 否则,合并以通常的方式进行。

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[=<path>]

此选项是 *subtree* 策略的更高级形式,该策略会猜测两个树在合并时必须如何移动才能相互匹配。 相反,指定路径被添加前缀(或从开头剥离)以使两个树的形状匹配。

recursive

这只能使用 3-way 合并算法解决两个头。 当有多个可用作 3-way 合并的共同祖先时,它会创建一个共同祖先的合并树,并将其用作 3-way 合并的参考树。 据报道,通过对从 Linux 2.6 内核开发历史记录中提取的实际合并提交进行的测试,这可以减少合并冲突,而不会导致合并错误。 此外,这可以检测和处理涉及重命名的合并。 它不使用检测到的副本。 这是从 Git v0.99.9k 到 v2.33.0 解决两个头的默认策略。

对于作为子模块的路径,与 _ort_ 相同的注意事项适用于此策略。

_recursive_ 策略采用与 _ort_ 相同的选项。 但是,还有三个 _ort_ 忽略的附加选项(上面未记录),这些选项可能与 _recursive_ 策略一起使用:

patience

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

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

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

no-renames

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

resolve

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

octopus

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

ours

这解决了任意数量的头,但是合并的结果树始终是当前分支头的树,从而有效地忽略了来自所有其他分支的所有更改。 它旨在用于取代侧分支的旧开发历史记录。 请注意,这与 _recursive_ 合并策略的 -Xours 选项不同。

subtree

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

对于使用 3-way 合并的策略(包括默认策略 _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: 行。除了 OPTIONS 部分中描述的 refspec 格式外,还可以使用如下所示的通配 refspec:

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

通配 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 是通配符 refspec,则不合并任何内容。

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

示例

  • 更新您从克隆的存储库的远程跟踪分支,然后将其中一个合并到您当前的分支中

    $ git pull
    $ git pull origin

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

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

    $ git pull origin next

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

    $ git fetch origin
    $ git merge origin/next

如果您尝试了一个 pull 操作,导致了复杂的冲突并希望重新开始,您可以使用 *git reset* 来恢复。

安全性

fetch 和 push 协议的设计目的不是为了防止一方从另一方窃取不打算共享的存储库数据。如果您有需要保护免受恶意对等方侵害的私有数据,最好的选择是将它存储在另一个存储库中。这适用于客户端和服务器。特别是,服务器上的命名空间对于读取访问控制无效;您应该只向您信任的客户端授予对命名空间的读取访问权限,以便他们可以读取整个存储库。

已知的攻击媒介如下:

  1. 受害者发送“have”行,宣告它拥有的对象的 ID,这些对象不是明确打算共享的,但如果对等方也拥有它们,则可以用来优化传输。攻击者选择要窃取的对象 ID X 并将 ref 发送到 X,但不需要发送 X 的内容,因为受害者已经拥有它。现在,受害者认为攻击者拥有 X,并且稍后会将 X 的内容发送回攻击者。(对于客户端在服务器上执行此攻击最简单的方法是在客户端有权访问的命名空间中创建对 X 的引用,然后获取它。服务器在客户端上执行此操作的最可能方法是将 X“合并”到公共分支中,并希望用户在此分支上进行额外的工作并将其推送回服务器而没有注意到合并。)

  2. 与#1中一样,攻击者选择要窃取的对象ID X。受害者发送攻击者已拥有的对象Y,并且攻击者错误地声称拥有X而不拥有Y,因此受害者将Y作为相对于X的增量发送。增量向攻击者显示X中与Y相似的区域。

错误

目前,使用 --recurse-submodules 只能获取已经检出的子模块中的新提交。例如,当上游在超级项目的刚刚获取的提交中添加了一个新的子模块时,无法获取子模块本身,从而无法在以后检出该子模块,而无需再次执行 fetch。预计在未来的 Git 版本中会修复此问题。

GIT

属于 git[1] 套件的一部分

scroll-to-top