Setup and Config
Getting and Creating Projects
Basic Snapshotting
Branching and Merging
Sharing and Updating Projects
Inspection and Comparison
Patching
Debugging
External Systems
Server Admin
Guides
- gitattributes
- Command-line interface conventions
- Everyday Git
- Frequently Asked Questions (FAQ)
- Glossary
- Hooks
- gitignore
- gitmodules
- Revisions
- Submodules
- Tutorial
- Workflows
- All guides...
Administration
Plumbing Commands
-
2.52.0
2025-11-17
- 2.48.1 → 2.51.2 no changes
-
2.48.0
2025-01-10
- 2.45.1 → 2.47.3 no changes
-
2.45.0
2024-04-29
- 2.44.1 → 2.44.4 no changes
-
2.44.0
2024-02-23
- 2.43.1 → 2.43.7 no changes
-
2.43.0
2023-11-20
- 2.42.2 → 2.42.4 no changes
-
2.42.1
2023-11-02
-
2.42.0
2023-08-21
- 2.41.1 → 2.41.3 no changes
-
2.41.0
2023-06-01
- 2.40.1 → 2.40.4 no changes
-
2.40.0
2023-03-12
- 2.39.1 → 2.39.5 no changes
-
2.39.0
2022-12-12
- 2.38.1 → 2.38.5 no changes
-
2.38.0
2022-10-02
- 2.35.1 → 2.37.7 no changes
-
2.35.0
2022-01-24
- 2.33.1 → 2.34.8 no changes
-
2.33.0
2021-08-16
- 2.32.1 → 2.32.7 no changes
-
2.32.0
2021-06-06
- 2.30.1 → 2.31.8 no changes
-
2.30.0
2020-12-27
- 2.25.1 → 2.29.3 no changes
-
2.25.0
2020-01-13
- 2.23.1 → 2.24.4 no changes
-
2.23.0
2019-08-16
- 2.22.1 → 2.22.5 no changes
-
2.22.0
2019-06-07
- 2.21.1 → 2.21.4 no changes
-
2.21.0
2019-02-24
- 2.20.1 → 2.20.5 no changes
-
2.20.0
2018-12-09
- 2.18.1 → 2.19.6 no changes
-
2.18.0
2018-06-21
- 2.17.0 → 2.17.6 no changes
-
2.16.6
2019-12-06
-
2.15.4
2019-12-06
- 2.14.6 no changes
-
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 no changes
-
2.4.12
2017-05-05
-
2.3.10
2015-09-28
-
2.2.3
2015-09-04
- 2.1.4 no changes
-
2.0.5
2014-12-17
概述
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] [<仓库> [<引用规范>…]]
描述
Updates one or more branches, tags, or other references in a remote repository from your local repository, and sends all necessary data that isn’t already on the remote.
The simplest way to push is git push <remote> <branch>. git push origin main will push the local main branch to the main branch on the remote named origin.
The <repository> argument defaults to the upstream for the current branch, or origin if there’s no configured upstream.
To decide which branches, tags, or other refs to push, Git uses (in order of precedence):
-
The <refspec> argument(s) (for example
mainingitpushoriginmain) or the--all,--mirror, or--tagsoptions -
The
remote.*.pushconfiguration for the repository being pushed to -
The
push.defaultconfiguration. The default ispush.default=simple, which will push to a branch with the same name as the current branch. See the CONFIGURATION section below for more onpush.default.
git push may fail if you haven’t set an upstream for the current branch, depending on what push.default is set to. See the UPSTREAM BRANCHES section below for more on how to set and use upstreams.
通过设置 “钩子”,你可以在每次推送到一个仓库时,让它发生有趣的事情。 见 git-receive-pack[1] 的文档。
选项
- <仓库>
-
作为推送操作的目的地的 “远程” 仓库。 这个参数可以是一个网址(见下面 GIT 地址 一节),也可以是一个远程库的名称(见下面 远程仓库 一节)。
- <引用规范>…
-
Specify what destination ref to update with what source object.
The format for a refspec is [+]<src>[:<dst>], for example
main,main:other, orHEAD^:refs/heads/main.The <src> is often the name of the local branch to push, but it can be any arbitrary "SHA-1 expression" (see gitrevisions[7]).
The <dst> determines what ref to update on the remote side. It must be the name of a branch, tag, or other ref, not an arbitrary expression.
The
+is optional and does the same thing as--force.You can write a refspec using the fully expanded form (for example
refs/heads/main:refs/heads/main) which specifies the exact source and destination, or with a shorter form (for examplemainormain:other). Here are the rules for how refspecs are expanded, as well as various other special refspec forms:-
<src> without a
:<dst> means to update the same ref as the <src>, unless theremote.<repository>.pushconfiguration specifies a different <dst>. For example, ifmainis a branch, then the refspecmainexpands tomain:refs/heads/main. -
If <dst> unambiguously refers to a ref on the <repository> remote, then expand it to that ref. For example, if
v1.0is a tag on the remote, thenHEAD:v1.0expands toHEAD:refs/tags/v1.0. -
If <src> resolves to a ref starting with
refs/heads/orrefs/tags/, then prepend that to <dst>. For example, ifmainis a branch, thenmain:otherexpands tomain:refs/heads/other -
特殊的引用规范
:(或`+:`以允许非快进式更新)指示 Git 推送“匹配”的分支:对于每一个存在于本地的分支,如果远程仓库已经有一个同名的分支存在,则远程仓库会被更新。 -
<src> may contain a * to indicate a simple pattern match. This works like a glob that matches any ref matching the pattern. There must be only one * in both the <src> and <dst>. It will map refs to the destination by replacing the * with the contents matched from the source. For example,
refs/heads/*:refs/heads/*will push all branches. -
A refspec starting with
^is a negative refspec. This specifies refs to exclude. A ref will be considered to match if it matches at least one positive refspec, and does not match any negative refspec. Negative refspecs can be pattern refspecs. They must only contain a <src>. Fully spelled out hex object names are also not supported. For example,gitpushoriginrefs/heads/*'^refs/heads/dev-*'will push all branches except for those starting withdev- -
If <src> is empty, it deletes the <dst> ref from the remote repository. For example,
gitpushorigin:devwill delete thedevbranch. -
tag<tag> expands torefs/tags/<tag>:refs/tags/<tag>. This is technically a special syntax forgitpushand not a refspec, since ingitpushorigintagv1.0the argumentstagandv1.0are separate. -
If the refspec can’t be expanded unambiguously, error out with an error indicating what was tried, and depending on the
advice.pushUnqualifiedRefnameconfiguration (see git-config[1]) suggest what refs/ namespace you may have wanted to push to.
-
Not all updates are allowed: see PUSH RULES below for the details.
- --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。 - --signed
- --no-signed
- --signed=(true|false|if-asked)
-
对推送请求进行 GPG 签名,以更新接收方的引用,使其能够被钩子检查和/或被记录下来。 如果指定
false或--no-signed,将不尝试签名。 如果指定true或--signed,且服务器不支持签名推送,推送将失败。 如果设置为if-asked,仅当服务器支持签名推送时才签名。 如果实际调用gpg--sign失败,推送也将失败。 关于接收端的细节,见 git-receive-pack[1]。 - --atomic
- --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 目录下的程序时,有时会很有用。
- --force-with-lease
- --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 的gitfetchorigin。与
--force相比,它提供的保护是确保你的工作不基于后续的变化,但如果有后台进程在后台更新引用,这一点就很容易被破坏。除了远程跟踪信息外,我们没有任何你期望看到并愿意去破解可以作为启发式引用的东西。如果你的编辑器或其他系统在后台为你运行`git fetch`,减轻这种情况的方法是简单地设置另一个远程:
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 # 从远程仓库更新 '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
-
Usually,
gitpushwill refuse to update a branch that is not an ancestor of the commit being pushed.This flag disables that check, the other safety checks in PUSH RULES below, and the checks in --force-with-lease. It can cause the remote repository to lose commits; use it with care.
注意,
--force适用于所有被推送的引用,因此在push.default设置为matching的情况下使用它,或者在remote.*.push配置了多个推送目的地的情况下,可能会覆盖当前分支以外的引用(包括严格落后于其远程对应的本地引用)。 要强制推送到一个分支,请在推送的引用规范前面使用+(例如gitpushorigin+master,强制推送到master分支)。详情见上面的 < 引用规范 >... 部分。 - --force-if-includes
- --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。
- --thin
- --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"。
- --verify
- --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:// 地址)不进行身份验证,在不安全的网络上应谨慎使用。
以下是上述几个传输协议的格式:
-
ssh://[<user>@]<host>[:<port>]/<path-to-git-repo> -
git://<主机地址>[:<端口>]/<Git 仓库路径>
-
http[s]://<主机地址>[:<端口>]/<Git 仓库路径>
-
ftp[s]://<主机地址>[:<端口>]/<Git 仓库路径>
ssh 协议也可以使用类似 scp 的语法:
-
[<用户名>@]<主机地址>:/<Git 仓库路径>
仅当第一个冒号之前没有斜杠时才能识别此语法。这有助于区分包含冒号的本地路径。例如,可以将本地路径 foo:bar 指定为绝对路径,或者将 ./foo:bar 指定为绝对路径,以避免被误识别为 ssh url。
ssh 和 git 协议还支持 ~<用户名> 扩展:
-
ssh://[<user>@]<host>[:<port>]/~<user>/<path-to-git-repo> -
git://<主机地址>[:<端口>]/~<用户名>/<Git 仓库路径>
-
[<用户名>@]<主机地址>:~<用户名>/<Git 仓库路径>
对于本地仓库(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-<传输方式> 远程帮助程序(如果存在)。要显式请求远程帮助程序,可以使用以下语法:
-
<传送>
::<地址>
其中,<地址> 可以是路径,服务器与路径,也可以是可被调用的特定远程帮助程序识别的类似于网页地址的任意字符串。有关详细信息,请参阅 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 pull 和 git 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 选项时,才会显示最新引用的状态。
- 标志
-
表示引用状态的单个字符:
- 概述
-
对于一个成功获取的引用,摘要以适合作为
gitlog参数的形式显示该引用的新旧值(在大多数情况下是 <旧>..<新>,对于强制非快速合并是 <旧>...<新>)。对于失败的更新,会给出更多的细节:
- 已拒绝
-
Git 根本没有尝试发送引用,典型的原因是它不是快速合并并且你没有强制更新。
- 远程拒绝
-
远程仓库拒绝更新。 通常是由远程仓库的钩子引起的,或者是因为远程仓库有以下安全选项:
receive.denyCurrentBranch(用于推送到已检出的分支),receive.denyNonFastForwards(用于强制非快进更新),receive.denyDeletes或者receive.denyDeleteCurrent。 见 git-config[1]。 - 远程故障
-
远程端没有报告引用的成功更新,可能是因为远程端的临时错误,网络连接中断,或其他瞬时错误。
- 起始
-
被推送的本地引用的名称,减去其 refs/< 类型 >/ 前缀。在删除的情况下,本地引用的名称被省略。
- 结束
-
被更新的本地引用的名称,去掉其 refs/< 类型 >/ 前缀。
- 原因
-
一个人类可读的解释。在成功推送引用的情况下,不需要解释。对于操作失败的引用,要描述失败的原因。
PUSH RULES
As a safety feature, the git push command only allows certain kinds of updates to prevent you from accidentally losing data on the remote.
Because branches and tags are intended to be used differently, the safety rules for pushing to a branch are different from the rules for pushing to a tag. In the following rules "update" means any modifications except deletions and creations. Deletions and creations are always allowed, except when forbidden by configuration or hooks.
-
If the push destination is a branch (
refs/heads/*): only fast-forward updates are allowed, which means the destination must be an ancestor of the source commit. The source must be a commit. -
If the push destination is a tag (
refs/tags/*): all updates will be rejected. The source can be any object. -
If the push destination is not a branch or tag:
-
If the source is a tree or blob object, any updates will be rejected
-
If the source is a tag or commit object, any fast-forward update is allowed, even in cases where what’s being fast-forwarded is not a commit, but a tag object which happens to point to a new commit which is a fast-forward of the commit the last tag (or commit) it’s replacing. Replacing a tag with an entirely different tag is also allowed, if it points to the same commit, as well as pushing a peeled tag, i.e. pushing the commit that existing tag object points to, or a new tag object which an existing commit points to.
-
You can override these rules by passing --force or by adding the optional leading + to a refspec. The only exceptions are that no amount of forcing will make a branch accept a non-commit object, and forcing won’t make the remote repository accept a push that it’s configured to deny.
Hooks and configuration can also override or amend these rules, see e.g. receive.denyNonFastForwards and receive.denyDeletes in git-config[1] and pre-receive and update in githooks[5].
关于快速合并的说明
当一个更新将原来指向提交 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 -
像`git push < 远端 >那样工作,其中 < 远端 > 是当前分支的远程仓库(或者`origin,如果没有为当前分支配置远程仓库)。
-
gitpushorigin -
不需要额外配置,如果它与当前分支同名,并且错误输出而不推送其他分支,则将其推送到配置过的上游仓库(
branch.<分支名>.merge配置变量)。当没有给出< 引用规范 >时,该命令的默认行为可以通过设置远程仓库的
push选项或 `push.default`配置变量来配置。例如,要默认只将当前分支推送到
origin,使用gitconfigremote.origin.pushHEAD。 任何有效的< 引用规范 >(比如下面例子中的那些)都可以被配置为gitpushorigin的默认值。 -
gitpushorigin: -
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`做同样的操作。关于匹配语义的讨论,请参见上面描述 <引用规范>... 的部分。
这是为了模拟在`母舰` 上运行的
gitfetch,使用gitpush以相反的方向运行,以便整合 卫星 上完成的工作,当你只能以一种方式进行连接时(即卫星可以ssh到母舰,但母舰不能启动与卫星的连接,因为后者在防火墙后面或不运行 sshd),这往往是必要的。在 卫星 机器上运行这个
gitpush后,你将 ssh 进入 母舰 并在那里运行gitmerge,以完成对 母舰 上运行的gitpull的模拟,以拉取 卫星 上的修改。 -
gitpushoriginHEAD:master -
推送当前分支到远程引用匹配
master的origin仓库中。这种形式可以方便地推送当前分支,而不必考虑其本地名称。 -
gitpushoriginmaster:refs/heads/experimental -
通过复制当前的
master分支,在origin仓库创建experimental分支。 只有在本地名称和远程名称不同的情况下,在远程仓库中创建新的分支或标签时才需要这个表单;否则,参考名称本身就可以了。 -
gitpushorigin:experimental -
在
origin仓库(例如`refs/heads/experimental`)中找到一个与experimental相匹配的引用,并将其删除。 -
gitpushorigin+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”命令删除。
安全
获取和推送协议并不是为了防止一方从另一个版本库窃取不打算共享的数据。如果你有需要保护的私人数据不被恶意的同行窃取,你最好的选择是把它存储在另一个资源库中。这同时适用于客户端和服务器。特别是,服务器上的命名空间对于读取访问控制是无效的;你应该只将命名空间的读取访问权授予那些你信任的可以读取整个版本库的客户。
已知的攻击媒介如下:
-
受害者发送 "have" 行,宣传它所拥有的对象的 ID,这些对象并没有明确地打算被共享,但如果对等体也有这些对象,就可以用来优化传输。攻击者选择了一个对象 ID X 来窃取,并向 X 发送了一个引用,但不需要发送 X 的内容,因为受害者已经拥有它。现在,受害者认为攻击者拥有 X,它稍后将 X 的内容发回给攻击者。(这种攻击对于客户端来说在服务器上执行是最直接的,通过在客户端可以访问的命名空间中创建一个 X 的引用,然后获取它。服务器最可能在客户端执行的方式是将 X "合并" 到一个公共分支,并希望用户在这个分支上做额外的工作,然后在没有注意到合并的情况下将其推回给服务器。)
-
和 #1 一样,攻击者选择了一个对象 ID X 来偷窃。受害者发送了一个攻击者已经拥有的对象 Y,攻击者谎称拥有 X 而没有 Y,因此受害者发送 Y 作为对 X 的d elta,delta 向攻击者显示了 X 中与 Y 相似的区域。
配置
本节中这一行以下的内容都是从 git-config[1] 文档中摘录的。其内容与那里的内容相同:
|
Warning
|
Missing See original version for this content. |
GIT
属于 git[1] 文档