In Git-config you can see:
branch.name.remote
When on branch <name>, it tells git fetch and git push which remote to fetch from/push to. The remote to push to may be overridden with remote.pushDefault (for all branches). The remote to push to, for the current branch, may be further overridden by branch.<name>.pushRemote. If no remote is configured, or if you are not on any branch, it defaults to origin for fetching and remote.pushDefault for pushing.
Now I have a cloned
repository and a branch which is named test
and is checkouted. Here you can see contents of config
file of the cloned repository:
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
[remote "origin"]
url = ...
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
remote = origin
merge = refs/heads/master
As you see, branch.
test
.pushRemote
, remote.pushDefault
and branch.
test
.remote
are not set there. So I expect when I do
$ git push
I will get
fatal: No configured push destination.
But I get
Everything up-to-date
It seems Git
uses origin
instead of not configured remote.pushDefault
. But why when docs say
it defaults to remote.pushDefault for pushing.
Edit:
In Git-push you can see:
When the command line does not specify where to push with the <repository> argument, branch.*.remote configuration for the current branch is consulted to determine where to push. If the configuration is missing, it defaults to origin.
It think there is a conflict between using origin
and remote.pushDefault
.
Git's push code (and pull too, really) is (in my opinion) unnecessarily complicated because it tries to retain a large number of historical behaviors, several of which were bad ideas.
Let's look first at the REMOTES section of the git-push
documentation:
The name of one of the following can be used instead of a URL as repository argument:
a remote in the Git configuration file:
$GIT_DIR/config
,a file in the
$GIT_DIR/remotes
directory, ora file in the
$GIT_DIR/branches
directory.All of these also allow you to omit the refspec from the command line because they each contain a refspec which git will use by default.
(The name of a remote is—again, this is just my opinion—the only one of these that really should survive today. I think the specified-URL method probably should be moved to a plumbing command, and git push
could return to being a simple script, although the Git-on-Windows folks are, alas, trying to convert away from scripts due to Windows performance issues.)
Fortunately, you are using the named-remote method, so we can ignore most of this. Specifically, the refspec is optional because you are using a remote in $GIT_DIR/config
.
Next, we should clearly distinguish between syntax (nouns and verbs and such that you enter on a command line) and semantics (behavior). Once we toss out the extra varieties of "remote" we're left with two tasks:
The syntax you used was git push
, i.e., no specified repository
argument and no specified refspec
. So for step 1, selecting a remote, Git uses the paragraph you quoted in your edit: find the current branch—in this case, test
–and then look up branch.test.remote
. This is not configured (is "missing"), so Git falls back to using origin
.
(There's a bug in the quoted documentation paragraph, as it fails to mention branch.branch.pushRemote
, which in this case would be branch.test.pushRemote
. The correct sequence is (1) look for the branch-specific pushRemote; (2) look for the branch-specific remote; (3) look for remote.pushDefault
if Git version 1.8.3 or newer; (4) try the word origin
. This documentation bug is still in git 2.8.1.)
Since origin
is a valid remote name, step 1 succeeds and we move on to step 2, selecting a refspec. This part does not have you puzzled, but just for completeness:
When the command line does not specify what to push with
refspec ...
arguments or--all
,--mirror
,--tags
options, the command finds the defaultrefspec
by consultingremote.*.push
configuration, and if it is not found, honorspush.default
configuration to decide what to push (Seegit-config(1)
for the meaning ofpush.default
).
So in this case, Git looks for remote.origin.push
and, since that is not set, push.default
. If push.default
is not set, there is a "default default", which in Git prior to 2.0 was matching
and is now (Git 2.0 or newer) simple
. This default push.default
means that there is always a refspec.
The default remote-name origin
means that there is usually a remote. This fails only when there is no [remote "origin"]
section in your $GIT_DIR/config
.