简体   繁体   中英

Default remote for Git push

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 .

If you look at the explenation for remote.pushDefault :

remote.pushDefault
The remote to push to by default. Overrides branch. .remote for all branches, and is overridden by branch. .pushRemote for specific branches.

So it's meant for overriding the default remote when pushing. When it's not set, it does nothing, and the default remote of origin comes into play.

Note that remote.pushDefault has been added later (v1.8.3), so it would break a lot of things when these semantics would change.

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, or

  • a 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:

  1. Select a remote.
  2. Select a refspec.

The syntax you used was git push , ie, 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 default refspec by consulting remote.*.push configuration, and if it is not found, honors push.default configuration to decide what to push (See git-config(1) for the meaning of push.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 .

The answer is not as simple as for fetching, because there is a list of fallbacks which need to be considered:

To get the remote programatically, see this question .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM