如何确定给定分支上是否存在给定的 git 哈希?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2444100/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-19 04:09:08  来源:igfitidea点击:

How can I determine if a given git hash exists on a given branch?

git

提问by Pinko

Background: I use an automated build system which takes a git hash as input, as well as the name of the branch on which that hash exists, and builds it. However, the build system uses the hash alone to check out the code and build it -- it simply stores the branch name, as given, in the build DB metadata.

背景:我使用一个自动构建系统,该系统将 git hash 作为输入,以及该散列所在分支的名称,然后构建它。但是,构建系统单独使用散列来检查代码并构建它——它只是在构建数据库元数据中存储给定的分支名称。

I'm worried about developers accidentally providing the wrong branch name when they kick off a build, causing confusion when people are looking through the build history.

我担心开发人员在开始构建时不小心提供了错误的分支名称,这会在人们查看构建历史时造成混乱。

So how can I confirm, before passing along the hash and branch name to the build system, that the given hash does in fact come from the given branch?

那么在将哈希和分支名称传递给构建系统之前,我如何确认给定的哈希确实来自给定的分支?

回答by Dustin

You can ask git branchdirectly which branches contain the commit in question:

您可以git branch直接询问哪些分支包含相关提交:

% git branch -a --contains 4f08c85ad
* master
  remotes/origin/bug_872
  remotes/origin/bug_898
  remotes/origin/master

回答by Chris Johnsen

Hmm, this use of a branch name seems fishy. As in Dustin's answer, there may be multiple branches that contain a commit. Why is any one of those branch names better than another for this purpose?

嗯,这种使用分支名称似乎很可疑。正如达斯汀的回答,可能有多个分支包含一个提交。为什么这些分支名称中的任何一个都比另一个更好?



If you only care about one specific branch, you could compute the “merge base” between the branch and the commit.

如果你只关心一个特定的分支,你可以计算分支和提交之间的“合并基础”。

In the following diagrams, the commit to build is C, the tip of the claimed branch is T, and the merge base is labeled with Mabove it.

在下图中,要构建的提交是C,声明分支的尖端是T,并且合并基础在其M上方标记。

  • If Mequals Cequals T, then the the commit to build is the tip of the claimed branch.

                   M
                   ↓
    o--o--o--o--o--x  branch  # x is both C and T
    
  • If Mequals C, then the tip of the claimed branch is a descendent of the commit to build.

          M
          ↓
    o--o--C--o--o--T  branch
    
  • If Mequals T, then the commit to build is a descendent of the tip of the claimed branch.

          M
          ↓
    o--o--T           branch
           \
            o--o--C
    
  • If Mequals something else, then Cis a descendent of some ancestor of T.

          M
          ↓
    o--o--o--o--o--T  branch
           \
            o--o--C
    
  • If there is no M, then the commit to build is not related to the claimed branch.

    o--o--o--o--o--T branch
    
    o--o--o--o--C
    
  • 如果Mequals Cequals T,则构建的提交是声明分支的尖端。

                   M
                   ↓
    o--o--o--o--o--x  branch  # x is both C and T
    
  • 如果Mequals C,则声明的分支的尖端是要构建的提交的后代。

          M
          ↓
    o--o--C--o--o--T  branch
    
  • 如果Mequals T,则构建的提交是声明分支的尖端的后代。

          M
          ↓
    o--o--T           branch
           \
            o--o--C
    
  • 如果M等于其他值,则C是 的某个祖先的后代T

          M
          ↓
    o--o--o--o--o--T  branch
           \
            o--o--C
    
  • 如果没有M,则构建的提交与声明的分支无关。

    o--o--o--o--o--T branch
    
    o--o--o--o--C
    

You can make this check like this:

您可以像这样进行检查:

#!/bin/sh

# Usage: is-ancestor-of <branch> <commit>

if test $# -ne 2; then
    echo "
#!/bin/sh

# Usage: is-branch <branch>

if test $# -ne 1; then
    echo "
is-branch "$claimed_branch" && is-ancestor-of "$claimed_branch" "$commit_to_build"
"': invalid arguments' exit 128 fi branch="" # check various branch hierarchies, adjust as needed git show-ref --verify refs/heads/"$branch" || git show-ref --verify refs/remotes/"$branch" || { echo "not a branch name: $branch" 1>&2 exit 1 }
"': invalid arguments' exit 128 fi claimed_branch="" commit="" merge_base="$(git merge-base "$commit" "$claimed_branch")" && test -n "$merge_base" && test "$merge_base" = "$(git rev-parse --verify "$commit")" && exit 0 echo "$commit is not an ancestor of $claimed_branch" 1>&2 exit 1

The above script does not actually require or check that the ‘branch' argument is a branch (it could be any commit-ish). To check that something is actually a branch, you might use something like this:

上面的脚本实际上并不需要或检查 'branch' 参数是否是一个分支(它可以是任何 commit-ish)。要检查某个东西是否确实是一个分支,您可以使用如下代码:

$ git reflog show myBranch

So you could use them together to verify that something is a branch and that a certain commit is in that branch:

所以你可以一起使用它们来验证某个东西是一个分支,并且某个提交在那个分支中:

C:\Prog\Git\tests\rep\main>git reflog show patches
786a190 patches@{0}: rebase finished: refs/heads/patches onto 74630b983db476c323b1d3f6771e57484551240e
8448d0f patches@{1}: master~1: updating HEAD
74630b9 patches@{2}: commit: test2
1e73e36 patches@{3}: branch: Created from master

回答by VonC

One possible non-solutionwould be to parse the result of:

一种可能的非解决方案是解析以下结果:

##代码##

and see if your hash is in it.

看看你的哈希是否在里面。

##代码##

I keep this as a Community Wiki answer to remember Igor Zevakaand Chris Johnsen's comments:

我将此作为社区 Wiki 的答案,以记住Igor ZevakaChris Johnsen的评论:

Would that work after a clone?
Pretty sure your reflog starts after you clone a remote. So if a branch had a commit before the clone, it wouldn't show up in the reflog.

There are also problems with pushes, rebases, fetches (for ‘remote tracking' branches), and pulls (either merge or rebase type) where only the new tip commit ends up the reflog.
Also reflogs are disabled by default in bare repositories (the most common destination for pushes).
Also, if “cheating” is a problem, it is just a matter of editing a text file to add or delete reflog entries, but it is a bigger ordeal to alter the history graph itself.

克隆后会起作用吗?
很确定您的 reflog 在您克隆遥控器后启动。所以如果一个分支在克隆之前有一个提交,它就不会出现在 reflog 中。

推送、rebases、获取(用于“远程跟踪”分支)和拉取(合并或 rebase 类型)也存在问题,其中只有新的提示提交结束了 reflog。
默认情况下,在裸存储库(最常见的推送目的地)中禁用引用日志。
此外,如果“作弊”是一个问题,只需编辑文本文件以添加或删除 reflog 条目即可,但更改历史图本身是一个更大的考验。