让我们假设我有以下本地存储库和一个像这样的提交树:
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,以确定该特性是否需要重基。
一个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运行它会给你掌握。
代码可以作为要点提供。
我不喜欢解析半结构化文本输出时涉及的不安全假设,所以我想要一个更健壮的解决方案,假设更少:
# 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。