$ git push [<repository> [<refspec>...]]
Updates remote references along with their history.
<refspec>
tells git
which remote reference to update with which local one.
$ git push origin ba:bb
pushes the local branch ba
to the branch bb
at origin
. If the remote branch doesn't exist it gets created.
If :<dst>
is not specified, then remote.<name>.push
is used as a refmap. I.e. remote.<name>.push
determines where to push a given reference.
If remote.origin.push
is +refs/heads/*:refs/heads/*
, then
$ git push origin ba
is equivalent to git push origin +ba:refs/heads/ba
and (force-)pushes the local branch ba
to the branch ba
at origin
.
If remote.origin.push
is refs/heads/ba:refs/heads/bb
, then the command is equivalent to git push origin ba:refs/heads/bb
and pushes the local branch ba
to the branch bb
at origin
.
If remote.<name>.push
is not set and push.default
is upstream
, then it (git push <repository> <refspec>
without :<dst>
) pushes the local branch to its upstream branch. If push.default
is not upstream
, to its matching (the same name) branch.
:
is a refspec that tells git
to update matching branches. I.e. for each local branch l
, if there's a remote branch r
that has the same name, then push l
to r
:
$ git push origin :
If <refspec>
is not passed, then remote.<name>.push
is used instead (git push origin
is equivalent to git push origin <remote.origin.push>
).
If remote.origin.push
is ba
, then
$ git push origin
is equivalent to git push origin ba
.
If <refspec>
is not passed and remote.<name>.push
is not set, then see push.default
.
The relevant docs:
When the command line does not specify what to push with
<refspec>...
arguments or--all
,--mirror
,--tags
options, the command finds the default<refspec>
by consultingremote.*.push
configuration, and if it is not found, honorspush.default
configuration to decide what to push (See git-config[1] for the meaning ofpush.default
).
https://git-scm.com/docs/git-push#_description
If
git push [<repository>]
without any<refspec>
argument is set to update some ref at the destination with<src>
withremote.<repository>.push
configuration variable,:<dst>
part can be omitted—such a push will update a ref that<src>
normally updates without any<refspec>
on the command line. Otherwise, missing:<dst>
means to update the same ref as the<src>
.The special refspec
:
(or+:
to allow non-fast-forward updates) directs Git to push "matching" branches: for every branch that exists on the local side, the remote side is updated if a branch of the same name already exists on the remote side.
https://git-scm.com/docs/git-push#Documentation/git-push.txt-ltrefspecgt82308203
git push origin
Without additional configuration, pushes the current branch to the configured upstream (
branch.<name>.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 thepush.default
configuration variable.For example, to default to pushing only the current branch to
origin
usegit config remote.origin.push HEAD
. Any valid<refspec>
(like the ones in the examples below) can be configured as the default forgit 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 findrefs/heads/master
), and update the same ref (e.g.refs/heads/master
) inorigin
repository with it. Ifmaster
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 matchessatellite/master
(most probablyrefs/remotes/satellite/master
) in themothership
repository; do the same fordev
andsatellite/dev
.See the section describing
<refspec>...
above for a discussion of the matching semantics.This is to emulate
git fetch
run on the mothership usinggit push
that is run in the opposite direction in order to integrate the work done onsatellite
, and is often necessary when you can only make connection in one way (i.e.satellite
can ssh intomothership
butmothership
cannot initiate connection tosatellite
because the latter is behind a firewall or does not runsshd
).After running this
git push
on the satellite machine, you would ssh into the mothership and rungit merge
there to complete the emulation ofgit pull
that were run onmothership
to pull changes made onsatellite
.git push origin HEAD:master
Push the current branch to the remote ref matching
master
in theorigin
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 theorigin
repository by copying the currentmaster
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 +dev:master
Update the
origin
repository’smaster
branch with thedev
branch, allowing non-fast-forward updates. This can leave unreferenced commits dangling in theorigin
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 toA---B (unnamed branch) / o---o---o---X---Y---Z master
Commits
A
andB
would no longer belong to a branch with a symbolic name, and so would be unreachable. As such, these commits would be removed by agit gc
command on theorigin
repository.
https://git-scm.com/docs/git-push#_examples
remote.<name>.push
The default set of "refspec" for git-push[1]. See git-push[1].
https://git-scm.com/docs/git-config#Documentation/git-config.txt-remoteltnamegtpush
a.bats
:
strict() { set -euo pipefail; shopt -s inherit_errexit; "$@"; }
setup() {
[ "$BATS_LIB_PATH" = /usr/lib/bats ] && BATS_LIB_PATH=$HOME/.bats/lib:$BATS_LIB_PATH
bats_load_library bats-support
bats_load_library bats-assert
strict
}
# the state of the cloned repository (1 commit, 1 local branch ba)
# A (HEAD -> ba, origin/ba)
@test "pushes to the specified branch" {
start_cloned_repo
git commit --allow-empty -m B
git push origin ba:ba
assert_equal_sha origin/ba ba
}
@test "the remote branch gets created when not exists" {
start_cloned_repo
git commit --allow-empty -m B
git push origin ba:bb
assert_branch refs/remotes/origin/bb
}
@test "remote.<name>.push is used as a refmap when no :<dst>" {
start_cloned_repo
git config remote.origin.push refs/heads/ba:bb
git commit --allow-empty -m B
git push origin ba
assert_equal_sha origin/bb ba
}
@test "allows non-fast-forwards when there's a + in remote.<name>.push" {
start_cloned_repo
git config remote.origin.push +refs/heads/ba:ba
git commit --allow-empty --amend -m A2
git push origin ba
assert_equal_sha origin/ba ba
}
@test "but <branch> without refs/heads doesn't match the branch" {
start_cloned_repo
git config remote.origin.push ba:bb
git commit --allow-empty -m B
git push origin ba
refute_branch refs/remotes/origin/bb
}
@test "pushes to the upstream branch when remote.<name>.push is not set and push.default = upstream" {
start_cloned_repo
git config push.default upstream
git push origin ba:bb; git branch -u origin/bb
git commit --allow-empty -m B
git push origin ba
assert_equal_sha origin/bb ba
}
@test "pushes to the matching branch when remote.<name>.push is not set and push.default != upstream" {
start_cloned_repo
git push origin ba:bb; git branch -u origin/bb
git commit --allow-empty -m B
git push origin ba
assert_equal_sha origin/ba ba
}
@test "the remote branch gets created when not exists (no :<dst>)" {
start_cloned_repo
git checkout -b bb
git commit --allow-empty -m B
git push origin bb
assert_branch refs/remotes/origin/bb
}
@test ": pushes when the matching branch exists" {
start_cloned_repo
git commit --allow-empty -m B
git push origin :
assert_equal_sha origin/ba ba
}
@test ": doesn't push when no matching branch" {
start_cloned_repo
git checkout -b bb
git commit --allow-empty -m B
git push origin :
refute_branch refs/remotes/origin/bb
}
@test ": pushes other branches" {
start_cloned_repo
git commit --allow-empty -m B
git checkout -b bb
git push origin :
assert_equal_sha origin/ba ba
}
@test "remote.<name>.push is used when no <refspec>" {
start_cloned_repo
git config remote.origin.push ba:bb
git commit --allow-empty -m B
git push origin
assert_equal_sha origin/bb ba
}
@test "push.default doesn't affect it when remote.<name>.push is set" {
start_cloned_repo
git config push.default upstream
git config remote.origin.push ba
git push origin ba:bb; git branch -u origin/bb
git commit --allow-empty -m B
git push origin
assert_equal_sha origin/ba ba
}
assert_equal_sha() {
assert_equal "`git rev-parse "$1"`" "`git rev-parse "$2"`"
}
assert_not_equal_sha() {
! assert_equal_sha "$1" "$2"
}
assert_branch() {
git show-ref --verify --quiet "$1"
}
refute_branch() {
run git show-ref --verify --quiet "$1"
assert_equal "$status" 1
}
start_cloned_repo() {
(mkrepo)
cd "$BATS_TEST_TMPDIR"
git clone --bare a a.git
git clone a.git b
cd b
git config user.email [email protected]
git config user.name "Your Name"
}
mkrepo() {
cd "$BATS_TEST_TMPDIR"
mkdir a
(cd a
git init
git branch -m ba
git config user.email [email protected]
git config user.name "Your Name"
git commit --allow-empty -m A)
}
ml() { for l; do printf '%s\n' "$l"; done; }
$ docker run --rm -itv "$PWD":/app -w /app alpine:3.21
/ # apk add git bash ncurses
/ # git clone https://github.com/bats-core/bats-core ~/.bats
/ # git clone https://github.com/bats-core/bats-support ~/.bats/lib/bats-support
/ # git clone https://github.com/bats-core/bats-assert ~/.bats/lib/bats-assert
/ # ~/.bats/bin/bats a.bats