设置和配置
获取和创建项目
基本快照
分支和合并
共享和更新项目
检查和比较
补丁
调试
电子邮件
外部系统
服务器管理
指南
管理
底层命令
- 2.45.1 → 2.47.0 无更改
- 2.45.0 04/29/24
- 2.44.1 → 2.44.2 无更改
- 2.44.0 02/23/24
- 2.43.1 → 2.43.5 无更改
- 2.43.0 11/20/23
- 2.42.2 → 2.42.3 无更改
- 2.42.1 11/02/23
- 2.42.0 08/21/23
- 2.41.1 → 2.41.2 无更改
- 2.41.0 06/01/23
- 2.40.1 → 2.40.3 无更改
- 2.40.0 03/12/23
- 2.39.1 → 2.39.5 无更改
- 2.39.0 12/12/22
- 2.38.1 → 2.38.5 无更改
- 2.38.0 10/02/22
- 2.35.1 → 2.37.7 无更改
- 2.35.0 01/24/22
- 2.33.1 → 2.34.8 无更改
- 2.33.0 08/16/21
- 2.32.1 → 2.32.7 无更改
- 2.32.0 06/06/21
- 2.30.1 → 2.31.8 无更改
- 2.30.0 12/27/20
- 2.25.1 → 2.29.3 无更改
- 2.25.0 01/13/20
- 2.23.1 → 2.24.4 无更改
- 2.23.0 08/16/19
- 2.22.1 → 2.22.5 无更改
- 2.22.0 06/07/19
- 2.21.1 → 2.21.4 无更改
- 2.21.0 02/24/19
- 2.20.1 → 2.20.5 无更改
- 2.20.0 12/09/18
- 2.18.1 → 2.19.6 无更改
- 2.18.0 06/21/18
- 2.17.0 → 2.17.6 无更改
- 2.16.6 12/06/19
- 2.15.4 12/06/19
- 2.14.6 无更改
- 2.13.7 05/22/18
- 2.12.5 09/22/17
- 2.11.4 09/22/17
- 2.10.5 09/22/17
- 2.9.5 07/30/17
- 2.8.6 07/30/17
- 2.7.6 07/30/17
- 2.6.7 05/05/17
- 2.5.6 无更改
- 2.4.12 05/05/17
- 2.3.10 09/28/15
- 2.2.3 09/04/15
- 2.1.4 无更改
- 2.0.5 12/17/14
概要
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>指示远程端上哪个引用将通过此推送进行更新。此处不能使用任意的表达式,必须命名一个实际的引用。如果
git push [<repository>]
没有使用任何<refspec>
参数,并且设置为使用remote.<repository>.push
配置变量使用<src>
更新目标端的某个引用,则可以省略:<dst>
部分——这种推送将更新<src>
在没有命令行上的<refspec>
的情况下通常更新的引用。否则,缺少的:<dst>
意味着要更新与<src>
相同的引用。如果<dst>不以
refs/
开头(例如refs/heads/master
),我们将尝试根据被推送的<src>的类型以及<dst>是否模糊来推断它在目标<repository>上的refs/*
中的位置。-
如果<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
同名的分支,则将删除远程分支tmp
。这也会尊重 refspecs,例如,git push --prune remote refs/heads/*:refs/tmp/*
将确保如果refs/heads/foo
不存在,则会删除远程refs/tmp/foo
。 - --mirror
-
而不是命名每个要推送的 ref,而是指定
refs/
下的所有 ref(包括但不限于refs/heads/
、refs/remotes/
和refs/tags/
)被镜像到远程仓库。新创建的本地 ref 将被推送到远程端,本地更新的 ref 将被强制更新到远程端,删除的 ref 将从远程端删除。如果配置选项remote.<remote>.mirror
设置了,这是默认行为。 - -n
- --dry-run
-
除了实际发送更新之外,执行所有操作。
- --porcelain
-
生成机器可读的输出。每个 ref 的输出状态行将用制表符分隔并发送到标准输出而不是标准错误。将给出 ref 的完整符号名称。
- -d
- --delete
-
从远程仓库删除所有列出的 ref。这与在所有 ref 前面添加冒号相同。
- --tags
-
除了命令行中明确列出的 refspecs 之外,还会推送
refs/tags
下的所有 ref。 - --follow-tags
-
推送所有在没有此选项的情况下将被推送的 ref,以及推送
refs/tags
中在远程仓库中不存在但在指向正在推送的 ref 可达的提交对象的带注释的标签。这也可以通过配置变量push.followTags
来指定。有关更多信息,请参阅 git-config[1] 中的push.followTags
。 - --[no-]signed
- --signed=(true|false|if-asked)
-
GPG 签署推送请求以更新接收端的 ref,以便它可以被钩子检查或被记录。如果为
false
或--no-signed
,则不会尝试签名。如果为true
或--signed
,则如果服务器不支持签署推送,推送将失败。如果设置为if-asked
,则仅当服务器支持签署推送时才签名。如果实际调用gpg --sign
失败,推送也会失败。有关接收端的详细信息,请参阅 git-receive-pack[1]。 - --[no-]atomic
-
如果可用,在远程端使用原子事务。所有 ref 都会被更新,或者在出错时,不会更新任何 ref。如果服务器不支持原子推送,推送将失败。
- -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" 拒绝更新不是用于覆盖它的本地 ref 的祖先的远程 ref。
如果远程 ref 的当前值为预期值,此选项将覆盖此限制。"git push" 否则将失败。
假设您必须重新整理已发布的内容。您将必须绕过“必须快进”规则,才能用重新整理的历史记录替换最初发布的历史记录。如果其他人基于您的原始历史记录进行了构建,而您正在重新整理,则远程分支的尖端可能会随着他们的提交而前进,并且盲目地使用
--force
推送将丢失他们的工作。此选项允许您声明您希望更新的历史记录是您重新整理的,并且希望替换。如果远程 ref 仍然指向您指定的提交对象,则可以确定没有其他人对该 ref 做任何操作。这就像在没有显式锁定 ref 的情况下对 ref 进行“租用”,并且只有在“租用”仍然有效的情况下才会更新远程 ref。
--force-with-lease
仅在没有指定详细信息的情况下,将通过要求它们的当前值与我们为它们拥有的远程跟踪分支相同来保护所有将要更新的远程 ref。--force-with-lease=<refname>
在没有指定预期值的情况下,将通过要求它的当前值与我们为其拥有的远程跟踪分支相同来保护命名的 ref(单独),如果它将要更新。--force-with-lease=<refname>:<expect>
将通过要求它的当前值与指定的<expect>
值相同来保护命名的 ref(单独),如果它将要更新(此值允许与我们为 refname 拥有的远程跟踪分支不同,或者我们甚至不必在使用此形式时拥有这样的远程跟踪分支)。如果<expect>
为空字符串,则命名的 ref 必须不存在。请注意,除了
--force-with-lease=<refname>:<expect>
之外的所有形式都明确指定了 ref 的预期当前值,仍然处于实验阶段,它们的语义可能会随着我们对该功能的经验而改变。"--no-force-with-lease" 将取消命令行中之前的所有 --force-with-lease。
关于安全性的一个一般说明:在没有预期值的情况下提供此选项,即作为
--force-with-lease
或--force-with-lease=<refname>
,与任何在后台隐式对要推送到的远程运行git fetch
的操作非常糟糕,例如,在 cronjob 中对您的仓库运行git fetch origin
。它提供的比
--force
更强的保护是确保不会覆盖您工作未基于的后续更改,但这可以通过在后台更新 ref 的某些后台进程轻松地打破。除了远程跟踪信息之外,我们没有任何东西可以作为您预期看到的 ref 的启发式方法,并且您愿意覆盖。如果您的编辑器或其他一些系统正在后台为您运行
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
即,为您看到并愿意覆盖的 upstream 代码的版本创建
base
标签,然后重写历史记录,最后如果远程版本仍然在base
,则将更改强制推送到master
,无论您本地的remotes/origin/master
在后台更新到什么。或者,在“推送”时指定
--force-if-includes
作为辅助选项以及--force-with-lease[=<refname>]
(即,没有说远程端的 ref 必须指向哪个确切的提交对象,或者远程端的哪些 ref 受保护),将在允许强制更新之前验证是否在本地集成了可能在后台隐式更新的远程跟踪 ref 的更新。 - -f
- --force
-
通常,该命令拒绝更新不是用于覆盖它的本地 ref 的祖先的远程 ref。此外,当使用
--force-with-lease
选项时,该命令拒绝更新当前值与预期不匹配的远程 ref。此标志将禁用这些检查,并且会导致远程仓库丢失提交;请谨慎使用。
请注意,
--force
适用于所有被推送的 ref,因此将其与设置为matching
的push.default
一起使用,或者使用remote.*.push
配置多个推送目标,可能会覆盖除当前分支之外的 ref(包括严格落后于其远程对应物的本地 ref)。要强制将推送推送到单个分支,请在 refspec 前面使用一个+
来进行推送(例如,git push origin +master
强制将推送推送到master
分支)。有关详细信息,请参阅上面的<refspec>...
部分。 - --[no-]force-if-includes
-
仅当远程跟踪 ref 的尖端已在本地集成时才强制更新。
此选项将启用一个检查,以验证远程跟踪 ref 的尖端是否可以从基于它的本地分支的“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 配置变量,当不需要子模块递归时。当使用 on-demand 或 only 时,如果子模块具有“push.recurseSubmodules={on-demand,only}”或“submodule.recurse”配置,则将发生进一步的递归。在这种情况下,“only”被视为“on-demand”。
- --[no-]verify
-
切换预推送钩子(见 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>
也可以使用 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/
这两种语法基本等效,除了克隆时,前者隐含 --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”或“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,因为它们都包含一个 refspec,git 将默认使用它。
配置文件中的命名远程
您可以选择提供您之前使用 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 或所有定义的 urls(如果未定义 pushurls)。但是,如果定义了多个 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>
OUTPUT
“git push”的输出取决于使用的传输方法;本节描述通过 Git 协议(本地或通过 ssh)推送时的输出。
推送的状态以表格形式输出,每行代表单个引用的状态。每行具有以下形式
<flag> <summary> <from> -> <to> (<reason>)
如果使用 --porcelain,则输出的每行具有以下形式
<flag> \t <from>:<to> \t <summary> (<reason>)
仅当使用 --porcelain 或 --verbose 选项时,才会显示已更新引用的状态。
- flag
-
表示引用状态的单个字符
- summary
-
对于成功推送的引用,摘要显示引用的旧值和新值,以适合用作
git log
的参数的形式(在大多数情况下为<old>..<new>
,对于强制的非快进更新则为<old>...<new>
)。对于失败的更新,将提供更多详细信息
- rejected
-
Git 根本没有尝试发送引用,通常是因为它不是快进,并且您没有强制更新。
- 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,会描述失败的原因。
关于快进的说明
当更新更改分支(或更一般地,ref)时,该分支以前指向提交 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,该提交在 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>(如以下示例中的 <refspec>)都可以配置为git push origin
的默认值。 -
git push origin :
-
将“匹配”的分支推送到
origin
。有关“匹配”分支的说明,请参见上面 选项 部分中的 <refspec>。 -
git push origin master
-
查找源存储库中与
master
匹配的 ref(很可能,它会找到refs/heads/master
),并使用它更新origin
存储库中的相同 ref(例如refs/heads/master
)。如果master
在远程不存在,它将被创建。 -
git push origin HEAD
-
将当前分支推送到远程上的相同名称的一个方便方法。
-
git push mothership master:satellite/master dev:satellite/dev
-
使用与
master
匹配的源 ref(例如refs/heads/master
)来更新与satellite/master
匹配的 ref(最可能是refs/remotes/satellite/master
)在mothership
存储库中;对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
匹配的远程 ref。此形式便于推送当前分支,无需考虑其本地名称。 -
git push origin master:refs/heads/experimental
-
通过复制当前
master
分支在origin
存储库中创建experimental
分支。此形式仅在本地名称和远程名称不同时才需要创建远程存储库中的新分支或标签;否则,ref 名称本身将起作用。 -
git push origin :experimental
-
查找
origin
存储库中与experimental
匹配的 ref(例如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
命令删除。
安全
获取和推送协议并非旨在防止一方从另一方存储库中窃取不应共享的数据。如果你有需要保护免受恶意对等方攻击的私有数据,最好的选择是将其存储在另一个存储库中。这适用于客户端和服务器。特别是,服务器上的命名空间对于读访问控制无效;你应该只向你信任读取整个存储库的客户端授予对命名空间的读取访问权限。
已知的攻击媒介如下
-
受害者发送“have”行,宣传它拥有的对象的 ID,这些对象并非明确要共享,但如果对等方也拥有它们,则可用于优化传输。攻击者选择要窃取的对象 ID X 并向 X 发送 ref,但不一定需要发送 X 的内容,因为受害者已经拥有它。现在受害者认为攻击者拥有 X,它会在稍后将 X 的内容发送回攻击者。(这种攻击对客户端对服务器执行起来最简单,方法是在客户端有权访问的命名空间中创建对 X 的 ref,然后获取它。服务器对客户端执行它的最可能方式是将 X “合并”到公共分支中,并希望用户在此分支上进行更多工作并将其推回服务器,而没有注意到合并。)
-
与 #1 一样,攻击者选择要窃取的对象 ID X。受害者发送攻击者已经拥有的对象 Y,而攻击者错误地声称拥有 X 而没有 Y,因此受害者将 Y 作为 X 的 delta 发送。delta 向攻击者揭示 X 中与 Y 相似的区域。
配置
本节中此行以下的所有内容都是从 git-config[1] 文档中选择性地包含的。内容与那里找到的内容相同
- push.autoSetupRemote
-
如果设置为“true”,则在默认推送时假设
--set-upstream
,而当前分支没有上游跟踪;此选项在 push.default 选项为 simple、upstream 和 current 时生效。如果默认情况下你想将新分支推送到默认远程(类似于 push.default=current 的行为),并且你还想设置上游跟踪,那么此选项很有用。最有可能从此选项中受益的工作流是 简单 的集中式工作流,其中所有分支都期望在远程具有相同的名称。 - push.default
-
定义
git push
在没有给出 refspec 时应采取的操作(无论是来自命令行、配置还是其他地方)。不同的值非常适合特定的工作流;例如,在纯粹的集中式工作流中(即获取源与推送目标相同),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。真值会导致所有推送都使用 GPG 签名,就像将
--signed
传递给git-push[1]一样。字符串if-asked会导致在服务器支持的情况下对推送进行签名,就像将--signed=if-asked
传递给git push一样。假值可能会覆盖来自较低优先级配置文件的值。显式的命令行标志始终会覆盖此配置选项。 - 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",则等效于在命令行中将
--force-if-includes
指定为git-push[1]的选项。在推送时添加--no-force-if-includes
会覆盖此配置设置。 - push.negotiate
-
如果设置为 "true",则尝试通过客户端和服务器尝试找到共同提交的协商轮次来减少发送的 packfile 的大小。如果为 "false",Git 将完全依赖于服务器的 ref 广告来找到共同提交。
- push.useBitmaps
-
如果设置为 "false",即使
pack.useBitmaps
为 "true",也会禁用对 "git push" 使用位图,但不会阻止其他 git 操作使用位图。默认值为 true。
GIT
是git[1]套件的一部分