## Name

git-push - 更新远程引用以及关联的对象

## 概要

    git push [--all | --mirror | --tags] [--follow-tags] [--atomic] [-n | --dry-run] [--receive-pack=<git-receive-pack>]           [--repo=<repository>] [-f | --force] [-d | --delete] [--prune] [-v | --verbose]           [-u | --set-upstream] [--push-option=<string>]           [--[no-]signed|--sign=(true|false|if-asked)]           [--force-with-lease[=<refname>[:<expect>]]]           [--no-verify] [<repository> [<refspec>…]]

## 描述

使用本地引用更新远程引用，同时发送完成给定引用所需的对象。

您可以在每次进入存储库时通过在存储库中设置有趣的事情`hooks`。请参阅 git-receive-pack [1] 的文档。

当命令行未指定将`<repository>`参数推`branch.*.remote`送到何处时，将查阅当前分支的配置以确定推送的位置。如果配置丢失，则默认为`origin`。

当在命令行中没有指定，可以把什么`<refspec>...`参数或`--all`，`--mirror`，`--tags`选项，该命令将查找默认`<refspec>`通过咨询`remote.*.push`配置，如果没有找到它，荣誉`push.default`配置来决定推什么（请查看 git-config[1]为）`push.default` 的意思。

如果命令行和配置均未指定要推送的内容，则使用默认行为，该行为对应于以下`simple`值`push.default`：当前分支被推送到相应的上游分支，但作为安全措施，如果上游分公司不具有与本地名称相同的名称。

## 选项

<repository>

作为推送操作目标的“远程”存储库。此参数可以是 URL（请参阅下面的 GIT URLS 部分）或远程名称（请参阅下面的 REMOTES 部分）。

<refspec>…

指定源对象要更新的目标引用。一个 <refspec> 参数的格式是一个可选的 plus `+`，后面是源对象 <src> ，后面是一个冒号`:`，后面是目标 ref <dst> 。

<src> 通常是您想要推送的分支的名称，但它可以是任意的“SHA-1表达式”，例如`master~4` `或` `HEAD`（请参阅 gitrevisions [7] ）。

<dst> 通过这个推送来告诉远程端的哪个 ref 被更新。任意表达式不能在这里使用，必须命名实际的引用。如果`git push [<repository>]`没有任何`<refspec>`参数设置为`<src>`使用`remote.<repository>.push`配置变量更新目标中的某个 ref ，`:<dst>`则可以省略部分 - 这样的推送将更新`<src>`通常`<refspec>`在命令行上没有任何更新的 ref 。否则，缺少`:<dst>`意味着更新相同的参考作为`<src>`。

由 <src> 引用的对象用于更新远程端的 <dst> 引用。默认情况下，只有当 <dst> 不是标签（带注释或轻量级标签）时才允许使用，并且只有在它可以快速转发 <dst> 时才允许使用。通过具有可选的领导`+`，你可以让 Git 更新 <DST> REF 即使是默认不允许的（比如，它不是一个快进。）这并不会试图合并<来源>为 <DST> 。有关详细信息，请参阅下面的示例。

`tag <tag>` means the same as `refs/tags/<tag>:refs/tags/<tag>`.

推送一个空的 <src>允许你从远程仓库中删除 <dst> ref 。

特殊 refspec `:`（或`+:`允许非快进更新）指示 Git 推送“匹配”分支：对于本地存在的每个分支，如果远程已存在的同名分支已经存在，则更新远程端侧。

--all

推送所有分支（即参考下`refs/heads/`）; 不能与其他 <refspec> 一起使用。

--prune

删除没有本地副本的远程分支。例如，`tmp`如果具有相同名称的本地分支不再存在，则远程分支将被删除。这也尊重 refspecs ，例如`git push --prune remote refs/heads/*:refs/tmp/*`，`refs/tmp/foo`如果`refs/heads/foo`不存在，将确保远程将被删除。

--mirror

代替命名每个裁判推的，指定了下的所有参考文献`refs/`（包括但不限于`refs/heads/`，`refs/remotes/`和`refs/tags/`）被镜像到远程存储库。新创建的本地参考将被推送到远端，本地更新的参考将在远端强制更新，删除的参考将从远端移除。如果`remote.<remote>.mirror`设置了配置选项，这是默认值。

-n --dry-run

做除了实际发送更新之外的其他事

--porcelain

生成机器可读的输出。每个 ref 的输出状态行将被制表符分隔并发送到 stdout 而不是 stderr 。将给出参考文献的完整符号名称。

--delete

所有列出的 ref 都从远程存储库中删除。这与用冒号前缀所有引用相同。

--tags

`refs/tags`除了在命令行中明确列出的 refspecs 之外，所有 refs 都将被推送。

--follow-tags

推送所有没有此选项时将被推送的引用，并且推送`refs/tags`远程引用中缺少的带注释的标签，但指向可从所推送的引用访问的提交标识。这也可以通过配置变量来指定`push.followTags`。有关更多信息，请参阅`push.followTags` git-config [1]。

--no-signed --sign=(true|false|if-asked)

GPG - 签署推送请求以更新接收端的 refs，以便通过钩子检查和/或记录。如果`false`或者`--no-signed`，不会尝试签名。如果`true`或者`--signed`，如果服务器不支持签名推送，推送将失败。如果设置为`if-asked`，则当且仅当服务器支持签名推送时签名。如果实际的呼叫`gpg --sign`失败，推送也会失败。有关接收端的详细信息，请参阅 git-receive-pack [1]。

--no-atomic

如果可用，请在远程端使用原子事务。要么所有的参考文献都被更新，要么出错，没有参考文献被更新。如果服务器不支持原子推送，推送将失败。

-o --push-option

将给定的字符串传送给服务器，服务器将它们传递给预接收以及接收后挂接。给定的字符串不能包含 NUL 或 LF 字符。

--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 上“租赁”而不显式锁定它，只有当“租约”仍然有效时才更新远程参考。

`--force-with-lease` 单独的，没有指定细节，将通过要求它们的当前值与我们对它们的远程跟踪分支相同来保护将被更新的所有远程参考。

`--force-with-lease=<refname>`，而不指定期望值，如果它将要更新，将通过要求它的当前值与我们为它的远程跟踪分支相同来保护指定的 ref（单独）。

`--force-with-lease=<refname>:<expect>`将保护指定的 ref（单独），如果它将被更新，则通过要求其当前值与指定值相同`<expect>`（其可以不同于我们针对 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`遥控器上的在后台推到，例如`git fetch origin`在一个你存储库的 cronjob 。

它提供的保护措施`--force`是确保您的工作不基于的后续更改不会被破坏，但如果某些后台进程正在更新后台中的 refs ，则会被轻微击败。除了远程追踪信息外，我们没有任何东西可以作为启发式参考，您预计会看到并愿意诋毁。

如果您的编辑器或其他系统正在`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`更新为背景。

-f --force

通常，该命令拒绝更新远程 ref ，该远程 ref 不是用于覆盖它的本地 ref 的祖先。另外，当使用`--force-with-lease`选项时，该命令拒绝更新当前值与预期值不匹配的远程参考。

该标志会禁用这些检查，并可能导致远程存储库丢失提交; 小心使用它。

请注意，`--force`适用于所有推入的 ref，因此使用它`push.default`设置为`matching`或配置有多个推送目标，`remote.*.push`可能会覆盖当前分支以外的引用（包括严格位于其远程对象之后的本地引用）。要强制只推送一个分支，可以使用`+`refspec前面的一个按钮（例如`git push origin +master`强制推送`master`分支）。有关`<refspec>...`详情，请参阅上面的部分。

--repo=<repository>

该选项等同于 <repository> 参数。如果两者都指定，则命令行参数优先。

-u --set-upstream

对于最新或成功推送的每个分支，添加无参数 git-pull [1] 和其他命令使用的上游（跟踪）引用。有关更多信息，请参阅`branch.<name>.merge` git-config [1]。

--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 配置变量。

--no-verify

切换预推钩（见 githooks [5]）。默认值是 - 验证，使钩子有机会阻止推送。使用 --no-verify ，挂钩完全被旁路。

-4 --ipv4

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

-6 --ipv6

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

## Git 网址

通常，URL 包含有关传输协议，远程服务器地址和存储库路径的信息。根据传输协议，这些信息可能不存在。

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/

- https://host.xz:port/path/to/repo.git/

- ftps://host.xz:port/path/to/repo.git/

ssh 协议也可以使用另一种类似 scp 的语法：

- user@host.xz：path / to / repo.git /只有在第一个冒号前没有斜线时才能识别此语法。这有助于区分包含冒号的本地路径。例如，本地路径`foo:bar`可以被指定为绝对路径或`./foo:bar`避免被误解为 ssh url 。ssh 和 git 协议还支持用户名扩展：

- 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/

对于本地支持的本地存储库，可以使用以下语法：

- /path/to/repo.git/

- file:///path/to/repo.git/

这两种语法大多是相同的，除了克隆时，前者意味着 --local 选项。有关详细信息，请参阅 git-clone [1]。

当 Git 不知道如何处理某个传输协议时，它会尝试使用`remote-<transport>`远程助手（如果存在）。要显式请求远程助手，可以使用以下语法：

- <transport>::<address>where <address> may be a path, a server and path, or an arbitrary URL-like string recognized by the specific remote helper being invoked. See gitremote-helpers[1] for details.If there are a large number of similarly-named remote repositories and you want to use a different format for them (such that the URLs you use will be rewritten into URLs that work), you can create a configuration section of the form: [url "<actual url base>"] insteadOf = <other url base>For example, with this: [url "git://git.host.xz/"] insteadOf = host.xz:/path/to/ insteadOf = work:a URL like "work:repo.git" or like "host.xz:/path/to/repo.git" will be rewritten in any context that takes a URL to be "git://git.host.xz/repo.git".If you want to rewrite URLs for push only, you can create a configuration section of the form: [url "<actual url base>"] pushInsteadOf = <other url base>For example, with this: [url "ssh://example.org/"] pushInsteadOf = git://example.org/a URL like "git://example.org/path/to/repo.git" will be rewritten to "ssh://example.org/path/to/repo.git" for pushes, but pulls will still use the original URL.RemotesThe name of one of the following can be used instead of a URL as `<repository>` argument:

- a remote in the Git configuration file: `$GIT_DIR/config`,

- a file in the `$GIT_DIR/remotes` directory, or

- a file in the `$GIT_DIR/branches` directory.

All of these also allow you to omit the refspec from the command line because they each contain a refspec which git will use by default.

### Named remote in configuration file

You can choose to provide the name of a remote which you had previously configured using git-remote[1], git-config[1] or even by a manual edit to the `$GIT_DIR/config` file. The URL of this remote will be used to access the repository. The refspec of this remote will be used by default when you do not provide a refspec on the command line. The entry in the config file would appear like this:

            [remote "<name>"]

                    url = <url>

                    pushurl = <pushurl>

                    push = <refspec>

                    fetch = <refspec>

The `<pushurl>` is used for pushes only. It is optional and defaults to `<url>`.

### Named file in `$GIT_DIR/remotes`

You can choose to provide the name of a file in `$GIT_DIR/remotes`. The URL in this file will be used to access the repository. The refspec in this file will be used as default when you do not provide a refspec on the command line. This file should have the following format:

            URL: one of the above URL format

            Push: <refspec>

            Pull: <refspec>

`Push:` lines are used by `git push` and `Pull:` lines are used by `git pull` and `git fetch`. Multiple `Push:` and `Pull:` lines may be specified for additional branch mappings.

### Named file in `$GIT_DIR/branches`

You can choose to provide the name of a file in `$GIT_DIR/branches`. The URL in this file will be used to access the repository. This file should have the following format:

            <url>#<head>

`<url>` is required; `#<head>` is optional.

Depending on the operation, git will use one of the following refspecs, if you don’t provide one on the command line. `<branch>` is the name of this file in `$GIT_DIR/branches` and `<head>` defaults to `master`.

git fetch uses:

            refs/heads/<head>:refs/heads/<branch>

git push uses:

            HEAD:refs/heads/<head>

## Output

The output of "git push" depends on the transport method used; this section describes the output when pushing over the Git protocol (either locally or via ssh).

The status of the push is output in tabular form, with each line representing the status of a single ref. Each line is of the form:

     <flag> <summary> <from> -> <to> (<reason>)

If --porcelain is used, then each line of the output is of the form:

     <flag> \t <from>:<to> \t <summary> (<reason>)

The status of up-to-date refs is shown only if --porcelain or --verbose option is used.

flag

A single character indicating the status of the ref:

(space)

for a successfully pushed fast-forward;

`+`

for a successful forced update;

`-`

for a successfully deleted ref;

`*`

for a successfully pushed new ref;

`!`

for a ref that was rejected or failed to push; and

`=`

for a ref that was up to date and did not need pushing.

summary

For a successfully pushed ref, the summary shows the old and new values of the ref in a form suitable for using as an argument to `git log` (this is `<old>..<new>` in most cases, and `<old>...<new>` for forced non-fast-forward updates).

For a failed update, more details are given:

rejected

Git did not try to send the ref at all, typically because it is not a fast-forward and you did not force the update.

remote rejected

The remote end refused the update. Usually caused by a hook on the remote side, or because the remote repository has one of the following safety options in effect: `receive.denyCurrentBranch` (for pushes to the checked out branch), `receive.denyNonFastForwards` (for forced non-fast-forward updates), `receive.denyDeletes` or `receive.denyDeleteCurrent`. See git-config[1].

remote failure

The remote end did not report the successful update of the ref, perhaps because of a temporary error on the remote side, a break in the network connection, or other transient error.

from

The name of the local ref being pushed, minus its `refs/<type>/` prefix. In the case of deletion, the name of the local ref is omitted.

to

The name of the remote ref being updated, minus its `refs/<type>/` prefix.

reason

A human-readable explanation. In the case of successfully pushed refs, no explanation is needed. For a failed ref, the reason for failure is described.

## Note about fast-forwards

When an update changes a branch (or more in general, a ref) that used to point at commit A to point at another commit B, it is called a fast-forward update if and only if B is a descendant of A.

In a fast-forward update from A to B, the set of commits that the original commit A built on top of is a subset of the commits the new commit B builds on top of. Hence, it does not lose any history.

In contrast, a non-fast-forward update will lose history. For example, suppose you and somebody else started at the same commit X, and you built a history leading to commit B while the other person built a history leading to commit A. The history looks like this:

          B     / ---X---A

Further suppose that the other person already pushed changes leading to A back to the original repository from which you two obtained the original commit X.

The push done by the other person updated the branch that used to point at commit X to point at commit A. It is a fast-forward.

But if you try to push, you will attempt to update the branch (that now points at A) with commit B. This does `not` fast-forward. If you did so, the changes introduced by commit A will be lost, because everybody will now start building on top of B.

The command by default does not allow an update that is not a fast-forward to prevent such loss of history.

If you do not want to lose your work (history from X to B) or the work by the other person (history from X to A), you would need to first fetch the history from the repository, create a history that contains changes done by both parties, and push the result back.

You can perform "git pull", resolve potential conflicts, and "git push" the result. A "git pull" will create a merge commit C between commits A and B.

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

Updating A with the resulting merge commit will fast-forward and your push will be accepted.

Alternatively, you can rebase your change between X and B on top of A, with "git pull --rebase", and push the result back. The rebase will create a new commit D that builds the change between X and B on top of A.

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

Again, updating A with this commit will fast-forward and your push will be accepted.

There is another common situation where you may encounter non-fast-forward rejection when you try to push, and it is possible even when you are pushing into a repository nobody else pushes into. After you push commit A yourself (in the first picture in this section), replace it with "git commit --amend" to produce commit B, and you try to push it out, because forgot that you have pushed A out already. In such a case, and only if you are certain that nobody in the meantime fetched your earlier commit A (and started building on top of it), you can run "git push --force" to overwrite it. In other words, "git push --force" is a method reserved for a case where you do mean to lose history.

## Examples

`git push`

Works like `git push <remote>`, where <remote> is the current branch’s remote (or `origin`, if no remote is configured for the current branch).

`git push origin`

Without additional configuration, pushes the current branch to the configured upstream (`remote.origin.merge` configuration variable) if it has the same name as the current branch, and errors out without pushing otherwise.

The default behavior of this command when no <refspec> is given can be configured by setting the `push` option of the remote, or the `push.default` configuration variable.

For example, to default to pushing only the current branch to `origin` use `git config remote.origin.push HEAD`. Any valid <refspec> (like the ones in the examples below) can be configured as the default for `git push origin`.

`git push origin :`

Push "matching" branches to `origin`. See <refspec> in the OPTIONS section above for a description of "matching" branches.

`git push origin master`

Find a ref that matches `master` in the source repository (most likely, it would find `refs/heads/master`), and update the same ref (e.g. `refs/heads/master`) in `origin` repository with it. If `master` did not exist remotely, it would be created.

`git push origin HEAD`

A handy way to push the current branch to the same name on the remote.

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

Use the source ref that matches `master` (e.g. `refs/heads/master`) to update the ref that matches `satellite/master` (most probably `refs/remotes/satellite/master`) in the `mothership` repository; do the same for `dev` and `satellite/dev`.

This is to emulate `git fetch` run on the `mothership` using `git push` that is run in the opposite direction in order to integrate the work done on `satellite`, and is often necessary when you can only make connection in one way (i.e. satellite can ssh into mothership but mothership cannot initiate connection to satellite because the latter is behind a firewall or does not run sshd).

After running this `git push` on the `satellite` machine, you would ssh into the `mothership` and run `git merge` there to complete the emulation of `git pull` that were run on `mothership` to pull changes made on `satellite`.

`git push origin HEAD:master`

Push the current branch to the remote ref matching `master` in the `origin` repository. This form is convenient to push the current branch without thinking about its local name.

`git push origin master:refs/heads/experimental`

Create the branch `experimental` in the `origin` repository by copying the current `master` branch. This form is only needed to create a new branch or tag in the remote repository when the local name and the remote name are different; otherwise, the ref name on its own will work.

`git push origin :experimental`

Find a ref that matches `experimental` in the `origin` repository (e.g. `refs/heads/experimental`), and delete it.

`git push origin +dev:master`

Update the origin repository’s master branch with the dev branch, allowing non-fast-forward updates. This can leave unreferenced commits dangling in the origin repository. Consider the following situation, where a fast-forward is not possible:

                o---o---o---A---B  origin/master

                         \

                          X---Y---Z  dev

The above command would change the origin repository to

                          A---B  (unnamed branch)                     /

                o---o---o---X---Y---Z  master

Commits A and B would no longer belong to a branch with a symbolic name, and so would be unreachable. As such, these commits would be removed by a `git gc` command on the origin repository.

## Security

The fetch and push protocols are not designed to prevent one side from stealing data from the other repository that was not intended to be shared. If you have private data that you need to protect from a malicious peer, your best option is to store it in another repository. This applies to both clients and servers. In particular, namespaces on a server are not effective for read access control; you should only grant read access to a namespace to clients that you would trust with read access to the entire repository.

The known attack vectors are as follows:

1. The victim sends "have" lines advertising the IDs of objects it has that are not explicitly intended to be shared but can be used to optimize the transfer if the peer also has them. The attacker chooses an object ID X to steal and sends a ref to X, but isn’t required to send the content of X because the victim already has it. Now the victim believes that the attacker has X, and it sends the content of X back to the attacker later. (This attack is most straightforward for a client to perform on a server, by creating a ref to X in the namespace the client has access to and then fetching it. The most likely way for a server to perform it on a client is to "merge" X into a public branch and hope that the user does additional work on this branch and pushes it back to the server without noticing the merge.)

1. As in #1, the attacker chooses an object ID X to steal. The victim sends an object Y that the attacker already has, and the attacker falsely claims to have X and not Y, so the victim sends Y as a delta against X. The delta reveals regions of X that are similar to Y to the attacker.