让我们假设我有以下本地存储库和一个像这样的提交树:

master --> a
            \
             \
      develop c --> d
               \
                \
         feature f --> g --> h

Master是我的,这是最新的稳定发布代码,develop是我的,这是“下一个”发布代码,feature是一个正在准备开发的新功能。

使用钩子,我希望能够拒绝推送功能到我的远程存储库,除非commit f是develop HEAD的直接后代。也就是说,提交树看起来是这样的,因为feature已经基于d。

master --> a
            \
             \
      develop c --> d
                     \
                      \
               feature f --> g --> h

那么是否有可能:

识别特征的父分支? 确定父分支中的提交f是哪个分支的后代?

从那里,我将检查父分支的HEAD是什么,并查看f前任是否匹配父分支HEAD,以确定该特性是否需要重基。


当前回答

这对我来说很有效:

git show-branch | grep '*' | grep -v "$(git rev-parse --abbrev-ref HEAD)" | head -n1 | sed 's/.*\[\(.*\)\].*/\1/' | sed 's/[\^~].*//'

来自droidbot和@ jstanidiot的礼貌评论和回答。

其他回答

我不喜欢解析半结构化文本输出时涉及的不安全假设,所以我想要一个更健壮的解决方案,假设更少:

# Search backwards in history for the first commit that is in a branch other than $1
# and output that branch's name.
parent_branch() {
    local result rev child_branch=$1
    rev=$(git rev-parse --revs-only $child_branch)
    while [[ -n $rev ]]; do
        result=$(git branch --contains $rev | grep -v " $child_branch$")
        if [[ -n $result ]]; then
            echo $result
            return 0
        fi
        rev=$(git rev-parse --revs-only $rev^)
    done
    return 1
}

注意:由于这是在历史上进行迭代,查看每个提交以找到第一个在不同分支中而不是$1的提交,因此分支越长,它的开销就越高。但是,由于通常情况下分支应该是相对短暂的,所以这不应该是一个太大的问题。

还要注意,我使用的是git branch——contains,所以这也会找到共享公共基础但已经超越它的分支。要只找到确切指向公共基的分支,请使用git branch——points-at。

对于您的整体问题,我有一个解决方案(确定feature是否源自develop的提示),但使用您概述的方法它不起作用。

你可以使用git branch——contains列出所有来自develop提示的分支,然后使用grep确保feature在其中。

git branch --contains develop | grep "^ *feature$"

如果是其中之一,则将“feature”打印到标准输出,并返回代码为0。否则,它将不打印任何东西,并有一个返回代码1。

你也可以试试:

git log --graph --decorate

由于之前的答案在我们的存储库中都不起作用,我想分享我自己的方法,使用git日志中的最新归并:

#!/bin/bash
git log --oneline --merges "$@" | grep into | sed 's/.* into //g' | uniq --count | head -n 10

把它放在一个名为git-last-merge的脚本中,该脚本也接受一个分支名称作为参数(而不是当前分支)以及其他git日志参数。

从输出中,我们可以根据自己的分支约定和每个分支的合并数量手动检测父分支。

如果你经常在子分支上使用git rebase(合并通常是快进的,所以没有太多的合并提交),这个答案不会很好地工作,所以我写了一个脚本来计算所有分支与当前分支相比的前提交(正常和合并)和后提交(在父分支中不应该有任何后合并)。

#!/bin/bash
HEAD="`git rev-parse --abbrev-ref HEAD`"
echo "Comparing to $HEAD"
printf "%12s  %12s   %10s     %s\n" "Behind" "BehindMerge" "Ahead" "Branch"
git branch | grep -v '^*' | sed 's/^\* //g' | while read branch ; do
    ahead_merge_count=`git log --oneline --merges $branch ^$HEAD | wc -l`
    if [[ $ahead_merge_count != 0 ]] ; then
        continue
    fi
    ahead_count=`git log --oneline --no-merges $branch ^$HEAD | wc -l`
    behind_count=`git log --oneline --no-merges ^$branch $HEAD | wc -l`
    behind_merge_count=`git log --oneline --merges ^$branch $HEAD | wc -l`
    behind="-$behind_count"
    behind_merge="-M$behind_merge_count"
    ahead="+$ahead_count"
    printf "%12s  %12s   %10s     %s\n" "$behind" "$behind_merge" "$ahead" "$branch"
done | sort -n

一个rephrasal

这个问题的另一种表达方式是“驻留在当前分支以外的分支上的最近的提交是什么?是哪个分支?”

一个解决方案

您可以使用一点命令行魔法找到它

git show-branch \
| sed "s/].*//" \
| grep "\*" \
| grep -v "$(git rev-parse --abbrev-ref HEAD)" \
| head -n1 \
| sed "s/^.*\[//"

AWK:

git show-branch -a \
| grep '\*' \
| grep -v `git rev-parse --abbrev-ref HEAD` \
| head -n1 \
| sed 's/[^\[]*//' \
| awk 'match($0, /\[[a-zA-Z0-9\/.-]+\]/) { print substr( $0, RSTART+1, RLENGTH-2 )}'

下面是它的工作原理:

Display a textual history of all commits, including remote branches. Ancestors of the current commit are indicated by a star. Filter out everything else. Ignore all the commits in the current branch. The first result will be the nearest ancestor branch. Ignore the other results. Branch names are displayed [in brackets]. Ignore everything outside the brackets, and the brackets. Sometimes the branch name will include a ~# or ^# to indicate how many commits are between the referenced commit and the branch tip. We don't care. Ignore them.

结果是

运行上面的代码

 A---B---D <-master
      \
       \
        C---E---I <-develop
             \
              \
               F---G---H <-topic

如果你从H运行它会给你发展,如果你从I运行它会给你掌握。

代码可以作为要点提供。