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

前端 未结 3 1804
梦如初夏
梦如初夏 2021-01-30 20:54

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 syst

3条回答
  •  面向向阳花
    2021-01-30 21:45

    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 M above it.

    • If M equals C equals 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 M equals 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 M equals 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 M equals something else, then C is 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
      

    You can make this check like this:

    #!/bin/sh
    
    # Usage: is-ancestor-of  
    
    if test $# -ne 2; then
        echo "$0"': invalid arguments'
        exit 128
    fi
    claimed_branch="$1"
    commit="$2"
    
    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:

    #!/bin/sh
    
    # Usage: is-branch 
    
    if test $# -ne 1; then
        echo "$0"': invalid arguments'
        exit 128
    fi
    branch="$1"
    
    # 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
    }
    

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

    is-branch "$claimed_branch" && is-ancestor-of "$claimed_branch" "$commit_to_build"
    

提交回复
热议问题