如何读取 git 分支的当前上游

How read the current upstream for a git branch

我正在搜索 git 命令以了解与现有分支(如果有)关联的上游。
(与 "write" 命令 git branch --set-upstream-to=... 关联的某种 "read" 命令)
原因是我使用了一个连接了多个远程repos的分支,我想在更改之前检查分支是否已经连接到正确的上游。

事实上,我发现第一个技巧是使用 git status 命令:
我的分支是当前分支并且有一个上游,我得到一条像 Your branch is up-to-date with 'the_repo/the branch' 的行,但我宁愿有一个更直接的方式来知道这一点。

以下是我如何找到与 git status 相同的答案,但以脚本友好的方式:

 $ branch="$(git branch | grep '\*' | cut -d' ' -f2-)"
 $ remote="$(git config "branch.${branch}.remote")"
 $ remote_branch="$(git config "branch.${branch}.merge" | cut -d/ -f3-)"
 $ echo "${branch} is tracking ${remote}/${remote_branch}"
 print_locking_less is tracking origin/master

远程跟踪分支的信息存储在.git/config中,它看起来像这样:

[branch "print_locking_less"]
        remote = origin
        merge = refs/heads/master

TL;DR: 使用 git rev-parse

$ git rev-parse --abbrev-ref master@{u}
weird/master

如果没有设置上游,你会得到:

fatal: no upstream configured for branch 'master'

(和非零退出代码)。如果不需要,将 stderr 重定向到 /dev/null 以丢弃错误消息:

if master_upstream=$(git rev-parse --abbrev-ref master@{u} 2>/dev/null); then
    master_has_upstream=true
else
    master_has_upstream=false
fi

例如。

说明

通常 会为您提供正确的名称,但并非总是如此。特别是,观察当 originremote.origin.fetch 设置不正常时会发生什么:

$ git init
Initialized empty Git repository in .../tmp/tt/.git/
$ git remote add origin git://github.com/git/git
$ git config remote.origin.fetch '+refs/heads/*:refs/remotes/weird/*'
$ git fetch
remote: Counting objects: 231294, done.
remote: Compressing objects: 100% (663/663), done.
remote: Total 231294 (delta 0), reused 662 (delta 0), pack-reused 230631
Receiving objects: 100% (231294/231294), 93.03 MiB | 3.54 MiB/s, done.
Resolving deltas: 100% (170261/170261), done.
From git://github.com/git/git
 * [new branch]          maint      -> weird/maint
 * [new branch]          master     -> weird/master
 * [new branch]          next       -> weird/next
 * [new branch]          pu         -> weird/pu
 * [new branch]          todo       -> weird/todo
 * [new tag]             v2.14.2    -> v2.14.2
[lots more tags snipped]

请注意,虽然 远程 被命名为 origin,但远程跟踪 分支 被命名为 weird/master , weird/next, 等等。它确实有效:

$ git checkout master
Branch master set up to track remote branch master from origin.
Already on 'master'
$ git status
On branch master
Your branch is up-to-date with 'weird/master'.

nothing to commit, working tree clean

但是如果远程跟踪分支名称是 origin/master:

,那么 .git/config 中的内容看起来仍然与您期望的一样
[branch "master"]
    remote = origin
    merge = refs/heads/master

使用:

 branch="$(git branch | grep '\*' | cut -d' ' -f2-)"

工作得很好(尽管人们应该经常使用 git symbolic-ref --short HEAD 来获取当前分支名称:见下文)。

remote="$(git config "branch.${branch}.remote")"

这部分工作完美——它获取遥控器的名称。

remote_branch="$(git config "branch.${branch}.merge" | cut -d/ -f3-)"

这是我们出错的地方。我们需要的是使用 git rev-parse 加上 "the upstream of a specified branch" 的 gitrevisions 语法,也就是将 @{u}@{upstream} 附加到分支名称。通常 git rev-parse 将其转换为散列 ID,但使用 --abbrev-ref,它会打印名称的短版本,或者使用 --symbolic-full-name,它会打印长版本:

$ git rev-parse --symbolic-full-name master@{u}
refs/remotes/weird/master

(我不知道为什么在一种情况下拼写为 --abbrev-ref 而在另一种情况下拼写为 --symbolic-full-name。)

注意在HEAD上使用git rev-parse时,如果HEAD被分离,答案就是符号HEAD。也就是说,在任何 Git 存储库中,git rev-parse HEAD 总是成功,即使在打印符号名称时也是如此。这 不是 git symbolic-ref

$ git checkout --detach
HEAD is now at ea220ee40... The eleventh batch for 2.15
$ git rev-parse --abbrev-ref HEAD
HEAD
$ git rev-parse --symbolic-full-name HEAD
HEAD
$ git symbolic-ref HEAD
fatal: ref HEAD is not a symbolic ref

所以为了解决HEAD(找到当前分支),根据你在"no current branch"情况下想要的行为选择要使用的命令。

只需使用git branch -vv:

foo    03b325f Commit on untracked branch
master b7da42b [origin/master] Initial commit

上游(如果有)很好地显示在方括号中。

摘自 manual 添加了重点:

-v
-vv
--verbose
When in list mode, show sha1 and commit subject line for each head, along with relationship to upstream branch (if any). If given twice, print the path of the linked worktree (if any) and the name of the upstream branch, as well (see also git remote show ). Note that the current worktree’s HEAD will not have its path printed (it will always be your current directory).

请注意 -vv--verbose 更冗长,后者与 -v 相同。