假设远程存储库具有开发的副本分支(您的初始描述是在本地存储库中描述的,但听起来它也存在于远程存储库中),那么您应该能够实现我认为想要的功能,但是该方法与您的设想有些不同。
Git的历史基于提交的DAG。分支(通常是“ refs”)只是临时标签,指向不断增长的提交DAG中的特定提交。这样,分支之间的关系可以随时间而变化,但是提交之间的关系却没有。
---o---1 foo
\
2---3---o bar
\
4
\
5---6 baz
看起来baz
是基于(旧版本)bar
?但是,如果我们删除该bar
怎么办?
---o---1 foo
\
2---3
\
4
\
5---6 baz
现在看起来像是baz
基于foo
。但是的祖先baz
没有改变,我们只是删除了一个标签(以及随之而来的悬空提交)。如果我们在添加新标签4
怎么办?
---o---1 foo
\
2---3
\
4 quux
\
5---6 baz
现在看起来像是baz
基于quux
。尽管如此,血统并没有改变,只是标签改变了。
但是,如果我们要问“是commit 6
的后代3
吗?” (假设3
并且6
是完整的SHA-1提交名称),那么答案将是“是”,无论是否bar
和quux
标签。
因此,您可能会问诸如“被推动的提交是开发当前提示的后代吗?的分支?”,但你不能可靠地问:“什么是推的父分支提交吗?”。
似乎最接近您想要的一个最可靠的问题是:
对于所有推送的提交的祖先(不包括当前的development和其祖先),以parent 为开发者的当前提示:
可以实现为:
pushedrev=...
basename=develop
if ! baserev="$(git rev-parse --verify refs/heads/"$basename" 2>/dev/null)"; then
echo "'$basename' is missing, call for help!"
exit 1
fi
parents_of_children_of_base="$(
git rev-list --pretty=tformat:%P "$pushedrev" --not "$baserev" |
grep -F "$baserev"
)"
case ",$parents_of_children_of_base" in
,) echo "must descend from tip of '$basename'"
exit 1 ;;
,*\ *) echo "must not merge tip of '$basename' (rebase instead)"
exit 1 ;;
,*) exit 0 ;;
esac
这将涵盖您要限制的部分内容,但可能不是全部。
作为参考,这是一个扩展的示例历史记录:
A master
\
\ o-----J
\ / \
\ | o---K---L
\ |/
C--------------D develop
\ |\
F---G---H | F'--G'--H'
| |\
| | o---o---o---N
\ \ \ \
\ \ o---o---P
\ \
R---S
上面的代码可以用来拒绝H
并S
同时接受H'
,J
,K
,或N
,但它也接受L
和P
(它们涉及合并,但他们不合并的尖端发展)。
要也拒绝L
和P
,您可以更改问题并提问
对于所有的推提交的祖先(不包括当前尖端发展及其祖先):
- 有两个父母有什么约定吗?
- 如果没有,那么至少一个这样的提交是否具有开发其(仅)父对象的当前提示?
pushedrev=...
basename=develop
if ! baserev="$(git rev-parse --verify refs/heads/"$basename" 2>/dev/null)"; then
echo "'$basename' is missing, call for help!"
exit 1
fi
parents_of_commits_beyond_base="$(
git rev-list --pretty=tformat:%P "$pushedrev" --not "$baserev" |
grep -v '^commit '
)"
case "$parents_of_commits_beyond_base" in
*\ *) echo "must not push merge commits (rebase instead)"
exit 1 ;;
*"$baserev"*) exit 0 ;;
*) echo "must descend from tip of '$basename'"
exit 1 ;;
esac