【发布时间】:2018-03-12 21:27:26
【问题描述】:
我正在搜索 git 命令以了解与现有分支关联的上游(如果有)。
(某种与“写”命令相关的“读”命令git branch --set-upstream-to=...)
原因是我使用了一个连接了多个远程仓库的分支,我想在更改之前检查分支是否已经与正确的上游连接。
【问题讨论】:
标签: git git-branch upstream-branch
我正在搜索 git 命令以了解与现有分支关联的上游(如果有)。
(某种与“写”命令相关的“读”命令git branch --set-upstream-to=...)
原因是我使用了一个连接了多个远程仓库的分支,我想在更改之前检查分支是否已经与正确的上游连接。
【问题讨论】:
标签: git git-branch upstream-branch
事实上,我发现了使用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
【讨论】:
.git/config 的信息,这也很有趣。
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
例如。
Anthony Sottile's answer 通常会为您提供正确的名称,但并非总是如此。特别要注意当origin 的remote.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]
请注意,虽然 remote 被命名为 origin,但远程跟踪 branches 被命名为 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加上“指定分支的上游”的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(查找当前分支),请根据“无当前分支”情况下的行为选择要使用的命令。
【讨论】:
origin,因此我将使用您的语法git rev-parse --abbrev-ref 'mybranch'@{upstream}
只需使用git branch -vv:
foo 03b325f Commit on untracked branch
master b7da42b [origin/master] Initial commit
上游(如果有)很好地显示在方括号中。
摘自manual,并添加了重点:
-v
-vv
--详细
在列表模式下,显示每个头的 sha1 和提交主题行,以及与上游分支的关系(如果有)。 如果给出两次,则打印链接工作树的路径(如果有)和 上游分支的名称(另见 git remote show )。注意当前工作树的 HEAD 不会有它的 打印的路径(它将始终是您的当前目录)。
请注意,-vv 比 --verbose 更详细,-v 与 -v 相同。
【讨论】: