Setup and Config
Getting and Creating Projects
Basic Snapshotting
Branching and Merging
Sharing and Updating Projects
Inspection and Comparison
Patching
Debugging
External Systems
Server Admin
Guides
- gitattributes
- Command-line interface conventions
- Everyday Git
- Frequently Asked Questions (FAQ)
- Glossary
- Hooks
- gitignore
- gitmodules
- Revisions
- Submodules
- Tutorial
- Workflows
- All guides...
Administration
Plumbing Commands
-
2.54.0
2026-04-20
-
2.53.0
2026-02-02
-
2.52.0
2025-11-17
- 2.51.2 no changes
-
2.51.1
2025-10-15
-
2.51.0
2025-08-18
- 2.50.1 no changes
-
2.50.0
2025-06-16
- 2.49.1 no changes
-
2.49.0
2025-03-14
- 2.48.1 → 2.48.2 no changes
-
2.48.0
2025-01-10
- 2.47.2 → 2.47.3 no changes
-
2.47.1
2024-11-25
- 2.46.3 → 2.47.0 no changes
-
2.46.2
2024-09-23
- 2.45.1 → 2.46.1 no changes
-
2.45.0
2024-04-29
- 2.44.1 → 2.44.4 no changes
-
2.44.0
2024-02-23
- 2.43.2 → 2.43.7 no changes
-
2.43.1
2024-02-09
-
2.43.0
2023-11-20
- 2.42.1 → 2.42.4 no changes
-
2.42.0
2023-08-21
- 2.41.1 → 2.41.3 no changes
-
2.41.0
2023-06-01
- 2.40.1 → 2.40.4 no changes
-
2.40.0
2023-03-12
- 2.36.1 → 2.39.5 no changes
-
2.36.0
2022-04-18
- 2.35.1 → 2.35.8 no changes
-
2.35.0
2022-01-24
- 2.34.1 → 2.34.8 no changes
-
2.34.0
2021-11-15
- 2.33.2 → 2.33.8 no changes
-
2.33.1
2021-10-12
-
2.33.0
2021-08-16
- 2.32.1 → 2.32.7 no changes
-
2.32.0
2021-06-06
- 2.31.1 → 2.31.8 no changes
-
2.31.0
2021-03-15
- 2.30.1 → 2.30.9 no changes
-
2.30.0
2020-12-27
- 2.29.1 → 2.29.3 no changes
-
2.29.0
2020-10-19
- 2.27.1 → 2.28.1 no changes
-
2.27.0
2020-06-01
- 2.25.2 → 2.26.3 no changes
-
2.25.1
2020-02-17
-
2.25.0
2020-01-13
- 2.24.1 → 2.24.4 no changes
-
2.24.0
2019-11-04
- 2.23.1 → 2.23.4 no changes
-
2.23.0
2019-08-16
- 2.22.2 → 2.22.5 no changes
-
2.22.1
2019-08-11
-
2.22.0
2019-06-07
- 2.20.1 → 2.21.4 no changes
-
2.20.0
2018-12-09
- 2.19.1 → 2.19.6 no changes
-
2.19.0
2018-09-10
- 2.18.1 → 2.18.5 no changes
-
2.18.0
2018-06-21
- 2.17.1 → 2.17.6 no changes
-
2.17.0
2018-04-02
-
2.16.6
2019-12-06
-
2.15.4
2019-12-06
-
2.14.6
2019-12-06
-
2.13.7
2018-05-22
- 2.12.5 no changes
-
2.11.4
2017-09-22
- 2.10.5 no changes
-
2.9.5
2017-07-30
-
2.8.6
2017-07-30
-
2.7.6
2017-07-30
-
2.6.7
2017-05-05
- 2.5.6 no changes
-
2.4.12
2017-05-05
-
2.3.10
2015-09-28
- 2.2.3 no changes
-
2.1.4
2014-12-17
-
2.0.5
2014-12-17
描述
将远程仓库中的更改集成到当前分支中。
首先,git pull 会使用相同参数(不包括 merge 选项)运行 git fetch,以获取远程分支。然后它会决定要集成哪个远程分支:如果你执行 git pull 时不带参数,则默认使用当前分支的 upstream。之后,它会将该分支集成到当前分支中。
将远程分支集成到当前分支主要有 4 种方式:
-
gitpull--ff-only只会执行“快进”更新:如果你的本地分支已经与远程分支发生分叉,它就会失败。这是默认行为。 -
gitpull--rebase会运行gitrebase -
gitpull--no-rebase会运行gitmerge。 -
gitpull--squash会运行gitmerge--squash
你也可以通过配置 pull.rebase、pull.squash 或 pull.ff 选项来指定自己偏好的行为。
如果在 merge 或 rebase 过程中出现你不想处理的冲突,可以安全地使用 git merge --abort 或 git rebase --abort 来中止。
选项
- <仓库>
-
作为获取或拉动操作的来源的 "remote" 仓库。 这个参数可以是一个 URL(见下面 GIT URLS 一节),也可以是一个远程仓库的名称(见下面 远程 一节)。
默认为当前分支已配置的上游分支;如果没有,则为
origin。关于如何配置上游分支,请参见下文 UPSTREAM BRANCHES。 - <引用规范>
-
要获取并集成到当前分支中的分支或其他引用,例如
gitpulloriginmain中的main。默认值为当前分支配置的上游分支。这可以是一个分支、标签或其他一组引用。完整语法请参见下文“Options related to fetching”下的 <refspec>,关于
gitpull如何使用此参数来决定集成哪个远程分支,请参见下文 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])。
如果检出是通过变基完成的,那么本地子模块的提交也会被变基。
如果更新是通过合并完成的,子模块的冲突就会被解决并被检查出来。
与合并有关的选项
-
--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选项。
Git 没有(也不会有)一个配置变量用于默认启用
--signoff命令行选项;更多细节参见 gitfaq[7] 中的commit.signoff条目。
-
--stat -
-n -
--no-stat -
在合并结束时显示一个差异状态。差异状态也由配置选项merge.stat控制。
使用-n或—no-stat,在合并结束时不显示差异状态。
-
--compact-summary -
在合并结束时显示简洁摘要。
-
--squash -
--no-squash -
产生工作区和索引状态,就像发生了真正的合并一样(除了合并信息),但不实际提交,不移动`HEAD`,也不记录`$GIT_DIR/MERGE_HEAD`(以导致下一个`git commit`命令创建一个合并提交)。 这允许你在当前分支的基础上创建一个单一的提交,其效果与合并另一个分支相同(如果是多路分支,则更多)。
使用 --no-squash 进行合并并提交结果。这个选项可以用来覆盖 --squash 选项。
使用 --squash,--commit 是不允许的,而且会失败。
只有在合并的时候才有用。
-
--verify -
--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中,并在操作结束后应用。 这意味着可以在脏工作区上运行操作。 但是,请谨慎使用:成功合并后的最终暂存应用可能会导致非实质性冲突。 -
默认情况下,`git merge`命令拒绝合并那些没有共同祖先的历史。 当合并两个独立开始的项目的历史时,这个选项可以用来覆盖这个安全性。由于这是一个非常罕见的情况,没有配置变量来默认启用,也不会被添加。
只有在合并的时候才有用。
-
-r -
--rebase[=(true|merges|false|interactive)] -
-
true -
为真时,在获取后将当前分支变基到上游分支之上。如果有一个远程跟踪的分支与上游分支相对应,并且上游分支在上次获取后被重新建立了基础,那么变基就会使用该信息以避免重新建立非本地的变化。
-
merges -
当设置为
merges时,使用gitrebase--rebase-merges进行重建,这样本地的合并提交就会包含在重建中(详见 git-rebase[1])。 -
false -
如果为false,则将上游分支合并到当前分支中。
-
interactive -
当设置为
interactive时,启用变基的交互模式。
如果你想让
gitpull总是使用--rebase而不是合并,请参见 git-config[1] 中的pull.rebase, branch.< 分支名 >.rebase 和branch.autoSetupRebase。+
Note这是一种潜在的「危险的」操作模式。 它重写了历史,当你已经发布了这些历史时,这并不是一个好兆头。 除非你仔细阅读了git-rebase[1],否则请「不要」使用这个选项。 -
-
--no-rebase -
这是对 --rebase=false 的简写。
与获取有关的选项
-
--all -
--no-all -
获取所有远程控制。这将覆盖配置变量
fetch.all。 -
-a -
--append -
在
.git/FETCH_HEAD的现有内容中添加获取的引用名称和对象名称。 如果没有这个选项,.git/FETCH_HEAD中的旧数据将被覆盖。 -
--atomic -
使用一个原子事务来更新本地索引。要么所有的引用都被更新,要么在出错时,没有引用被更新。
-
--depth<深度> -
限制从每个远程分支历史的顶端获取指定数量的提交。如果获取的是由
gitclone创建的 浅层 仓库,并使用--depth=<depth> 选项(见 git-clone[1]),则加深或缩短历史,达到指定数量的提交。深化后的提交的标签不会被获取。 - --deepen=<深度>
-
与—depth类似,只是它指定了从当前浅层边界开始的提交数量,而不是从每个远程分支历史的顶端开始。
-
--shallow-since=<日期> -
加深或缩短浅层仓库的历史,包括<日期>之后所有可触及的提交。
-
--shallow-exclude=<引用> -
深化或缩短浅层仓库的历史,以排除从指定的远程分支或标签中可以到达的提交。 这个选项可以指定多次。
-
--unshallow -
如果源仓库是完整的,将浅层资源库转换为完整的仓库,消除浅层仓库带来的所有限制。
如果源仓库是浅层的,尽可能多的获取,使当前仓库的历史与源仓库相同。
-
--update-shallow -
默认情况下,当从浅层仓库获取时,
gitfetch会拒绝需要更新 .git/shallow 的引用。这个选项更新了 .git/shallow 并接受这样的引用。 - --negotiation-tip=<提交|通配符>
-
默认情况下,Git 会向服务器报告从所有本地引用中可触及的提交,以寻找共同的提交,试图减少待接收的打包文件的大小。如果指定的话,Git将只报告从给定提示中的可达提交。 当用户知道哪个本地引用可能与被获取的上游引用有共同的提交时,这会加快获取文件的速度。
这个选项可以指定多次;如果是这样,Git将报告从任何一个给定的提交中可达提交。
这个选项的参数可以是一个引用名称的通配符,一个引用,或者一个提交的SHA-1(可能是缩写的)。指定一个通配符相当于多次指定这个选项,为每个匹配的引用名称指定该选项。
参见 git-config[1] 中记录的
fetch.negotiationAlgorithm和push.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配置选项。 -
--filter=<过滤规范> -
使用部分克隆功能,请求服务器根据给定的对象过滤器发送可达对象的子集。使用
--filter时,提供的 <filter-spec> 用于部分获取。如果使用
--filter=auto,过滤规格将通过合并服务器为客户端接受的承诺远程仓库所通告的过滤规格来自动确定(参见 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[1] 中所讨论的,当
gitfetch与 <源>:<目标> 引用规范一起使用时,它可能会拒绝更新本地分支 这个选项覆盖了该检查。 -
-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>
-
将所有形式的 fetch 并行化,每次最多运行 <n> 个任务。
值为 0 将使用某个合理的默认值。
如果指定了
--multiple选项,不同的远程将被并行获取。如果多个子模块被取走,它们将并行获取。要独立控制它们,使用配置fetch.parallel和submodule.fetchJobs(见git-config[1])。通常情况下,并行的递归和多远程的提取会更快。默认情况下,检索是按顺序进行的,而不是并行的。
-
--set-upstream -
如果远程被成功获取,添加上游(跟踪)引用,由无参数的 git-pull[1] 和其他命令使用。更多信息,见 git-config[1] 中的
branch.<名称>.merge和branch.<名称>.remote。 - --upload-pack <upload-pack>
-
当给出时,并且要获取的仓库是由
gitfetch-pack处理的,--exec=<upload-pack> 被传递到命令中,为另一端运行的命令指定非默认路径。 -
--progress -
当标准错误流连接到终端时,除非指定了 -q,否则默认情况下会在标准错误流上报告进展状态。即使标准错误流没有指向终端,这个标志也会强制显示进度状态。
- -X <选项>
-
--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.<仓库>.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-receive的pre-fetch钩子。就像用 git-push[1] 推送一样,上面描述的所有关于不允许更新的规则都可以通过在引用规范中添加一个可选的前导词
+来覆盖(或者使用--force命令行选项)。唯一的例外是,无论如何强制都不能使refs/heads/*命名空间接受一个非提交对象。Note当你想获取的远程分支已知会被定期回溯和重定向时,预计它的新提示不会是其先前提示的后代(如你上次获取时存储在远程跟踪分支中的提示)。 你应该使用 +号来表示对这类分支需要进行非快速合并式更新。 没有办法确定或声明一个分支将以这种行为在仓库中提供;拉取的用户只是必须知道这是一个分支的预期使用模式。Note在 gitpull命令行上直接列出多个 <引用规范> 和在 <仓库> 的配置中拥有多个`remote.<仓库>.fetch` 条目以及在没有任何明确的 <引用规范> 参数的情况下运行gitpull命令是有区别的。 在命令行上明确列出的 <引用规范> 在获取后总是被合并到当前分支。 换句话说,如果你列出一个以上的远程引用,gitpull将创建一个多路合并。 另一方面,如果你没有在命令行中列出任何明确的 <引用规范> 参数,gitpull将获取它在remote.<仓库>.fetch配置中发现的所有 <引用规范>,并且只将发现的第一个<引用规范> 合并到当前分支。 这是因为很少有人从远程引用中多路合并,而通过获取多个远程头来一次性跟踪多个远程头往往是有用的。
GIT 地址
通常,地址包含有关传输协议,远程服务器的地址以及仓库路径的信息。对于某些传输协议,一些信息可能会缺失。
Git 支持 ssh,git,http 和 https 协议(此外,可以使用 ftp 和 ftps 进行获取,但这效率低下且不建议使用;请勿使用)。
本地传输(即 git:// 地址)不进行身份验证,在不安全的网络上应谨慎使用。
以下是上述几个传输协议的格式:
-
ssh://[<user>@]<host>[:<port>]/<path-to-git-repo> -
git://<主机地址>[:<端口>]/<Git 仓库路径>
-
http[s]://<主机地址>[:<端口>]/<Git 仓库路径>
-
ftp[s]://<主机地址>[:<端口>]/<Git 仓库路径>
ssh 协议也可以使用类似 scp 的语法:
-
[<用户名>@]<主机地址>:/<Git 仓库路径>
仅当第一个冒号之前没有斜杠时才能识别此语法。这有助于区分包含冒号的本地路径。例如,可以将本地路径 foo:bar 指定为绝对路径,或者将 ./foo:bar 指定为绝对路径,以避免被误识别为 ssh url。
ssh 和 git 协议还支持 ~<用户名> 扩展:
-
ssh://[<user>@]<host>[:<port>]/~<user>/<path-to-git-repo> -
git://<主机地址>[:<端口>]/~<用户名>/<Git 仓库路径>
-
[<用户名>@]<主机地址>:~<用户名>/<Git 仓库路径>
对于本地仓库(Git 本身也支持),可以使用以下语法:
-
/path/to/repo.git/ -
file:///path/to/repo.git/
这两种语法几乎是等效的,除了在克隆时,前者隐含使用了 --local 选项。有关详细信息,请参阅 git-clone[1]。
git clone、git fetch 和 git 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]、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 pull 和 git 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 中的分支可以选择关联一个上游远程分支。对于远程操作,Git 默认会使用该上游分支,例如:
-
它是无参数执行
gitpull或gitfetch时的默认目标。 -
除少数例外情况外,它也是无参数执行
gitpush时的默认目标。例如,你可以使用branch.<name>.pushRemote选项,将代码推送到与拉取时不同的远程;并且在默认的push.default=simple模式下,你所配置的上游分支必须与当前分支同名。 -
包括
gitcheckout和gitstatus在内的各种命令都会告诉你:自从当前分支从上游分出以来,当前分支和上游分支各新增了多少个提交。例如会显示“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配置项,那么第一次推送某个分支时,gitpush会自动设置其上游。 -
使用
gitcheckout<branch> 检出远程跟踪分支时,会自动创建同名本地分支,并将该远程分支设置为其上游。
|
Note
|
上游分支有时也被称为 “tracking information”(跟踪信息),例如“set the branch’s tracking information”。 |
合并战略
合并机制( git merge 和 git pull 命令)允许用 -s 选项来选择后端’合并策略'。 一些策略也可以采取自己的选项,可以通过给 git merge 和/或 git pull 的 -X<选项> 参数来传递。
-
ort -
这是拉取或合并一个分支时的默认合并策略。 这个策略只能使用三方合并算法解决两个头。 当有一个以上的共同祖先可用于三方合并时,它会创建一个共同祖先的合并树,并将其作为三方合并的参考树。 据报道,通过对Linux 2.6内核开发历史中的实际合并提交的测试,这导致了较少的合并冲突,而不会引起错误的合并。 此外,这个策略可以检测并处理涉及重命名的合并。 它并不使用检测到的副本。 这个算法的名字是一个缩写("Ostensibly Recursive’s Twin"),来自于它是作为以前的默认算法`recursive`的替代而编写的。
当路径是一个子模块时,如果合并一侧使用的子模块提交是另一侧使用的子模块提交的后代,Git 会尝试快进到该后代。否则,Git 会将该情况视为冲突;若存在,会建议一个同时为冲突双方提交后代的子模块提交作为解决方案。
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> 的同义词。 -
no-renames -
关闭重名检测。这覆盖了
merge.renames的配置变量。 参见git-diff[1]--no-renames。 -
histogram -
废弃的,
diff-algorithm=patience的同义词。 -
patience -
废弃的,
diff-algorithm=patience的同义词。 - diff-algorithm=[histogram|minimal|myers|patience]
-
在合并时使用不同的差异算法,这可以帮助避免由于不重要的匹配行(比如不同函数的大括号)而发生的错误合并。 参见git-diff[1]
--diff-algorithm。 注意,ort特定diff-algorithm=histogram,而`recursive`默认为`diff.algorithm`配置设置。 - subtree[=<路径>]
-
这个选项是 子树 策略的更高级形式,该策略对两棵树在合并时必须如何移位以相互匹配进行猜测。 相反,指定的路径是前缀(或从开始剥离),以使两棵树的形状相匹配。
-
-
recursive -
它现在是
ort的同义词。它在 v2.49.0 之前是一个替代实现,但从 v2.50.0 起被重定向为表示ort。此前的 recursive 策略曾在 Git v0.99.9k 至 v2.33.0 期间作为合并两个 head 的默认策略。 -
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/<远程名> 中的引用规范。 在这种情况下,以下规则适用:
-
如果当前分支 <分支名> 的 branch.< 分支名 >.merge 配置存在,这就是被合并的远程站点的分支名称。
-
如果引用规范是全局的, 则不合并任何信息。
-
否则将合并第一个引用规范的远程分支。
实例
-
更新你所克隆的仓库的远程跟踪分支,然后将其中一个分支合并到你当前的分支:
$ 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 来恢复。
安全
获取和推送协议并不是为了防止一方从另一个仓库窃取不打算共享的数据。如果你有需要保护的私人数据不被恶意的同行窃取,你最好的选择是把它存储在另一个资源库中。这同时适用于客户端和服务器。特别是,服务器上的命名空间对于读取访问控制是无效的;你应该只将命名空间的读取访问权授予那些你信任的可以读取整个仓库的客户。
已知的攻击媒介如下:
-
受害者发送 "have" 行,宣传它所拥有的对象的 ID,这些对象并没有明确地打算被共享,但如果对等体也有这些对象,就可以用来优化传输。攻击者选择了一个对象 ID X 来窃取,并向 X 发送了一个引用,但不需要发送 X 的内容,因为受害者已经拥有它。现在,受害者认为攻击者拥有 X,它稍后将 X 的内容发回给攻击者。(这种攻击对于客户端来说在服务器上执行是最直接的,通过在客户端可以访问的命名空间中创建一个 X 的引用,然后获取它。服务器最可能在客户端执行的方式是将 X "合并" 到一个公共分支,并希望用户在这个分支上做额外的工作,然后在没有注意到合并的情况下将其推回给服务器。)
-
和 #1 一样,攻击者选择了一个对象 ID X 来偷窃。受害者发送了一个攻击者已经拥有的对象 Y,攻击者谎称拥有 X 而没有 Y,因此受害者发送 Y 作为对 X 的d elta,delta 向攻击者显示了 X 中与 Y 相似的区域。
漏洞
使用 --recurse-submodules 现在只能获取已经检出的子模块的新提交。例如,当上游在刚刚获取的超级项目的提交中添加了一个新的子模块时,子模块本身不能被获取,这使得以后不需要再次获取就能检出该子模块。这个问题有望在未来的 Git 版本中被修复。
GIT
属于 git[1] 文档