Git
简体中文 ▾ Topics ▾ Latest version ▾ git-push last updated in 2.45.0

名称

git-push - 与相关对象一起更新远程分支引用

概述

git push [--all | --branches | --mirror | --tags] [--follow-tags] [--atomic] [-n | --dry-run] [--receive-pack=<git-receive-pack>]
	   [--repo=<仓库>] [-f | --force] [-d | --delete] [--prune] [-q | --quiet] [-v | --verbose]
	   [-u | --set-upstream] [-o <字符串> | --push-option=<字符串>]
	   [--[no-]signed|--signed=(true|false|if-asked)]
	   [--force-with-lease[=<引用名>[:<expect>]] [--force-if-includes]]
	   [--no-verify] [<仓库> [<引用规范>…​]]

描述

使用本地引用更新远程仓库引用,同时发送完成给定引用的必要对象。

通过设置 “钩子”,你可以在每次推送到一个仓库时,让它发生有趣的事情。 见 git-receive-pack[1] 的文档。

当命令行没有用 <仓库> 参数指定推送位置时,会参考当前分支的 branch.*.remote 配置来决定推送位置。 如果配置丢失,则默认为 "origin"。

当命令行没有用 <引用规范>... 参数或 --all--mirror--tags 选项指定推送内容时,命令通过查阅 remote.*.push 配置找到默认的 < 引用规范 >,如果没有找到,则以 push.default 配置决定推送内容(关于 push.default 的含义,见 git-config[1] )。

当命令行和配置都没有指定推送的内容时,将使用默认行为,这与 push.defaultsimple 值相对应:当前分支被推送到相应的上游分支,但作为一项安全措施,如果上游分支的名称与本地分支不一致,推送将被中止。

选项

<仓库>

作为推送操作的目的地的 “远程” 仓库。 这个参数可以是一个网址(见下面 GIT 地址 一节),也可以是一个远程库的名称(见下面 远程仓库 一节)。

<引用规范>…​

指定用什么源对象来更新哪个目标参考文献。 <引用规范> 参数的格式是一个可选的加号 +,后面是源对象 <src>,后面是冒号 :,后面是目标引用 <dst>。

<src> 通常是你想推送的分支的名字,但它可以是任何任意的“SHA-1 表达式”,比如 master~4HEAD(见 gitrevisions[7])。

<dst> 远程仓库的哪个引用被这个推送更新。这里不能使用任意的表达式,必须命名一个实际的引用。 如果 git push [< 仓库 >] 没有任何 < 引用规范 > 参数被设置用 remote.< 仓库 >.push 配置变量更新目的地 <src> 的某个引用,则`:<dst>` 部分可以省略 —— 这样的推送将更新 <src> 通常更新的引用,命令行上没有任何 < 引用规范 >。 否则,缺少 :<dst> 意味着更新与 <src> 相同的引用。

如果 <dst> 不是以 refs/ 开头(例如 refs/heads/master),我们将根据被推送的 <src> 的类型和 <dst> 是否含糊不清,尝试推断它在目的地 < 仓库 > 的 refs/* 中的位置。

  • 如果 <dst> 明确地指向 < 仓库 > 远程的一个引用,那么就推送到该引用。

  • 如果 <src> 解析为以 refs/heads/ 或 refs/tags/ 开头的引用,则将其前置到 <dst>。

  • 其他含糊的解决方案可能会在未来加入,但现在我们所尝试的任何其他情况都会出错,并根据`advice.pushUnqualifiedRefname`配置(见git-config[1])建议你可能想推送到哪个类型的引用中。

由 <src> 引用的对象被用来更新远程端的 <dst> 引用。这是否被允许取决于 <dst> 引用在`refs/*`中的位置,下面将详细描述,在这些章节中,“更新”意味着除了删除之外的任何修改,正如在接下来的几节中所指出的,这将被不同地对待。

refs/heads/* 命名空间只接受提交对象,只有在可以快进的情况下才接受更新。

refs/tags/* 命名空间将接受任何种类的对象(因为提交、树和二进制对象都可以被标记),对它们的任何更新都将被拒绝。

可以将任何类型的对象推送到 refs/{tags,heads}/* 之外的任何命名空间。在标签和提交的情况下,这些将被视为 refs/heads/* 内的提交,以决定是否允许更新。

也就是说,允许在 refs/{tags,heads}/* 之外进行快进提交和标签,即使被快进的不是一个提交,而是一个标签对象,它恰好指向一个新的提交,而这个提交是它所替代的最后一个标签(或提交)的快进。用一个完全不同的标签替换一个标签也是允许的,如果它指向同一个提交,以及推送一个剥离的标签,即推送现有标签对象所指向的提交,或现有提交所指向的新标签对象。

refs/{tags,heads}/* 之外的树和二进制对象的处理方式与在 refs/tags/* 之内的相同,它们的任何更新都会被拒绝。

上面描述的所有关于不允许更新的规则都可以通过在引用规范前面添加一个可选 + 来覆盖(或者使用 --force 命令行选项)。唯一的例外是,无论如何强制都不会使 refs/heads/* 命名空间接受一个非提交对象。钩子和配置也可以覆盖或修改这些规则,例如见 git-config[1] 中的 receive.denyNonFastForwardsgithooks[5] 中的 pre-receiveupdate

推送一个空的 <src> 允许你从远程版本库中删除 <dst> 的引用。除非配置或钩子禁止,否则在引用规范中没有前面的 + (或 --force) ,删除总是被接受的。参见 git-config[1] 中的 receive.denyDeletes 以及 githooks[5] 中的 pre-receiveupdate

特殊的引用规范 :(或`+:`以允许非快进式更新)指示 Git 推送“匹配”的分支:对于每一个存在于本地的分支,如果远程仓库已经有一个同名的分支存在,则远程仓库会被更新。

tag <tag>refs/tags/<tag>:refs/tags/<tag> 意思相同。

--all
--branches

推送所有分支(即`refs/heads/`下的引用);不能与其他 < 引用规范 > 一起使用。

--prune

删除没有本地对应分支的远程分支。例如,如果本地的同名分支不存在了,那么远程分支 tmp 将被删除。这也是对引用规范的尊重,例如,git push --prune remote refs/heads/*:refs/tmp/* 将确保如果 refs/heads/foo 不存在,那么远程的 refs/tmp/foo 将被删除。

--mirror

而不是命名每一个要推送的引用,指定`refs/(包括但不限于`refs/heads/refs/remotes/`和`refs/tags/)下的所有引用都被镜像到远程仓库。 新创建的本地引用将被推送到远程端,本地更新的引用将被强制更新到远程端,而删除的引用将从远程仓库删除。 如果配置选项 `remote.<remote>.mirror`被设置,这就是默认的。

-n
--dry-run

做除了实际发送更新外的所有事。

--porcelain

生成机器可读的输出。 每个引用的输出状态行将以制表符分隔,并发送至标准输出而不是标准报错。 将给出引用的完整符号名称。

-d
--delete

所有列出的引用都从远程仓库中删除。这与在所有引用前加冒号的做法相同。

--tags

除了命令行上明确列出的引用规范之外,refs/tags 下的所有引用都被推送。

--follow-tags

推送所有在没有这个选项的情况下会被推送的引用,同时也推送 refs/tags 中的注释标签,这些标签在远程中缺失,但却指向被推送的引用中可以到达的提交号。 这也可以用配置变量 push.followTags 来指定。 更多信息,见 git-config[1] 中的 push.followTags

--[no-]signed
--signed=(true|false|if-asked)

对推送请求进行 GPG 签名,以更新接收方的引用,使其能够被钩子检查和/或被记录下来。 如果指定 false--no-signed,将不尝试签名。 如果指定 true--signed,且服务器不支持签名推送,推送将失败。 如果设置为 if-asked,仅当服务器支持签名推送时才签名。 如果实际调用 gpg --sign 失败,推送也将失败。 关于接收端的细节,见 git-receive-pack[1]

--[no-]atomic

如果有的话,在远程仓库使用一个原子事务。 要么所有的引用都被更新,要么出错时,没有引用被更新。 如果服务器不支持原子推送,推送将会失败。

-o <选项>
--push-option=<选项>

将给定的字符串传输给服务器,服务器将它们传递给 pre-receive 以及 post-receive 钩子。给定的字符串不能包含 NUL 或 LF 字符。 当给出多个 --push-option=< 选项 > 时,它们将按照命令行中列出的顺序全部发送给对方。 当命令行中没有给出 --push-option=< 选项 > 时,将使用配置变量`push.pushOption` 的值来代替。

--receive-pack=<git-receive-pack>
--exec=<git-receive-pack>

到远端的 git-receive-pack 程序的路径。 当通过 ssh 推送到远程版本库,而你没有在默认的 $PATH 目录下的程序时,有时会很有用。

--[no-]force-with-lease
--force-with-lease=<引用名>
--force-with-lease=< 引用名 >:< 期望>

通常,"git push" 会拒绝更新一个不是用来覆盖它的本地引用的远程父引用。

如果远程引用的当前值是预期值,该选项会覆盖这一限制。否则,"git push" 会失败。

想象一下,你必须对你已经发表的内容进行重新定位。 你必须绕过“必须快速合并”的规则,以便用重写的历史替换你最初发布的历史。 如果在你重新发布的时候,有其他人在你原来的历史之上构建,那么远程分支的顶端可能会随着他们的提交而前进,而盲目地用 --force 推送会丢失他们的改动。

这个选项允许你说,你希望你更新的历史是你重新建立的,并希望取代它。如果远程引用仍然指向你指定的提交,你就可以确定没有其他人对该引用做了什么。这就像在没有明确锁定的情况下对引用进行“租赁”,只有在 “租赁”仍然有效的情况下才会更新远程引用。

--force-with-lease,不指定细节,将保护所有将被更新的远程引用,要求它们的当前值与我们为它们准备的远程跟踪分支相同。

--force-with-lease=< 引用名 >,没有指定预期值,将保护命名的引用(单独),如果它要被更新,要求其当前值与我们对它的远程跟踪分支相同。

--force-with-lease=< 引用名 >:< 期望 >`将保护指定的引用(单独),如果它要被更新,要求它的当前值与指定的值< 期望 >相同(允许与我们对引用名的远程跟踪分支不同,或者在使用这种形式时,我们甚至不需要有这样一个远程跟踪分支)。 如果< 期望 >`是空字符串,那么命名的引用必须不存在。

请注意,除了`--force-with-lease=< 引用名 >:< 期望 >`以外的所有形式都是明确指定引用的预期当前值,这些形式仍然是试验性的,它们的语义可能会随着我们对这个功能的经验积累而改变。

"--no-force-with-lease " 将取消之前在命令行上所有的 --force-with-lease。

关于安全性的一般说明:在没有预期值的情况下提供这个选项,即 --force-with-lease 或`--force-with-lease=< 引用名 >,会与任何在后台隐式运行 `git fetch 的远端推送的进程产生非常不好的互动,例如仓库中 cronjob 的 git fetch origin

--force 相比,它提供的保护是确保你的工作不基于后续的变化,但如果有后台进程在后台更新引用,这一点就很容易被破坏。除了远程跟踪信息外,我们没有任何你期望看到并愿意去破解可以作为启发式引用的东西。

如果你的编辑器或其他系统在后台为你运行`git fetch`,减轻这种情况的方法是简单地设置另一个远程:

git remote add origin-push $(git config remote.origin.url)
git fetch origin-push

现在,当后台进程运行 git fetch origin 时,`origin-push`上的引用将不会被更新,因此,像这样的命令:

git push --force-with-lease origin-push

除非你手动运行 git fetch origin-push,否则会失败。当然,这种方法完全可以被运行 git fetch --all 的东西打败,在这种情况下,你需要禁用它或者做一些更繁琐的事情,比如:

git fetch              # 从远程仓库更新 'master' 分支
git tag base master    # 标记基点
git rebase -i master   # 重写某些提交
git push --force-with-lease=master:base master:master

也就是说,为你已经看到并愿意覆盖的上游仓库创建一个`base` 标签,然后重写历史,最后如果远程版本仍然在 base,则强制推送修改到`master`,不管你本地的 remotes/origin/master 在后台更新了什么。

另外,在“推送”时将 --force-if-includes 作为辅助选项与 --force-with-lease[=< 引用名 >] 一起指定(即不说远程的引用必须指向什么确切的提交,或远程的哪些引用被保护),将验证远程跟踪引用的更新是否在允许强制更新之前被整合在本地。

-f
--force

通常情况下,命令会拒绝更新一个不属于用来覆盖它的本地引用祖先的远程引用。 另外,当使用 --force-with-lease 选项时,命令会拒绝更新一个当前值与预期不符的远程引用。

这个标志禁用了这些检查,并可能导致远程版本库丢失提交,使用时要小心。

注意,--force 适用于所有被推送的引用,因此在 push.default 设置为 matching 的情况下使用它,或者在 remote.*.push 配置了多个推送目的地的情况下,可能会覆盖当前分支以外的引用(包括严格落后于其远程对应的本地引用)。 要强制推送到一个分支,请在推送的引用规范前面使用 +(例如 git push origin +master,强制推送到 master 分支)。详情见上面的 < 引用规范 >... 部分。

--[no-]force-if-includes

只有远程跟踪的引用顶端被整合到本地才强制更新。

这个选项启用了一个检查,以验证远程跟踪引用的顶端是否可以从本地分支的“引用日志”条目中到达,以便进行重写。该检查确保来自远程的任何更新都已纳入本地,如果不是这样,则拒绝强制更新。

如果该选项没有指定 --force-with-lease,或者与 `--force-with-lease=< 引用名 >:< 期望 >`一起指定,则是“无选项”的。

指定 --no-force-if-includes 就可以禁止这种行为。

--repo=<仓库>

这个选项等同于 < 仓库 > 参数。如果两者都被指定,则以命令行参数为优先。

-u
--set-upstream

对于每一个已经更新或成功推送的分支,添加上游(跟踪)引用,由无参数的 git-pull[1] 和其他命令使用。更多信息,见 git-config[1] 中的 branch.< 分支名 >.merge

--[no-]thin

这些选项被传递给 git-send-pack[1]。当发送方和接收方有许多共同的对象时,稀松传输会大大减少发送的数据量。默认是 --thin

-q
--quiet

抑制所有的输出,包括更新的引用的列表,除非发生错误。进度不会报告给标准错误流。

-v
--verbose

详细运行。

--progress

当标准错误流连接到终端时,除非指定了 -q,否则默认情况下会在标准错误流上报告进展状态。即使标准错误流没有指向终端,这个标志也会强制显示进度状态。

--no-recurse-submodules
--recurse-submodules=check|on-demand|only|no

可以用来确保要推送的修订版所使用的所有子模块提交都在远程跟踪分支上可用。 如果使用 check,Git 将验证所有在要推送的修订版中发生变化的子模块提交是否在该子模块的至少一个远程上可用。如果缺少任何提交,推送将被中止并以非零状态退出。如果使用 on-demand,所有在要推送的修订版中发生变化的子模块都会被推送。如果 on-demand 不能推送所有必要的修订版,它也将被中止并以非零状态退出。如果使用 only,所有的子模块将被推送,父级项目则不被推送。当不需要子模块递归时,一个 "no" 的值或使用 --no-recurse-submodules 可以用来覆盖 push.recurseSubmodules 配置变量。

当使用 "on-demand" 或 "only" 时,如果一个子模块有 "push.recurseSubmodules={on-demand,only}" 或 "submodule.recurse"配置,将发生进一步递归。在这种情况下,"only" 被视为 "on-demand"。

--[no-]verify

切换 pre-push 钩子(见 githooks[5])。 默认是 --verify,给钩子一个机会来阻止推送。 如果使用 --no-verify,钩子会被完全绕过。

-4
--ipv4

仅使用 IPv4 地址,忽略 IPv6 地址。

-6
--ipv6

仅使用 IPv6 地址,忽略 IPv4 地址。

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]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 push" 的输出取决于所使用的传输方式;本节将介绍通过 Git 协议(本地或通过 ssh)推送时的输出。

推送的状态以表格的形式输出,每一行代表一个引用的状态。每一行的形式是:

 <标志> <概述> <起始> -> <结束> (<原因>)

如果使用了 --porcelain ,那么输出的每一行都是这样的:

 <标志> \t <起始>:<结束> \t <概述> (<原因>)

只有在使用 --porcelain 或 --verbose 选项时,才会显示最新引用的状态。

标志

表示引用状态的单个字符:

(空格)

表示推送成功的快速合并;

+

表示一个成功的强制更新;

-

表示一个成功删除的引用;

*

表示成功推送的引用;

!

表示一个被拒绝或推送失败的引用;并且

=

表示一个最新的、不需要推送的引用。

概述

对于一个成功获取的引用,摘要以适合作为 git log 参数的形式显示该引用的新旧值(在大多数情况下是 <旧>..<新>,对于强制非快速合并是 <旧>...<新>)。

对于失败的更新,会给出更多的细节:

已拒绝

Git 根本没有尝试发送引用,典型的原因是它不是快速合并并且你没有强制更新。

远程拒绝

远程仓库拒绝更新。 通常是由远程仓库的钩子引起的,或者是因为远程仓库有以下安全选项:receive.denyCurrentBranch(用于推送到已检出的分支),receive.denyNonFastForwards(用于强制非快进更新),receive.denyDeletes 或者 receive.denyDeleteCurrent。 见 git-config[1]

远程故障

远程端没有报告引用的成功更新,可能是因为远程端的临时错误,网络连接中断,或其他瞬时错误。

起始

被推送的本地引用的名称,减去其 refs/< 类型 >/ 前缀。在删除的情况下,本地引用的名称被省略。

结束

被更新的本地引用的名称,去掉其 refs/< 类型 >/ 前缀。

原因

一个人类可读的解释。在成功推送引用的情况下,不需要解释。对于操作失败的引用,要描述失败的原因。

关于快速合并的说明

当一个更新将原来指向提交 A 的分支(或更普遍的,一个引用)改为指向另一个提交 B 时,当且仅当 B 是 A 的后代时,它被称为快速合并。

在从 A 到 B 的快速合并中,原始提交 A 所建立的提交集是新提交 B 所建立的提交集的一个子集。 因此,它不会丢失任何历史。

相反,非快速合并更新会丢失历史。 例如,假设你和别人从同一个提交 X 开始,你建立了一个通往提交 B 的历史,而另一个人建立了一个通往提交 A 的历史。 这段历史看起来像这样:

      B
     /
 ---X---A

进一步假设对方已经将 A 导致的修改推送回原仓库,你们俩从原仓库中获得原始提交 X。

另一个人所做的推送,将原来指向提交 X 的分支更新为指向提交 A 的分支。

但如果你试图推送,你会试图用提交 B 来更新分支(现在指向 A)。这不是快速合并。 如果你这样做了,提交 A 引入的修改就会丢失,因为大家现在都会在 B 的基础上开始构建。

该命令默认不允许非快速合并的更新,以防止这种历史的损失。

如果你不想丢失你的工作(从 X 到 B 的历史)或对方的工作(从 X 到 A 的历史),你需要先从仓库中获取历史,创建一个包含双方修改的历史,并将结果推送回去。

您可以执行 "git pull",解决潜在的冲突,然后将结果 "git push"。 一个 "git pull "会在提交 A 和 B 之间创建一个合并提交 C。

      B---C
     /   /
 ---X---A

用所产生的合并提交更新 A,将快速合并,你的推送将被接受。

另外,你也可以用 "git pull --rebase" 将 X 和 B 之间的改动重新归档到 A 之上,然后将结果推送回来。 重置将创建一个新的提交 D,将 X 和 B 之间的修改建立在 A 的基础上。

      B   D
     /   /
 ---X---A

同样的,用这个提交更新 A 会快速合并,你的推送会被接受。

还有一种常见的情况是,当你试图推送时,可能会遇到非快速合并拒绝,即使你推送到一个没有人推送的版本库中也有可能。在你自己推送了提交 A(在本节的第一幅图中),用 "git commit --amend" 替换后产生了提交 B,你试图推送它,因为忘记了你已经推送了 A。在这种情况下,只有当您确定在此期间没有人取走您先前的提交 A(并在其基础上开始构建),您才能运行 "git push --force" 来覆盖它。换句话说,"git push --force" 是一种保留给你确实想失去历史的情况的方法。

实例

git push

像`git push < 远端 >那样工作,其中 < 远端 > 是当前分支的远程仓库(或者`origin,如果没有为当前分支配置远程仓库)。

git push origin

不需要额外配置,如果它与当前分支同名,并且错误输出而不推送其他分支,则将其推送到配置过的上游仓库(branch.<分支名>.merge 配置变量)。

当没有给出< 引用规范 >时,该命令的默认行为可以通过设置远程仓库的 push 选项或 `push.default`配置变量来配置。

例如,要默认只将当前分支推送到 origin,使用 git config remote.origin.push HEAD。 任何有效的< 引用规范 >(比如下面例子中的那些)都可以被配置为 git push origin 的默认值。

git push origin :

将 “匹配” 的分支推送到 origin。关于 “匹配” 分支的描述,请参见上面 选项 部分的 [引用规范]

git push origin master

在源仓库中找到一个与 master 相匹配的引用(最可能的是找到 refs/heads/master),并在 origin 仓库中用它更新相同的引用(例如`refs/heads/master`)。 如果 master 不存在,它将被创建。

git push origin HEAD

一个方便的方法是将当前分支推送到远程的相同名称。

git push mothership master:satellite/master dev:satellite/dev

使用与 "master" 相匹配的源引用(例如,refs/heads/master)来更新 mothership 仓库中与 satellite/master 相匹配的引用(很可能是 refs/remotes/satellite/master);对 dev 和 `satellite/dev`做同样的操作。

关于匹配语义的讨论,请参见上面描述 <引用规范>... 的部分。

这是为了模拟在`母舰` 上运行的 git fetch ,使用 git push 以相反的方向运行,以便整合 卫星 上完成的工作,当你只能以一种方式进行连接时(即卫星可以ssh到母舰,但母舰不能启动与卫星的连接,因为后者在防火墙后面或不运行 sshd),这往往是必要的。

卫星 机器上运行这个 git push 后,你将 ssh 进入 母舰 并在那里运行 git merge ,以完成对 母舰 上运行的 git pull 的模拟,以拉取 卫星 上的修改。

git push origin HEAD:master

推送当前分支到远程引用匹配 masterorigin 仓库中。这种形式可以方便地推送当前分支,而不必考虑其本地名称。

git push origin master:refs/heads/experimental

通过复制当前的 master 分支,在 origin 仓库创建 experimental 分支。 只有在本地名称和远程名称不同的情况下,在远程仓库中创建新的分支或标签时才需要这个表单;否则,参考名称本身就可以了。

git push origin :experimental

origin 仓库(例如`refs/heads/experimental`)中找到一个与 experimental 相匹配的引用,并将其删除。

git push origin +dev:master

用开发分支更新仓库的主分支,允许非快速合并更新。 *这可能会使未引用的提交在源码库中悬空。*考虑以下情况,即不可能进行快速合并:

	    o---o---o---A---B  origin/master
		     \
		      X---Y---Z  dev

上面的命令将 origin 仓库更改为

		      A---B  (unnamed branch)
		     /
	    o---o---o---X---Y---Z  master

提交 A 和 B 将不再属于具有符号名称的分支,因此将不可访问。因此,这些提交将被原始存储库上的“ gitgc”命令删除。

安全

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

已知的攻击媒介如下:

  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 相似的区域。

配置

Warning

Missing zh_HANS-CN/includes/cmd-config-section-all.txt

See original version for this content.

Warning

Missing zh_HANS-CN/config/push.txt

See original version for this content.

GIT

属于 git[1] 文档

scroll-to-top