Get default remote push and default remote branch

2019-04-11 17:29发布

问题:

From a script, I would like to get the default push remote and the default push branch.

For the recall, git will choose the remote between these settings, in this order:

  • branch.<name>.pushRemote
  • remote.pushDefault
  • branch.<name>.remote
  • very last default
    • origin if config push.default current
    • NULL if config push.default upstream

I can't find any reference how git is choosing this last default origin, but it seems static.

Default remote branch can be:

  • branch.<name>.merge if config push.default upstream
  • current branch name otherwise

Now, I would like a safe way to get both default push remote and default push branch.

  1. I could use git config --get, but I'll have to resolve myself the behoavior according to config push.default, and it seems a bit risky.
  2. I would prefer to use one of these:
    • git for-each-ref --format='%(push:short)' refs/heads/mybranch
    • git rev-parse --abbrev-ref=loose mybranch@{push}

Finally, I have two questions:

  1. git for-each and git rev-parse returns a path like origin/mybranch. How can I split between the remote name and the branch name (a remote name can contains /'s).
  2. Is there a safer function between the both? (in all my tests, they always return the same output).

回答1:

With Git 2.16 (Q1 2018), there is a new syntax, where the "--format=..." option for "git for-each-ref" learned to show the name of the 'remote' repository and the ref at the remote side that is affected for 'upstream' and 'push' via "%(push:remotename)" and friends.

See commit 1b58686 (07 Nov 2017), and commit cc72385 (05 Oct 2017) by Johannes Schindelin (dscho).
See commit 9700fae (07 Nov 2017) by J Wyman (whoisj).
(Merged by Junio C Hamano -- gitster -- in commit 093048b, 15 Nov 2017)

for-each-ref: let upstream/push optionally report the remote name

There are times when e.g. scripts want to know not only the name of the upstream branch on the remote repository, but also the name of the remote.

This patch offers the new suffix :remotename for the upstream and for the push atoms, allowing to show exactly that. Example:

$ cat .git/config
...
[remote "origin"]
    url = https://where.do.we.come/from
    fetch = refs/heads/*:refs/remote/origin/*
[remote "hello-world"]
    url = https://hello.world/git
    fetch = refs/heads/*:refs/remote/origin/*
    pushURL = hello.world:git
    push = refs/heads/*:refs/heads/*
[branch "master"]
    remote = origin
    pushRemote = hello-world
...

$ git for-each-ref \
  --format='%(upstream) %(upstream:remotename) %(push:remotename)' \
  refs/heads/master
refs/remotes/origin/master origin hello-world

The implementation chooses not to DWIM the push remote if no explicit push remote was configured; The reason is that it is possible to DWIM this by using

%(if)%(push:remotename)%(then)
    %(push:remotename)
%(else)
    %(upstream:remotename)
%(end)

while it would be impossible to "un-DWIM" the information in case the caller is really only interested in explicit push remotes.

While :remote would be shorter, it would also be a bit more ambiguous, and it would also shut the door e.g. for :remoteref (which would obviously refer to the corresponding ref in the remote repository).


for-each-ref: let upstream/push report the remote ref name

There are times when scripts want to know not only the name of the push branch on the remote, but also the name of the branch as known by the remote repository.

An example of this is when a tool wants to push to the very same branch from which it would pull automatically, i.e. the <remote> and the <to> in git push <remote> <from>:<to> would be provided by %(upstream:remotename) and %(upstream:remoteref), respectively.

This patch offers the new suffix :remoteref for the upstream and push atoms, allowing to show exactly that. Example:

$ cat .git/config
...
[remote "origin"]
    url = https://where.do.we.come/from
    fetch = refs/heads/*:refs/remote/origin/*
[branch "master"]
    remote = origin
    merge = refs/heads/master
[branch "develop/with/topics"]
    remote = origin
    merge = refs/heads/develop/with/topics
...

$ git for-each-ref \
    --format='%(push) %(push:remoteref)' \
    refs/heads
refs/remotes/origin/master refs/heads/master
refs/remotes/origin/develop/with/topics refs/heads/develop/with/topics


标签: git push