设置和配置
获取和创建项目
基本快照
分支和合并
共享和更新项目
检查和比较
补丁
调试
邮件
外部系统
服务器管理
指南
管理
底层命令
- 2.48.1 → 2.49.0 没有变化
-
2.48.0
2025-01-10
- 2.45.1 → 2.47.2 没有变化
-
2.45.0
2024-04-29
- 2.44.1 → 2.44.3 没有变化
-
2.44.0
2024-02-23
- 2.43.1 → 2.43.6 没有变化
-
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
值:当前分支被推送到相应的上游分支,但作为安全措施,如果上游分支的名称与本地分支的名称不同,则会中止推送。
选项
- <repository>
-
作为推送操作目标的“远程”仓库。此参数可以是 URL(请参阅下面的 GIT URLS 部分)或远程的名称(请参阅下面的 REMOTES 部分)。
- <refspec>…
-
指定要使用什么源对象更新什么目标引用。 <refspec> 参数的格式是一个可选的加号
+
,后跟源对象 <src>,后跟一个冒号:
,后跟目标引用 <dst>。<src> 通常是您要推送的分支的名称,但它可以是任何任意的“SHA-1 表达式”,例如
master~4
或HEAD
(请参见 gitrevisions[7])。<dst> 告诉我们要使用此推送更新远程端的哪个引用。此处不能使用任意表达式,必须命名实际的引用。 如果将没有
<refspec>
参数的git push [<repository>]
设置为通过remote.<repository>.push
配置变量使用<src>
更新目标处的某个引用,则可以省略:<dst>
部分——此类推送将更新一个<src>
通常更新的引用,而命令行上没有任何<refspec>
。否则,缺少:<dst>
意味着更新与<src>
相同的引用。如果 <dst> 不以
refs/
开头(例如refs/heads/master
),我们将尝试推断它在目标 <repository> 上的refs/*
中的位置,这基于被推送的 <src> 的类型以及 <dst> 是否含糊不清。-
如果 <dst> 明确地指向 <repository> 远程仓库上的引用,则推送到该引用。
-
如果 <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/*
中的对象相同,对它们的任何更新都将被拒绝。可以通过在 refspec 中添加可选的前导
+
(或使用--force
命令行选项)来覆盖上述所有关于不允许作为更新的规则。 唯一的例外是,无论如何强制执行都不会使refs/heads/*
命名空间接受非提交对象。 钩子和配置也可以覆盖或修改这些规则,例如,请参见 git-config[1] 中的receive.denyNonFastForwards
和 githooks[5] 中的pre-receive
和update
。推送空的 <src> 允许您从远程仓库中删除 <dst> 引用。 始终接受删除,而无需在 refspec 中使用前导
+
(或--force
),除非配置或钩子禁止这样做。 请参见 git-config[1] 中的receive.denyDeletes
和 githooks[5] 中的pre-receive
和update
。特殊的 refspec
:
(或+:
以允许非快进更新)指示 Git 推送“匹配”的分支:对于本地端存在的每个分支,如果远程端已存在同名分支,则更新远程端。tag <tag>
与refs/tags/<tag>:refs/tags/<tag>
的含义相同。 -
- --all
- --branches
-
推送所有分支(即
refs/heads/
下的引用); 不能与其他 <refspec> 一起使用。 - --prune
-
删除没有本地对应项的远程分支。 例如,如果不再存在同名的本地分支,则将删除远程分支
tmp
。 这也尊重 refspec,例如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
-
产生机器可读的输出。每个引用的输出状态行将以制表符分隔,并发送到 stdout 而不是 stderr。将给出引用的完整符号名称。
- -d
- --delete
-
所有列出的引用都将从远程仓库中删除。这与在所有引用前加上冒号相同。
- --tags
-
除了命令行上显式列出的引用规范之外,还将推送
refs/tags
下的所有引用。 - --follow-tags
-
推送所有不使用此选项也会推送的引用,并推送
refs/tags
中缺失的,但指向可从被推送的引用访问的 commit-ish 的带注释标签。也可以使用配置变量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 <option>
- --push-option=<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=<refname>
- --force-with-lease=<refname>:<expect>
-
通常,"git push" 拒绝更新不是用于覆盖它的本地引用的祖先的远程引用。
如果远程引用的当前值是预期值,则此选项将覆盖此限制。否则,“git push”将失败。
想象一下,您必须 rebase 已经发布的内容。您必须绕过“必须 fast-forward”规则,才能将最初发布的历史记录替换为 rebase 后的历史记录。如果在您 rebase 时,有人在您的原始历史记录之上构建,则远程分支的 tip 可能会随着他们的提交而前进,而盲目地使用
--force
推送会丢失他们的工作。此选项允许您声明您期望正在更新的历史记录是您 rebase 并想要替换的历史记录。如果远程引用仍然指向您指定的 commit,您可以确定没有人对该引用执行任何操作。这就像在引用上取得“租约”而无需显式锁定它,并且只有当“租约”仍然有效时,远程引用才会被更新。
单独的
--force-with-lease
,不指定详细信息,将通过要求所有将被更新的远程引用的当前值与我们拥有的远程跟踪分支的值相同来保护它们。--force-with-lease=<refname>
,不指定预期值,如果它将被更新,则通过要求其当前值与我们拥有的远程跟踪分支的值相同来保护命名的引用(单独)。--force-with-lease=<refname>:<expect>
将保护命名的引用(单独),如果它将被更新,则要求其当前值与指定的值<expect>
相同(允许它与我们拥有的 refname 的远程跟踪分支不同,或者我们甚至在使用此形式时不必有这样的远程跟踪分支)。如果<expect>
是空字符串,则命名的引用必须尚不存在。请注意,除了显式指定引用预期当前值的
--force-with-lease=<refname>:<expect>
之外的所有形式仍然是实验性的,并且它们的语义可能会随着我们获得此功能的经验而改变。"--no-force-with-lease" 将取消命令行上所有先前的 --force-with-lease。
关于安全性的一般说明:在没有预期值的情况下提供此选项,即作为
--force-with-lease
或--force-with-lease=<refname>
与在后台隐式运行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 # 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
标签,然后重写历史记录,最后强制推送更改到master
,如果远程版本仍然在base
,而不管您的本地remotes/origin/master
在后台已更新到什么。或者,在 “push” 时指定
--force-if-includes
作为辅助选项与--force-with-lease[=<refname>]
一起(即,不说明远程端的引用必须指向哪个确切的提交,或者远程端的哪些引用受到保护)将验证在允许强制更新之前,是否已在本地集成可能已在后台隐式更新的远程跟踪引用中的更新。 - -f
- --force
-
通常,该命令拒绝更新不是用于覆盖它的本地引用的祖先的远程引用。此外,当使用
--force-with-lease
选项时,该命令拒绝更新当前值与预期值不匹配的远程引用。此标志禁用这些检查,并可能导致远程仓库丢失提交;谨慎使用。
请注意,
--force
应用于所有被推送的引用,因此将其与设置为matching
的push.default
或配置了多个推送目标的remote.*.push
一起使用可能会覆盖当前分支以外的引用(包括严格落后于其远程对应部分的本地引用)。要强制推送到一个分支,请在要推送的 refspec 前面使用+
(例如git push origin +master
强制推送到master
分支)。有关详细信息,请参见上面的<refspec>...
部分。 - --[no-]force-if-includes
-
仅当本地集成了远程跟踪引用的 tip 时才强制更新。
此选项启用一项检查,以验证远程跟踪引用的 tip 是否可以从本地分支中基于它的一个“reflog”条目访问以进行重写。该检查通过拒绝强制更新来确保来自远程仓库的任何更新都已在本地合并(如果不是这种情况)。
如果该选项在未指定
--force-with-lease
的情况下传递,或者与--force-with-lease=<refname>:<expect>
一起指定,则它是“no-op”。指定
--no-force-if-includes
禁用此行为。 - --repo=<repository>
-
此选项等效于 <repository> 参数。如果两者都指定,则命令行参数优先。
- -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*,将推送在要推送的修订版中更改的所有子模块。如果 on-demand 无法推送所有必要的修订版,它也将被中止并以非零状态退出。如果使用 *only*,则将推送所有子模块,而超级项目保持未推送状态。当不需要子模块递归时,可以使用值 *no* 或使用
--no-recurse-submodules
来覆盖 push.recurseSubmodules 配置变量。当使用按需或仅时,如果子模块具有 "push.recurseSubmodules={on-demand,only}" 或 "submodule.recurse" 配置,则会发生进一步的递归。 在这种情况下,“仅”被视为“按需”。
- --[no-]verify
-
切换 pre-push 钩子(参见 githooks[5])。 默认值为 --verify,让钩子有机会阻止推送。 使用 --no-verify,钩子将被完全绕过。
- -4
- --ipv4
-
仅使用 IPv4 地址,忽略 IPv6 地址。
- -6
- --ipv6
-
仅使用 IPv6 地址,忽略 IPv4 地址。
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 clone
、git fetch
和 git 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" 这样的 URL 或像 "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>
。 推送到远程仓库会影响所有定义的 pushurl 或所有定义的 url(如果未定义 pushurl)。 但是,如果定义了多个 url,则抓取只会从第一个定义的 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 pull 和 git 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 push" 的输出取决于使用的传输方法; 本节描述了通过 Git 协议(本地或通过 ssh)推送时的输出。
推送的状态以表格形式输出,每行代表单个 ref 的状态。 每行的格式为
<flag> <summary> <from> -> <to> (<reason>)
如果使用 --porcelain,则输出的每一行都采用以下格式
<flag> \t <from>:<to> \t <summary> (<reason>)
仅当使用 --porcelain 或 --verbose 选项时,才会显示最新的 ref 的状态。
- flag
-
指示 ref 状态的单个字符
- summary
-
对于成功推送的 ref,摘要以适合用作
git log
参数的形式显示 ref 的旧值和新值(在大多数情况下为<old>..<new>
,对于强制的非快进更新,则为<old>...<new>
)。对于失败的更新,将提供更多详细信息
- rejected
-
Git 根本没有尝试发送 ref,通常是因为它不是快进并且您没有强制更新。
- remote rejected
-
远程端拒绝了更新。 通常是由于远程端的钩子引起的,或者是因为远程仓库具有以下安全选项之一:
receive.denyCurrentBranch
(用于推送到已检出的分支),receive.denyNonFastForwards
(用于强制的非快进更新),receive.denyDeletes
或receive.denyDeleteCurrent
。 请参见 git-config[1]。 - remote failure
-
远程端未报告 ref 的成功更新,可能是由于远程端的临时错误、网络连接中断或其他瞬时错误。
- from
-
正在推送的本地 ref 的名称,减去其
refs/<type>/
前缀。 在删除的情况下,将省略本地 ref 的名称。 - to
-
正在更新的远程 ref 的名称,减去其
refs/<type>/
前缀。 - reason
-
人类可读的解释。 对于成功推送的 ref,不需要解释。 对于失败的 ref,将描述失败的原因。
关于快进的说明
当更新将指向提交 A 的分支(或更常见的是 ref)更改为指向另一个提交 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,该提交在 A 之上构建 X 和 B 之间的更改。
B D / / ---X---A
同样,使用此提交更新 A 将进行快进,并且您的推送将被接受。
还有另一种常见的情况,当您尝试推送时可能会遇到非快进拒绝,即使您正在推送到没有人推送的仓库中也可能发生。 在您自己推送提交 A 之后(在本节的第一张图片中),使用 "git commit --amend" 替换它以生成提交 B,然后您尝试将其推送出去,因为忘记您已经推送了 A。在这种情况下,只有在您确定没有人在此期间抓取您之前的提交 A(并开始在其之上构建)的情况下,您才可以运行 "git push --force" 来覆盖它。 换句话说,"git push --force" 是一种为确实要丢失历史记录的情况保留的方法。
示例
-
git push
-
类似于
git push <remote>
,其中 <remote> 是当前分支的远程分支(如果当前分支未配置远程分支,则为origin
)。 -
git push origin
-
如果没有额外的配置,会将当前分支推送到配置的上游分支 (
branch.<name>.merge
配置变量),前提是它与当前分支具有相同的名称,否则会出错且不会推送。如果没有提供 <refspec>,此命令的默认行为可以通过设置远程的
push
选项或push.default
配置变量来配置。例如,要默认仅将当前分支推送到
origin
,请使用git config remote.origin.push HEAD
。任何有效的 <refspec> (例如下面的示例) 都可以配置为git push origin
的默认值。 -
git push origin :
-
将“匹配的”分支推送到
origin
。有关“匹配的”分支的描述,请参见上面的 OPTIONS 部分中的 <refspec>。 -
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
执行相同的操作。有关匹配语义的讨论,请参见上面描述
<refspec>...
的部分。这是为了模拟在
mothership
上运行的git fetch
,使用在相反方向运行的git push
,以便集成在satellite
上完成的工作,这通常是在只能以一种方式建立连接时所必需的(即,satellite 可以 ssh 进入 mothership,但 mothership 无法启动与 satellite 的连接,因为后者位于防火墙后面或未运行 sshd)。在
satellite
机器上运行此git push
之后,您将 ssh 进入mothership
并在那里运行git merge
,以完成模拟在mothership
上运行的git pull
,从而拉取在satellite
上所做的更改。 -
git push origin HEAD:master
-
将当前分支推送到
origin
存储库中与master
匹配的远程引用。 这种形式便于推送当前分支,而无需考虑其本地名称。 -
git push origin master:refs/heads/experimental
-
通过复制当前的
master
分支,在origin
存储库中创建experimental
分支。 仅当本地名称和远程名称不同时,才需要此形式在远程存储库中创建新分支或标签;否则,单独的引用名称即可起作用。 -
git push origin :experimental
-
在
origin
存储库中查找与experimental
匹配的引用(例如refs/heads/experimental
),并将其删除。 -
git push origin +dev:master
-
使用 dev 分支更新 origin 存储库的 master 分支,允许非快进更新。 这可能会使未引用的提交在 origin 存储库中悬空。 考虑以下情况,其中无法进行快进
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 将不再属于具有符号名称的分支,因此将无法访问。 因此,这些提交将被 origin 存储库上的
git gc
命令删除。
安全性
fetch 和 push 协议并非旨在阻止一方从另一存储库窃取原本不打算共享的数据。 如果您有需要保护免受恶意对等方攻击的私有数据,最好的选择是将其存储在另一个存储库中。 这适用于客户端和服务器。 特别是,服务器上的命名空间对于读取访问控制无效;您应该仅向您信任其具有对整个存储库的读取访问权限的客户端授予对命名空间的读取访问权限。
已知的攻击媒介如下
-
受害者发送 "have" 行,声明它拥有的对象的 ID,这些对象并非明确打算共享,但如果对等方也拥有它们,则可用于优化传输。 攻击者选择要窃取的对象 ID X,并发送对 X 的引用,但不要求发送 X 的内容,因为受害者已经拥有它。 现在,受害者认为攻击者拥有 X,并且稍后会将 X 的内容发回给攻击者。(对于客户端在服务器上执行此攻击,通过在客户端有权访问的命名空间中创建对 X 的引用,然后获取它,这是最直接的。 服务器在客户端上执行此操作的最可能方法是将 X "合并" 到公共分支中,并希望用户在此分支上进行其他工作,并在没有注意到合并的情况下将其推送回服务器。)
-
与 #1 中一样,攻击者选择要窃取的对象 ID X。 受害者发送攻击者已拥有的对象 Y,攻击者谎称拥有 X 而没有 Y,因此受害者将 Y 作为针对 X 的增量发送。 增量向攻击者显示了 X 中与 Y 相似的区域。
配置
此部分中此行以下的所有内容均从 git-config[1] 文档中选择性地包含。 内容与在那里找到的内容相同
- push.autoSetupRemote
-
如果设置为 "true",则在当前分支不存在上游跟踪时,默认 push 上假设为
--set-upstream
; 此选项在使用 push.default 选项 *simple*、*upstream* 和 *current* 时生效。 如果您默认希望将新分支推送到默认远程(例如 *push.default=current* 的行为),并且您也希望设置上游跟踪,则此选项很有用。 最有可能从该选项中受益的工作流程是 *simple* 中央工作流程,其中所有分支都应在远程上具有相同的名称。 - push.default
-
定义如果未提供 refspec (无论是来自命令行、配置还是其他位置),
git push
应执行的操作。 不同的值非常适合特定的工作流程; 例如,在纯粹的中央工作流程中(即,fetch 源等于 push 目标),您可能需要upstream
。 可能的值是-
nothing
- 除非提供 refspec,否则不推送任何内容(出错)。 这主要适用于那些希望通过始终保持明确来避免错误的人。 -
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 签名,就像将
--signed
传递给 git-push[1] 一样。 字符串 if-asked 会导致在服务器支持时对推送进行签名,就像将--signed=if-asked
传递给 *git push* 一样。 值为 false 可能会覆盖来自较低优先级配置文件的值。 显式命令行标志始终会覆盖此配置选项。 - push.pushOption
-
如果未从命令行给出
--push-option=<option>
参数,则git push
的行为就好像此变量的每个 <value> 都作为--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",则相当于在命令行中为 git-push[1] 指定
--force-if-includes
选项。 在推送时添加--no-force-if-includes
会覆盖此配置设置。 - push.negotiate
-
如果设置为 "true",尝试通过客户端和服务器尝试查找共同提交的几轮协商来减小发送的 packfile 的大小。 如果为 "false",Git 将仅依赖服务器的 ref 广播来查找共同提交。
- push.useBitmaps
-
如果设置为 "false",则禁用 "git push" 使用位图,即使
pack.useBitmaps
为 "true",也不会阻止其他 git 操作使用位图。 默认为 true。
GIT
是 git[1] 套件的一部分