Git push 推送分支到远程仓库详解
git push
从将本地的分支版本上传到远程并合并。
在动手之前先理清 push 到底做了什么:它把本地某个分支上远程还没有的提交对象发送过去,然后请求远程仓库把对应的分支引用(ref)移动到新的提交上。关键点在于远程分支的移动必须是"快进"(fast-forward)的,也就是新提交必须包含远程当前提交的全部历史。一旦不满足这个条件,git 就会拒绝推送并提示 rejected ... non-fast-forward,这是在保护别人已经推上去的提交不被我们悄悄覆盖掉。
理解了这一层,后面各种参数和报错就都有了统一的解释。
- 命令格式
git push <远程主机名> <本地分支名>:<远程分支名>
冒号前后分别是源和目标,这个写法叫 refspec。它意味着本地分支名和远程分支名可以不一样,比如把本地的 dev 推到远程的 feature/login 完全合法。远程主机名一般就是 origin,它是 git clone 时自动创建的默认远程别名,可以用 git remote -v 查看当前仓库配了哪些远程地址。
如果本地分支名与远程分支名相同,则可以省略冒号:
git push <远程主机名> <本地分支名>
- 示例 以下命令将本地的
master分支推送到origin主机的master分支。
git push origin master
相等于:
git push origin master:master
- 如果本地版本与远程版本有差异,但又要强制推送可以使用
--force参数:
git push --force origin master
--force(简写 -f)跳过了前面说的快进检查,直接把远程分支的引用挪到我们本地的提交上。这意味着远程上那些我们本地没有的提交会从分支历史里消失,如果那些提交是同事刚推上来的,他的工作就丢了。所以这个参数要谨慎:共享分支(master、main、develop)上原则上不要用,只在自己独占的功能分支上用。
更安全的强制推送:--force-with-lease
多数需要 --force 的场景(rebase 之后、commit --amend 之后重推),其实都可以换成一个更安全的参数:
git push --force-with-lease origin feature/login
它的逻辑是:先检查远程分支当前的提交,是否和我们本地记录的远程分支状态(origin/feature/login)一致。一致说明从我们上次 fetch 到现在没有别人推过东西,覆盖是安全的,推送执行;不一致说明有人插了新提交,推送被拒绝。这样既能完成重写历史,又不会把别人的提交冲掉。
有一点要注意:如果在这之前跑过 git fetch,本地的远程跟踪分支就已经更新成别人的最新提交了,--force-with-lease 的检查会通过,保护就失效了。所以正确姿势是 rebase 完直接推,不要先 fetch 再强推。
推送新分支并建立跟踪关系
本地新建的分支第一次推送时,远程还不存在这个分支,加上 -u 让 git 顺便记下上下游对应关系:
git push -u origin feature/login
-u 是 --set-upstream 的简写。设置好之后,这个分支后续直接敲 git push 和 git pull 就行,不用每次都写远程名和分支名。查看已有的跟踪关系可以用:
git branch -vv
删除远程分支
回到 refspec 的写法上:冒号左边留空,表示"用空内容去覆盖远程分支",效果就是删除它。
git push origin :feature/login
现在更推荐用语义明确的 --delete,两条命令等价,后者不容易写错:
git push origin --delete feature/login
推送标签
标签默认不会随 git push 一起推送,需要显式指定。推送单个标签:
git push origin v1.0.0
把本地所有标签一次推上去:
git push origin --tags
如果希望在推送分支的同时带上那些指向被推送提交的标签,用 --follow-tags,它比 --tags 更克制,不会把无关的本地标签一起推上去:
git push --follow-tags origin master
几个常用参数
# 演练:完整走一遍流程但不真的推送,用来确认将要发生什么
git push --dry-run origin master
# 推送所有本地分支
git push --all origin
# 跳过 pre-push 钩子(比如钩子里的测试跑得太慢时临时用)
git push --no-verify origin master
--dry-run 在执行有风险的操作前特别有用,尤其是配合 --force 或 --delete 时,先加上它确认一遍目标对不对。
常见报错怎么处理
rejected / non-fast-forward:远程有我们本地没有的提交。正确做法是先把远程的改动整合到本地再推,而不是直接强推:
git pull --rebase origin master
git push origin master
--rebase 会把我们的本地提交挪到远程最新提交之后,历史是一条直线,比默认的 merge 方式产生的历史更干净。整合过程中如果有冲突,解决完 git rebase --continue 即可。
src refspec xxx does not match any:本地根本没有这个分支名,通常是拼错了,或者是在一个还没有任何提交的新仓库里推送。用 git branch 确认分支名。
Updates were rejected because the remote contains work that you do not have locally:和第一种是同一类问题,多见于本地初始化仓库后关联到一个已有内容的远程仓库(远程有 README 而本地没有)。同样用 git pull --rebase 先整合。
Permission denied (publickey):这是认证问题不是 push 逻辑问题,说明 SSH key 没配好或没加到平台账号上。用 ssh -T git@github.com 单独验证连通性。

还没有留言,来发表第一条吧~