让我们假设我有以下本地存储库和一个像这样的提交树:
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运行它会给你掌握。
代码可以作为要点提供。
Joe Chrysler的命令行魔法可以简化。下面是Joe的逻辑——为了简洁起见,我在两个版本中都引入了一个名为cur_branch的参数来代替命令替换' git rev-parse——abbrev-ref HEAD ';可以像这样初始化:
cur_branch=$(git rev-parse --abbrev-ref HEAD)
然后,这是Joe的管道:
git show-branch -a |
grep '\*' | # we want only lines that contain an asterisk
grep -v "$cur_branch" | # but also don't contain the current branch
head -n1 | # and only the first such line
sed 's/.*\[\(.*\)\].*/\1/' | # really, just the part of the line between []
sed 's/[\^~].*//' # and with any relative refs (^, ~n) removed
我们可以在一个相对简单的awk命令中完成与所有这五个单独的命令过滤器相同的事情:
git show-branch -a |
awk -F'[]^~[]' '/\*/ && !/'"$cur_branch"'/ {print $2;exit}'
具体情况是这样的:
-F'[]^~[]'
将行分割为以]、^、~和[为字符的字段。
/\*/
找出包含星号的行
&& !/'"$cur_branch"'/
...但不是当前的分支名称
{ print $2;
当您找到这样的一行时,打印它的第二个字段(即字段分隔符第一次和第二次出现之间的部分)。对于简单的分支名称,这将是括号之间的内容;对于具有相对跳转的引用,它将只是没有修饰符的名称。因此,我们的字段分隔符集处理了两个sed命令的意图。
exit }
然后立即退出。这意味着它只处理第一个匹配的行,所以我们不需要通过head -n 1来输出。