简体   繁体   English

如何找到git SHA指向分支HEAD?

[英]How do I find if a git SHA points to a branch HEAD?

To avoid unnecessarily detached HEADs when checking out a certain git SHA with a (python) script, I'd like to check out a branch instead, if that SHA happens to be the current HEAD of a branch. 为了避免在使用(python)脚本检出某个git SHA时不必要的分离HEAD,我想检查一个分支,如果该SHA恰好是分支的当前HEAD。

Ideally, I want to feed git an SHA, and it returns a branch name if the SHA is on a branch's current tip, or error out if not. 理想情况下,我想给git一个SHA,如果SHA在分支的当前提示上,则返回分支名称,否则返回错误。

git describe --all --exact-match <SHA> very nearly is what I need, only that it is primarily aimed at tags, and so if a branch and a tag point at my SHA (which often happens in our release branches, for example), only the tag is given. git describe --all --exact-match <SHA> 非常接近我所需要的,只是它主要针对标签,所以如果分支标签指向我的SHA(通常发生在我们的发布分支中,例如),只给出标签。 This is not useful, because checking out the tag leads to a detached HEAD (even if a branch points at the same SHA). 这没用,因为签出标签会导致分离的HEAD(即使分支指向同一个SHA)。

Note, I don't want to do git branch --contains - I don't need to know which branches contain my commit. 注意,我不想做git branch --contains - 我不需要知道哪些分支包含我的提交。

If there's no command like git describe , just for branches, I know I can cross-check my SHA against branch SHAs via git show-ref . 如果没有像git describe这样的命令,只是对于分支,我知道我可以通过git show-ref交叉检查我的SHA对分支SHA。 That's not the most elegant solution, though. 不过,这不是最优雅的解决方案。

I could also do git name-rev --name-only <hash> , but I'd have to manually check the output for ~ characters, which feels unelegant if there's a git command somewhere to do the same thing. 我也可以做git name-rev --name-only <hash> ,但是我必须手动检查~字符的输出,如果有一个git命令在某处做同样的事情,感觉很不雅。

You could try something like this: 你可以尝试这样的事情:

git for-each-ref --format="%(refname:short) %(objectname)" 'refs/heads/' |
    grep SHA1 | cut -d " " -f 1

That should give you a list of branches that are currently at the revision SHA1 . 这应该为您提供当前位于修订版SHA1的分支列表。

If you are going to use python, this is what I would do: 如果你打算使用python,这就是我要做的:

import subprocess

def get_name(target):
    p = subprocess.Popen(['git', 'for-each-ref', 'refs/heads/'], stdout=subprocess.PIPE)
    for line in p.stdout:
        sha1, kind, name = line.split()
        if sha1 != target:
            continue
        return name
    return None

Another option is to use the power of eval to construct a dictionary: 另一个选择是使用eval的力量来构造字典:

d = '{' + subprocess.check_output(['git', 'for-each-ref', '--python', '--format=%(objectname): %(refname),', 'refs/heads/']) + '}'
name = eval(d)[sha1]

With the upcoming git 2.7 (Q4 2015) you will get a more complete version of git for-each-ref , which now support the --points-at 随着即将推出的git 2.7(2015年第4季度),您将获得更完整版的git for-each-ref ,现在支持--points-at

git for-each-ref --points-at <branch_name>

With the doc: 随着文档:

--points-at <object>:

Only list refs which points at the given object. 仅列出指向给定对象的引用。

That will allow to check if a commit is part of that list or not. 这将允许检查提交是否是该列表的一部分。


See commit 4a71109 , commit ee2bd06 , commit f266c91 , commit 9d306b5 , commit 7c32834 , commit 35257aa , commit 5afcb90 , ..., commit b2172fd (07 Jul 2015), and commit af83baf (09 Jul 2015) by Karthik Nayak ( KarthikNayak ) . 请参阅提交4a71109提交ee2bd06提交f266c91提交9d306b5提交7c32834提交35257aa提交5afcb90 ,..., 提交b2172fd (2015年7月7日),并提交af83baf (2015年7月9日)作者: Karthik Nayak( KarthikNayak
(Merged by Junio C Hamano -- gitster -- in commit 9958dd8 , 05 Oct 2015) (由Junio C gitster合并- gitster - in commit 9958dd8 ,2015年10月5日)

Some features from " git tag -l " and " git branch -l " have been made available to " git for-each-ref " so that eventually the unified implementation can be shared across all three, in a follow-up series or two. 来自“ git tag -l ”和“ git branch -l ”的一些功能已经可用于“ git for-each-ref ”,因此最终可以在后续系列或两个中共享所有三个的统一实现。

* kn/for-each-tag-branch:
  for-each-ref: add '--contains' option
  ref-filter: implement '--contains' option
  parse-options.h: add macros for '--contains' option
  parse-option: rename parse_opt_with_commit()
  for-each-ref: add '--merged' and '--no-merged' options
  ref-filter: implement '--merged' and '--no-merged' options
  ref-filter: add parse_opt_merge_filter()
  for-each-ref: add '--points-at' option
  ref-filter: implement '--points-at' option  

For my case, I wanted to know if HEAD pointed to a branch post-checkout and then exit 0 if pointing to a branch, or exit non-zero if not pointing to a branch, which is most likely detached HEAD state assuming the checkout succeeded. 对于我的情况,我想知道HEAD是否指向分支后检查 ,然后如果指向分支则退出0,或者如果不指向分支则退出非零,这很可能是分离的HEAD状态,假设结账成功。 git symbolic-ref --short HEAD does this and also returns the name of the branch when pointing to one. git symbolic-ref --short HEAD执行此操作,并在指向一个分支时返回分支的名称。 Obviously, there's better solutions for what the OP needs, but I wanted to throw this in just in case anyone wanted to make use of the information. 显然,有更好的解决方案可以满足OP的需求,但我想把它放在以防任何人想要利用这些信息的情况下。

Get only branch names 只获取分支名称

To get the branch names referenced by a commit or tag, I came up with this .gitconfig : 为了获得提交或标记引用的分支名称,我想出了这个.gitconfig

[alias]
  branch-name = !"git for-each-ref --format=\"%(refname:short) %(objectname)\" 'refs/heads/' | sed -En 's/^(\\S+)\\s+'\"$(git rev-parse \"$1\" 2>/dev/null)\"'$/\\1/p' | grep . || { echo \"$1: not a branch\" >&2; false;}

Eg: 例如:

$ git branch-head-name da8ecd90
master

Edge cases: 边缘情况:

  • Output is null if commit-ish isn't a branch. 如果commit-ish不是分支,则输出为null。
  • With no arguments, lists all branch names. 没有参数,列出所有分支名称。

Note: the alias without .gitconfig string quoting is: 注意:没有.gitconfig字符串引用的别名是:

branch-name=!git for-each-ref --format="%(refname:short) %(objectname)" 'refs/heads/' | sed -En 's/^(\S+)\s+'"$(git rev-parse "$1" 2>/dev/null)"'$/\1/p' | grep . || { echo "$1: not a branch" >&2; false;}

我认为解决方案之一,也许不是很优雅,但相当可靠:是列出所有分支branch --contains $sha然后检查git rev-parse $branch == $sha

What about grep : 怎么样grep:

grep -R [sha] .git/refs/heads/

Or since you are calling it from a python script, why not just create a function that searches through those files, and returns the branch name or exception as you wanted. 或者,因为您是从python脚本调用它,为什么不创建一个搜索这些文件的函数,并根据需要返回分支名称或异常。

try something like this to test each branch tip hash against your given $sha: 尝试这样的东西来测试你给定的$ sha的每个分支提示哈希:

 git branch -a| cut -d " " -f 2,3 | xargs -n 1 git rev-parse | grep $sha

or just local 或者只是当地的

git branch | xargs -n 1 git rev-parse | grep $sha

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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