Whenever I’d issue a git push
without specifying the remote repository or branch, expecting it to just pick up the default remote repository and push to the remote branch with the same name as the current local branch, I get the following message:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
PS> git push warning: push.default is unset; its implicit value is changing in Git 2.0 from 'matching' to 'simple'. To squelch this message and maintain the current behavior after the default changes, use: git config --global push.default matching To squelch this message and adopt the new behavior now, use: git config --global push.default simple See 'git help config' and search for 'push.default' for further information. (the 'simple' mode was introduced in Git 1.7.11. Use the similar mode 'current' instead of 'simple' if you sometimes use older versions of Git) |
Usually I’d ignore the message and go ahead anyways, but today I decided to explore further.
So, first up: what are these two behavior options matching
and simple
? From the git-config
manpage I understand there are five such options:
nothing
: If you don’t specify the remote, do nothing.
123PS> git config --global push.default nothingPS> git pushfatal: You didn't specify any refspecs to push, and push.default is "nothing".current
: If you don’t specify the remote, push the current branch to a branch with the same name on the remote end. If a branch of the same name doesn’t exist at the remote end, create one.
123PS> git config --global push.default currentPS> git pushEverything up-to-dateupstream
: If you don’t specify the remote, push the current branch to the branch you have designated as upstream. Note: this is similar tocurrent
just that the remote branch isn’t chosen based on one with the same name, it is chosen based on what you have set as the upstream branch. This is useful when the remote branch name is not the same as the local branch name.How do you set a branch as upstream? Use
git branch --set-upstream-to
. (Note:--set-upstream
too works but is deprecated. You may also use-u
instead of--set-upstream-to
).Here’s an example. I have three branches for my repository: 0.1, master, and testing. All three branches exist both locally and remotely.
12345678910111213141516171819# view the local and remote branchesPS> git remote show origin* remote originFetch URL: git@github.com:rakheshster/PS-AppMgmt.gitPush URL: git@github.com:rakheshster/PS-AppMgmt.gitHEAD branch (remote HEAD is ambiguous, may be one of the following):0.1masterRemote branches:0.1 trackedmaster trackedtesting trackedLocal branch configured for 'git pull':master merges with remote masterLocal refs configured for 'git push':0.1 pushes to 0.1 (up to date)master pushes to master (up to date)testing pushes to testing (up to date)Next I change the push policy to
upstream
and …1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465PS> git config --global push.default upstream# create a new branch called testing2 and switch to itPS> git branch testing2PS> git checkout testing2Switched to branch 'testing2'PS> git branch0.1mastertesting* testing2# try pushing this branch to the remote end - note that it failsPS> git pushfatal: The current branch testing2 has no upstream branch.To push the current branch and set the remote as upstream, usegit push --set-upstream origin testing2# if the remote branch name is explicitly specified, a new branch is created and pushed toPS> git push origin testing2Total 0 (delta 0), reused 0 (delta 0)To git@github.com:rakheshster/PS-AppMgmt.git* [new branch] testing2 -> testing2# delete the remote branch so I can try one more thingPS> git push origin :testing2To git@github.com:rakheshster/PS-AppMgmt.git- [deleted] testing2# set the upstream via git branch - note that it fails as the remote branch does not existPS> git branch --set-upstream-to origin/testing2error: the requested upstream branch 'origin/testing2' does not existhint:hint: If you are planning on basing your work on an upstreamhint: branch that already exists at the remote, you may need tohint: run "git fetch" to retrieve it.hint:hint: If you are planning to push out a new local branch thathint: will track its remote counterpart, you may want to usehint: "git push -u" to set the upstream config as you push.# let's create a new branch called nottesting2 and set that as the upstreamPS> git checkout -b nottesting2Switched to a new branch 'nottesting2'PS> git push origin nottesting2Total 0 (delta 0), reused 0 (delta 0)To git@github.com:rakheshster/PS-AppMgmt.git* [new branch] nottesting2 -> nottesting2# now switch to testing2 and set nottesting2 as its upstreamPS> git branch -u origin/nottesting2Branch testing2 set up to track remote branch nottesting2 from origin.# and do a git push with no remote specified and notice how it works without a fuss!PS> git pushEnter passphrase for key '/c/Users/rakhesh/.ssh/id_rsa':Everything up-to-date# just to compare "matching" with "current" let's change the push policy to "current" and see what happensPS> git config --global push.default currentPS> git pushTotal 0 (delta 0), reused 0 (delta 0)To git@github.com:rakheshster/PS-AppMgmt.git* [new branch] HEAD -> testing2The last example makes the difference between
current
andupstream
very clear. If the push policy is set tocurrent
it always pushes to a branch of the same name on the remote end, and if such a branch doesn’t exist it creates one. This makes it impossible to have your local branch point to a differently named remote branch and issuegit push
without any further instructions and expect it to work. If that’s the behavior you want, be sure to set the push policy asupstream
.As an aside: I found this and this – two useful posts from StackOverflow to understand the concept of an upstream remote. These in turn helped me understand why the push policy is called
upstream
and the scenarios where one might require such a policy. This GitHub help page too is worth a read.simple
: If you don’t specify the remote, push the current branch to a branch with the same name on the remote end. However, if a branch of the same name doesn’t exist at the remote end, a new one won’t be created. Thussimple
is a cross betweencurrent
andupstream
– unlikecurrent
it does not create a new branch and unlikeupstream
it cannot push to a branch with a different name.12345678910111213141516171819202122232425262728293031323334353637383940PS> git config --global push.default simple# create a new branch and switch to itPS> git checkout -b testing2Switched to a new branch 'testing2'# try pushing this branch to the remote end - note that it fails.# this behaviour is similar to "upstream" and unlike "current". a new remote branch isn't created.PS> git pushfatal: The current branch testing2 has no upstream branch.To push the current branch and set the remote as upstream, usegit push --set-upstream origin testing2# create a new branch locally and push to remotePS> git checkout -b nottesting2Switched to a new branch 'nottesting2'PS> git push origin nottesting2Total 0 (delta 0), reused 0 (delta 0)To git@github.com:rakheshster/PS-AppMgmt.git* [new branch] nottesting2 -> nottesting2# switch to the testing2 and set nottesting2 as its upstreamPS> git checkout testing2Switched to branch 'testing2'PS> git branch -u origin/nottesting2Branch testing2 set up to track remote branch nottesting2 from origin.# try pushing - and note that again it fails.# this is similar to "current" and unlike "upstream". the remote branch *must* have the same name as local.PS> git pushfatal: The upstream branch of your current branch does not matchthe name of your current branch. To push to the upstream branchon the remote, usegit push origin HEAD:nottesting2To push to the branch of the same name on the remote, usegit push origin testing2Starting from Git 2.0 the
simple
will be the default forgit push
. This is the safest option and so considered beginner friendly.matching
: If you don’t specify the remote, push all branches having the same name on both ends.If a branch of the same name doesn’t exist at the remote end, create one.
12345678910111213141516171819202122232425262728PS> git config --global push.default matching# create a new local branchPS> git checkout -b testing2Switched to a new branch 'testing2'# try pushing this branch and note that it succeeds.# however, note that a new branch called testing2 is not created remotely.# all that's happened is that the existing local branches with same name on the remote end were pushed.PS> git pushEverything up-to-datePS> git remote show origin* remote originFetch URL: git@github.com:rakheshster/PS-AppMgmt.gitPush URL: git@github.com:rakheshster/PS-AppMgmt.gitHEAD branch (remote HEAD is ambiguous, may be one of the following):0.1masterRemote branches:0.1 trackedmaster trackedtesting trackedLocal branch configured for 'git pull':master merges with remote masterLocal refs configured for 'git push':0.1 pushes to 0.1 (up to date)master pushes to master (up to date)testing pushes to testing (up to date)Currently
matching
is the defaultgit push
policy but starting with Git 2.0 it will be replaced withsimple
.
Good stuff! I’ve now set my default to simple
.