Git 推送映射配置
remote.<name>.push 用于给某个 remote 显式声明一条"本地分支 → 远端分支"的推送映射(push refspec)。一旦配置了它,裸git push 会忽略 push.default,改为始终按这条固定映射推送,与当前所在分支无关
语法
git config remote.<name>.push <src>:<dst>
<name>:remote 名称,如origin<src>:本地 ref,通常写作refs/heads/<本地分支名>,也可以用HEAD表示"当前所在分支"<dst>:远端 ref,通常写作refs/heads/<远端分支名>:是分隔符,含义是"把<src>推送到<dst>"
配置之后,裸 git push(不带任何参数)在语义上等价于:
git push <name> <src>:<dst>
落地位置:.git/config
git config remote.<name>.push <src>:<dst> 本质上只是在修改仓库的 .git/config 文件(加 --global 则写入 ~/.gitconfig),在对应 remote 的配置段里追加一行 push = <src>:<dst>。例如原本的 .git/config 是:
[remote "origin"]
url = git@github.com:acme/webapp.git
fetch = +refs/heads/*:refs/remotes/origin/*
执行:
git config remote.origin.push refs/heads/dev:refs/heads/dev
后会变成:
[remote "origin"]
url = git@github.com:acme/webapp.git
fetch = +refs/heads/*:refs/remotes/origin/*
push = refs/heads/dev:refs/heads/dev
也可以跳过 git config 命令,直接用编辑器打开 .git/config 手动加上 push = ... 这一行,效果完全一样。删除时同理,把这一行删掉,或者执行 git config --unset remote.origin.push。下面每个场景都会同时给出对应命令和它在 .git/config 中的落地内容。
常见写法对照
| 配置 | 含义 |
|---|---|
remote.origin.push refs/heads/dev:refs/heads/dev | 裸 git push 始终推送本地 dev 到远端 dev |
remote.origin.push refs/heads/master:refs/heads/master | 裸 git push 始终推送本地 master 到远端 master,与当前所在分支无关 |
remote.origin.push refs/heads/*:refs/heads/* | 裸 git push 推送所有本地分支到远端同名分支(类似旧版 push.default=matching) |
remote.origin.push HEAD:refs/heads/release | 不管当前在哪个分支,都把它推到远端固定的 release 分支 |
| 不配置 | 遵循 push.default(现代 Git 默认 simple,即推当前分支到同名远端分支) |
配置案例
场景一:本地任意分支统一发布到固定分支
某些团队希望"不管在哪个本地分支上开发,裸 git push 都统一推到远端的 staging 分支",可以这样配置:
git config remote.origin.push HEAD:refs/heads/staging
.git/config 变化:
[remote "origin"]
url = git@github.com:acme/webapp.git
fetch = +refs/heads/*:refs/remotes/origin/*
push = HEAD:refs/heads/staging
效果:
git checkout feature-x
git push # 实际执行:本地 feature-x → 远端 staging
场景二:把裸 git push 锁定为固定分支
假设仓库地址为 git@github.com:acme/webapp.git,团队约定只能通过固定流程发布 master,希望即使有人在其他分支下手滑执行了裸
git push,也不会误推到错误的远端分支,可以这样配置:
git config remote.origin.push refs/heads/master:refs/heads/master
.git/config 变化:
[remote "origin"]
url = git@github.com:acme/webapp.git
fetch = +refs/heads/*:refs/remotes/origin/*
push = refs/heads/master:refs/heads/master
配置后,无论当前在哪个分支,裸 git push 都只会尝试把本地 master 推到远端 master:
git checkout dev
git push --dry-run
To github.com:acme/webapp.git
! [rejected] master -> master (non-fast-forward)
可以看到即便当前在 dev 分支,实际尝试推送的仍是 master -> master(上例中因为本地 master 落后于远端而被拒绝)。如果这不是预期行为,说明当前不需要这条固定映射,直接移除即可:
git config --unset remote.origin.push
这条配置会让裸 git push 的行为脱离"推当前分支"的直觉——不管在哪个分支下执行,结果都只跟 master 有关。团队协作时容易造成困惑(比如以为在推 dev,实际什么都没推上去或推错了分支),务必在仓库 README 或团队文档中注明;如果只是偶尔需要把某个分支推到远端,用 git push origin <branch> 显式指定即可绕开这条固定映射,不需要专门为此改配置。
场景三:配合多个 remote 使用
一个仓库可以同时配置多个 remote,比如常见的 fork 协作模式:
git remote add origin git@github.com:my-name/webapp.git
git remote add upstream git@github.com:acme/webapp.git
remote.<name>.push 是按 remote 独立配置的,不同 remote 互不影响。比如只想在推送到 upstream 时固定映射到 main,而
origin 保持默认行为:
git config remote.upstream.push refs/heads/main:refs/heads/main
.git/config 会有两个独立的 [remote ...] 段,只有 upstream 那段带 push:
[remote "origin"]
url = git@github.com:my-name/webapp.git
fetch = +refs/heads/*:refs/remotes/origin/*
[remote "upstream"]
url = git@github.com:acme/webapp.git
fetch = +refs/heads/*:refs/remotes/upstream/*
push = refs/heads/main:refs/heads/main
此时:
git push origin # 遵循 push.default,推当前分支到 origin 同名分支
git push upstream # 忽略当前分支,固定推送 main -> main
再比如一个仓库同时对接 GitHub 和 GitLab 两个远端做双向备份:
git remote add origin git@github.com:acme/webapp.git
git remote add mirror git@gitlab.com:acme/webapp.git
如果希望裸 git push 只推送到 origin(默认行为即可),备份仓库通过显式命令单独同步,则不需要给 mirror 配置
remote.mirror.push,直接用:
git push mirror HEAD:refs/heads/dev
即可按需推送,不影响 origin 的默认推送行为。
remote.<name>.push 可以配置多条(多次执行 git config --add remote.<name>.push <src>:<dst>),此时裸 git push
会依次按所有映射规则推送,适合"一次裸 push 同时更新多个远端分支"的场景。落到 .git/config 里就是同一个 remote 段下出现多行 push:
[remote "origin"]
url = git@github.com:acme/webapp.git
fetch = +refs/heads/*:refs/remotes/origin/*
push = refs/heads/dev:refs/heads/dev
push = refs/heads/dev:refs/heads/backup-dev