设置和配置
获取和创建项目
基本快照
分支与合并
共享和更新项目
检查和比较
打补丁
调试
电子邮件
外部系统
服务器管理
指南
管理
底层命令
- 2.48.1 → 2.50.1 无更改
-
2.48.0
2025-01-10
- 2.45.1 → 2.47.3 无更改
-
2.45.0
2024-04-29
- 2.44.1 → 2.44.4 无更改
-
2.44.0
2024-02-23
- 2.43.1 → 2.43.7 无更改
-
2.43.0
2023-11-20
- 2.42.2 → 2.42.4 无更改
-
2.42.1
2023-11-02
-
2.42.0
2023-08-21
- 2.41.1 → 2.41.3 无更改
-
2.41.0
2023-06-01
- 2.40.1 → 2.40.4 无更改
-
2.40.0
2023-03-12
- 2.39.1 → 2.39.5 无变化
-
2.39.0
2022-12-12
- 2.38.1 → 2.38.5 无更改
-
2.38.0
2022-10-02
- 2.35.1 → 2.37.7 无更改
-
2.35.0
2022-01-24
- 2.33.1 → 2.34.8 无变化
-
2.33.0
2021-08-16
- 2.32.1 → 2.32.7 无变更
-
2.32.0
2021-06-06
- 2.30.1 → 2.31.8 无更改
-
2.30.0
2020-12-27
- 2.25.1 → 2.29.3 无更改
-
2.25.0
2020-01-13
- 2.23.1 → 2.24.4 无更改
-
2.23.0
2019-08-16
- 2.22.1 → 2.22.5 无更改
-
2.22.0
2019-06-07
- 2.21.1 → 2.21.4 无更改
-
2.21.0
2019-02-24
- 2.20.1 → 2.20.5 无更改
-
2.20.0
2018-12-09
- 2.18.1 → 2.19.6 无变更
-
2.18.0
2018-06-21
- 2.17.0 → 2.17.6 无更改
-
2.16.6
2019-12-06
-
2.15.4
2019-12-06
- 2.14.6 无更改
-
2.13.7
2018-05-22
-
2.12.5
2017-09-22
-
2.11.4
2017-09-22
-
2.10.5
2017-09-22
-
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 无更改
-
2.4.12
2017-05-05
-
2.3.10
2015-09-28
-
2.2.3
2015-09-04
- 2.1.4 无更改
-
2.0.5
2014-12-17
概要
git push [--all | --branches | --mirror | --tags] [--follow-tags] [--atomic] [-n | --dry-run] [--receive-pack=<git-receive-pack>] [--repo=<repository>] [-f | --force] [-d | --delete] [--prune] [-q | --quiet] [-v | --verbose] [-u | --set-upstream] [-o <string> | --push-option=<string>] [--[no-]signed|--signed=(true|false|if-asked)] [--force-with-lease[=<refname>[:<expect>]] [--force-if-includes]] [--no-verify] [<repository> [<refspec>…]]
描述
使用本地引用更新远程引用,同时发送完成给定引用所需的全部对象。
每次向仓库推送时,可以通过设置钩子使其发生有趣的事情。请参阅 git-receive-pack[1] 的文档。
当命令行未使用 <repository> 参数指定推送位置时,将查阅当前分支的 branch.*.remote 配置来确定推送位置。如果缺少该配置,则默认为 origin。
当命令行未使用 <refspec>... 参数或 --all、--mirror、--tags 选项指定推送内容时,该命令会通过查阅 remote.*.push 配置来查找默认的 <refspec>,如果未找到,则会遵循 push.default 配置来决定推送内容(有关 push.default 的含义,请参阅 git-config[1])。
当命令行和配置均未指定推送内容时,将使用默认行为,这对应于 push.default 的 simple 值:当前分支被推送到相应的上游分支,但作为一项安全措施,如果上游分支与本地分支名称不同,则推送会被中止。
选项
- <仓库>
-
作为推送操作目的地的“远程”仓库。此参数可以是 URL(参见下面的 GIT URL 部分)或远程名称(参见下面的 远程 部分)。
- <引用规范>…
-
指定用哪个源对象更新哪个目标引用。<引用规范> 参数的格式是可选的加号
+,后跟源对象 <src>,再跟冒号:,最后跟目标引用 <dst>。<src> 通常是您希望推送的分支名称,但它可以是任意“SHA-1 表达式”,例如
master~4或HEAD(参见 gitrevisions[7])。<dst> 指定了远程端哪个引用将通过此推送进行更新。此处不能使用任意表达式,必须指定实际的引用名称。如果
gitpush[<repository>] 在没有任何 <refspec> 参数的情况下,通过remote.<repository>.push配置变量设置为用 <src> 更新目标处的某个引用,则可以省略:<dst> 部分—这种推送会更新通常由 <src> 更新的引用,而无需在命令行上指定任何 <refspec>。否则,省略:<dst> 意味着更新与 <src> 相同的引用。如果 <dst> 没有以
refs/开头(例如refs/heads/master),我们将根据被推送的 <src> 类型以及 <dst> 是否模棱两可,尝试推断它在目标 <仓库> 的refs/*中的位置。-
如果 <dst> 明确地指向 <仓库> 远程上的一个引用,则推送到该引用。
-
如果 <src> 解析为以 refs/heads/ 或 refs/tags/ 开头的引用,则将其前置到 <dst>。
-
未来可能会增加其他歧义解析,但目前任何其他情况都会报错,指出我们尝试过什么,并根据
advice.pushUnqualifiedRefname配置(参见 git-config[1])建议您可能希望推送到哪个 refs/ 命名空间。
<src> 引用的对象用于更新远程端的 <dst> 引用。这是否允许取决于 <dst> 引用在
refs/*中的位置,具体描述如下,在这些部分中,“更新”意味着除删除之外的任何修改,删除将在接下来的几节中单独处理。refs/heads/*命名空间只接受提交对象,并且只有在可以快进的情况下才允许更新。refs/tags/*命名空间接受任何类型的对象(因为提交、树和 blob 都可以被标记),并且对它们的任何更新都将被拒绝。可以将任何类型的对象推送到
refs/{tags,heads}/*之外的任何命名空间。对于标签和提交,它们将被视为refs/heads/*内部的提交,以决定是否允许更新。即,允许对
refs/{tags,heads}/*之外的提交和标签进行快进,即使在快进的对象不是提交,而是一个标签对象,并且该标签对象恰好指向一个新提交,而这个新提交是其替换的最后一个标签(或提交)的快进时,也允许这样做。用一个完全不同的标签替换现有标签也允许,如果它指向相同的提交,以及推送剥离标签,即推送现有标签对象指向的提交,或一个现有提交指向的新标签对象。refs/{tags,heads}/*之外的树和 blob 对象将被视为与在refs/tags/*内部一样对待,对它们的任何更新都将被拒绝。上述所有关于不允许更新的规则都可以通过在引用规范前添加可选的
+号(或使用--force命令行选项)来覆盖。唯一的例外是,无论如何强制,refs/heads/*命名空间都不会接受非提交对象。钩子和配置也可以覆盖或修改这些规则,例如参见 git-config[1] 中的receive.denyNonFastForwards以及 githooks[5] 中的pre-receive和update。推送空的 <src> 允许您从远程仓库中删除 <dst> 引用。除非被配置或钩子禁止,否则删除操作总是被接受的,即使引用规范中没有前导
+(或--force)。参见 git-config[1] 中的receive.denyDeletes以及 githooks[5] 中的pre-receive和update。特殊的引用规范
:(或+:以允许非快进更新)指示 Git 推送“匹配”分支:对于本地存在的每个分支,如果远程端已存在同名分支,则更新远程端的分支。tag<tag> 的含义与refs/tags/<tag>:refs/tags/<tag> 相同。 -
- --all
- --branches
-
推送所有分支(即
refs/heads/下的引用);不能与其他 <引用规范> 一起使用。 - --prune
-
删除没有本地对应分支的远程分支。例如,如果同名的本地分支不再存在,则远程分支
tmp将被删除。这也遵循引用规范,例如gitpush--pruneremoterefs/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=<option> 时,它们将按照命令行中列出的顺序全部发送到另一端。当命令行中未给出--push-option=<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=<refname>,不指定期望值时,将通过要求其当前值与其对应的远程跟踪分支值相同来保护指定的引用(单独),如果它将被更新。--force-with-lease=<refname>:<expect> 将保护指定的引用(单独),如果它将被更新,通过要求其当前值与指定值 <expect> 相同(该值可以与我们拥有的该引用名的远程跟踪分支不同,或者在使用此形式时我们甚至不必拥有这样的远程跟踪分支)。如果 <expect> 是空字符串,则指定的引用不得已存在。请注意,除明确指定引用期望当前值的
--force-with-lease=<refname>:<expect> 形式之外的所有形式仍处于实验阶段,并且随着我们对该功能的经验积累,它们的语义可能会发生变化。"--no-force-with-lease" 将取消命令行中所有先前的 --force-with-lease。
关于安全性的一般注意事项:在不指定期望值的情况下提供此选项,即使用
--force-with-lease或--force-with-lease=<refname>,与任何在后台隐式运行gitfetch到要推送的远程仓库的操作都会产生非常糟糕的交互,例如,在 cronjob 中对您的仓库运行gitfetchorigin。它比
--force提供的保护是确保您的工作所基于的后续更改不会被覆盖,但如果某些后台进程在后台更新引用,则这种保护很容易失效。除了远程跟踪信息,我们没有其他任何东西可以作为启发式地判断您预期已见过并愿意覆盖的引用。如果您的编辑器或某些其他系统在后台为您运行
gitfetch,则缓解此问题的一种方法是简单地设置另一个远程仓库git remote add origin-push $(git config remote.origin.url) git fetch origin-push
现在,当后台进程运行
gitfetchorigin时,origin-push上的引用将不会更新,因此像这样的命令git push --force-with-lease origin-push
将失败,除非您手动运行
gitfetchorigin-push。当然,如果运行gitfetch--all,此方法将完全失效,在这种情况下,您需要禁用它或执行更繁琐的操作,例如git fetch # update 'master' from remote git tag base master # mark our base point git rebase -i master # rewrite some commits git push --force-with-lease=master:base master:master
即,为您已见过并愿意覆盖的上游代码版本创建
base标签,然后重写历史,最后在远程版本仍处于base时强制推送更改到master,无论您的本地remotes/origin/master在后台更新到了什么。或者,在“推送”时将
--force-if-includes作为辅助选项与--force-with-lease[=<refname>](即,不说明远程端引用必须指向哪个确切提交,或远程端哪些引用受到保护)一起指定,将验证远程跟踪引用(可能已在后台隐式更新)的更新是否已在本地集成,然后才允许强制更新。 - -f
- --force
-
通常,该命令会拒绝更新不是用于覆盖它的本地引用的祖先的远程引用。此外,当使用
--force-with-lease选项时,如果远程引用的当前值与期望值不匹配,则该命令会拒绝更新该远程引用。此标志禁用这些检查,并可能导致远程仓库丢失提交;请谨慎使用。
请注意,
--force适用于所有被推送的引用,因此,将其与设置为matching的push.default或配置了多个推送目标(通过remote.*.push)一起使用时,可能会覆盖当前分支以外的引用(包括严格落后于其远程对应项的本地引用)。要强制推送到单个分支,请在推送的引用规范前使用+(例如gitpushorigin+master以强制推送到master分支)。有关详细信息,请参见上面的 <refspec>... 部分。 - --[no-]force-if-includes
-
仅当远程跟踪引用的尖端已在本地集成时才强制更新。
此选项启用一个检查,验证远程跟踪引用的尖端是否可从用于重写的本地分支的“reflog”条目之一到达。该检查通过在未合并远程更新时拒绝强制更新,确保任何来自远程的更新已在本地合并。
如果传递该选项而未指定
--force-with-lease,或与--force-with-lease=<refname>:<expect> 一起指定,则它是一个“无操作”(no-op)。指定
--no-force-if-includes将禁用此行为。 - --repo=<仓库>
-
此选项等同于 <仓库> 参数。如果两者都指定,则命令行参数优先。
- -u
- --set-upstream
-
对于每个已是最新或已成功推送的分支,添加上游(跟踪)引用,该引用被无参数的 git-pull[1] 和其他命令使用。有关详细信息,请参见 git-config[1] 中的
branch.<name>.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*,则将推送要推送的修订版中更改的所有子模块。如果按需推送未能推送所有必要的修订版,它也将中止并以非零状态退出。如果使用 *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 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 clone、git fetch 和 git pull,但不是 git push,也会接受合适的捆绑文件。参见 git-bundle[1]。
当 Git 不知道如何处理某个传输协议时,它会尝试使用 remote-<transport> 远程助手(如果存在)。要明确请求远程助手,可以使用以下语法
-
<传输方式>
::<地址>
其中 <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>。推送到远程会影响所有已定义的推送 URL,如果没有定义推送 URL,则影响所有已定义的 URL。但是,如果定义了多个 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 push”的输出取决于所使用的传输方法;本节描述通过 Git 协议(本地或通过 ssh)推送时的输出。
推送状态以表格形式输出,每行代表单个引用的状态。每行的形式如下
<flag> <summary> <from> -> <to> (<reason>)
如果使用 --porcelain,则输出的每行形式如下
<flag> \t <from>:<to> \t <summary> (<reason>)
仅在使用 --porcelain 或 --verbose 选项时显示最新引用的状态。
- 标志
-
一个字符指示引用的状态
- 摘要
-
对于成功推送的引用,摘要显示引用的旧值和新值,其格式适用于作为
gitlog的参数(在大多数情况下是 <old>..<new>,对于强制非快进更新则是 <old>...<new>)。对于失败的更新,将给出更多详情
- 被拒绝
-
Git 根本没有尝试发送该引用,通常是因为它不是快进,并且您没有强制更新。
- 远程拒绝
-
远程端拒绝了更新。通常是由于远程端的钩子,或者因为远程仓库启用了以下安全选项之一:
receive.denyCurrentBranch(用于推送到已检出分支)、receive.denyNonFastForwards(用于强制非快进更新)、receive.denyDeletes或receive.denyDeleteCurrent。参见 git-config[1]。 - 远程失败
-
远程端未报告引用的成功更新,可能是由于远程端的临时错误、网络连接中断或其他临时错误。
- 源
-
被推送的本地引用名称,不包括其
refs/<type>/前缀。在删除的情况下,省略本地引用名称。 - 目标
-
被更新的远程引用名称,不包括其
refs/<type>/前缀。 - 原因
-
人类可读的解释。对于成功推送的引用,无需解释。对于失败的引用,将描述失败原因。
关于快进的说明
当一次更新将一个分支(或更普遍地,一个引用)从指向提交 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”是一种仅用于您确实打算丢失历史记录的情况的方法。
示例
gitpush-
工作方式类似于
gitpush<远程仓库>,其中 <远程仓库> 是当前分支的远程仓库(如果当前分支未配置远程仓库,则为origin)。 gitpushorigin-
如果没有额外的配置,如果当前分支的名称与配置的上游分支(
branch.<name>.merge配置变量)相同,则将当前分支推送到配置的上游分支,否则会报错而不进行推送。当未给定 <引用规范> 时,此命令的默认行为可以通过设置远程的
push选项或push.default配置变量来配置。例如,要将仅推送当前分支到
origin设置为默认行为,请使用gitconfigremote.origin.pushHEAD。任何有效的 <引用规范>(如下例所示)都可以配置为gitpushorigin的默认值。 gitpushorigin:-
推送“匹配”分支到
origin。有关“匹配”分支的描述,请参见上面 选项 部分中的 <引用规范>。 gitpushoriginmaster-
在源仓库中找到与
master匹配的引用(很可能找到refs/heads/master),并用它来更新origin仓库中的相同引用(例如refs/heads/master)。如果master在远程不存在,则会创建它。 gitpushoriginHEAD-
将当前分支推送到远程同名分支的便捷方式。
gitpushmothershipmaster:satellite/masterdev:satellite/dev-
使用与
master匹配的源引用(例如refs/heads/master)来更新mothership仓库中与satellite/master匹配的引用(最可能是refs/remotes/satellite/master);对dev和satellite/dev执行相同的操作。有关匹配语义的讨论,请参见上面描述 <refspec>... 的部分。
这是为了模拟在
mothership上运行gitfetch,通过反向运行gitpush来集成在satellite上完成的工作,当您只能单向连接时,这通常是必要的(即 satellite 可以通过 ssh 连接到 mothership,但 mothership 无法发起连接到 satellite,因为后者在防火墙后面或未运行 sshd)。在
satellite机器上运行此gitpush后,您将通过 ssh 连接到mothership并在那里运行gitmerge,以完成在mothership上运行gitpull以拉取在satellite上所做更改的模拟。 gitpushoriginHEAD:master-
将当前分支推送到
origin仓库中与master匹配的远程引用。这种形式方便在不考虑本地名称的情况下推送当前分支。 gitpushoriginmaster:refs/heads/experimental-
通过复制当前的
master分支,在origin仓库中创建分支experimental。当本地名称与远程名称不同时,才需要此形式在远程仓库中创建新分支或标签;否则,单独的引用名称即可。 gitpushorigin:experimental-
在
origin仓库中找到与experimental匹配的引用(例如refs/heads/experimental),并删除它。 gitpushorigin+dev:master-
用 dev 分支更新 origin 仓库的 master 分支,允许非快进更新。**这可能在 origin 仓库中留下未引用的悬空提交。**
o---o---o---A---B origin/master \ X---Y---Z dev
考虑以下情况,其中快进不可能发生
A---B (unnamed branch) / o---o---o---X---Y---Z master
上述命令将把 origin 仓库更改为
安全性
提交 A 和 B 将不再属于具有符号名称的分支,因此将无法访问。因此,这些提交将通过在 origin 仓库上运行 git gc 命令而被删除。
已知的攻击向量如下:
-
抓取和推送协议并非旨在防止一方从另一方窃取不打算共享的仓库数据。如果您有需要保护免受恶意对等方侵害的私人数据,最好的选择是将其存储在另一个仓库中。这适用于客户端和服务器。特别是,服务器上的命名空间对于读取访问控制无效;您应该只向您信任其可以读取整个仓库的客户端授予命名空间的读取访问权限。
-
受害者发送“have”行,宣传其拥有的未明确打算共享但如果对等方也有则可用于优化传输的对象 ID。攻击者选择要窃取的对象 ID X 并向 X 发送引用,但不需要发送 X 的内容,因为受害者已经拥有它。现在受害者相信攻击者拥有 X,并且稍后会将 X 的内容发回给攻击者。(这种攻击对于客户端在服务器上执行最为直接,方法是在客户端有权访问的命名空间中创建一个指向 X 的引用,然后抓取它。服务器对客户端执行这种攻击最可能的方法是将 X “合并”到一个公共分支中,并希望用户在此分支上进行额外的工作并将其推回服务器而没有注意到合并。)
配置
本节中以下所有内容均从 git-config[1] 文档中选择性地包含。内容与彼处相同:
- push.autoSetupRemote
-
如果设置为“true”,则在当前分支不存在上游跟踪时,默认推送时假定使用
--set-upstream;此选项对 push.default 选项 *simple*、*upstream* 和 *current* 生效。如果您默认希望将新分支推送到默认远程仓库(如同 *push.default=current* 的行为),并且还希望设置上游跟踪,则此功能很有用。最可能受益于此选项的工作流程是所有分支都预期在远程上具有相同名称的*简单*集中式工作流程。 - push.default
-
定义了在未给定引用规范(无论是来自命令行、配置或其他地方)时
gitpush应采取的操作。不同的值适用于特定的工作流程;例如,在纯粹的集中式工作流程中(即抓取源等于推送目的地),upstream可能就是您想要的。可能的值有-
nothing- 除非给定引用规范,否则不推送任何内容(并报错)。这主要是为了那些希望通过始终明确来避免错误的人。 -
current- 推送当前分支以更新接收端同名的分支。适用于集中式和非集中式工作流程。 -
upstream- 将当前分支推送回通常集成到当前分支的那个分支(即@{upstream})。仅当您推送到通常从中拉取的同一个仓库时(即集中式工作流程),此模式才有意义。 -
tracking- 这是upstream的一个已弃用的同义词。 -
simple- 将当前分支推送到远程同名分支。如果您在集中式工作流程中工作(推送到与您拉取相同的仓库,通常是
origin),那么您需要配置一个同名的上游分支。自 Git 2.0 起,此模式为默认模式,是最适合初学者的安全选项。
-
matching- 推送两端同名的所有分支。这使得您要推送到的仓库会记住将要推送出去的分支集(例如,如果您总是将 maint 和 master 推送到那里,而没有其他分支,那么您要推送到的仓库将拥有这两个分支,并且您的本地 maint 和 master 将被推送到那里)。要有效使用此模式,您必须确保在运行 *git push* 之前,所有要推送的分支都已准备好被推送,因为此模式的全部目的就是让您一次性推送所有分支。如果您通常只在一个分支上完成工作并推送结果,而其他分支未完成,则此模式不适合您。此外,此模式不适合推送到共享的中心仓库,因为其他人可能会在那里添加新分支,或在您控制之外更新现有分支的尖端。
这曾是默认值,但自 Git 2.0 以来不再是(
simple是新的默认值)。
-
- push.followTags
-
如果设置为 true,默认启用
--follow-tags选项。您可以在推送时通过指定--no-follow-tags来覆盖此配置。 - push.gpgSign
-
可以设置为布尔值,或字符串 if-asked。true 值会导致所有推送都进行 GPG 签名,如同向 git-push[1] 传递了
--signed。字符串 if-asked 会导致推送在服务器支持时进行签名,如同向 git push 传递了--signed=if-asked。false 值可以覆盖来自较低优先级配置文件的值。显式命令行标志始终会覆盖此配置选项。 - push.pushOption
-
当命令行中没有给出
--push-option=<option> 参数时,gitpush的行为如同此变量的每个 <值> 都被作为--push-option=<value> 给出。这是一个多值变量,空值可以在优先级更高的配置文件(例如仓库中的
.git/config)中使用,以清除从优先级较低的配置文件(例如$HOME/.gitconfig)继承的值。Example: /etc/gitconfig push.pushoption = a push.pushoption = b ~/.gitconfig push.pushoption = c repo/.git/config push.pushoption = push.pushoption = b This will result in only b (a and c are cleared).
- push.recurseSubmodules
-
可以是“check”、“on-demand”、“only”或“no”,行为与“push --recurse-submodules”相同。如果未设置,默认使用 no,除非设置了 submodule.recurse(在这种情况下,true 值表示 on-demand)。
- push.useForceIfIncludes
-
如果设置为“true”,则等同于在命令行中将
--force-if-includes指定为 git-push[1] 的一个选项。在推送时添加--no-force-if-includes将覆盖此配置设置。 - push.negotiate
-
如果设置为“true”,则尝试通过客户端和服务器试图寻找共同提交的多轮协商来减小发送的 packfile 大小。如果为“false”,Git 将仅依赖服务器的引用通告来寻找共同提交。
- push.useBitmaps
-
如果设置为“false”,则即使
pack.useBitmaps为“true”,也会禁用“git push”使用位图,但不阻止其他 Git 操作使用位图。默认值为 true。