Предполагая, что удаленный репозиторий имеет копию ветви develop (ваше первоначальное описание описывает ее в локальном репозитории, но, похоже, она также существует в удаленном), вы должны быть в состоянии достичь то, что я думаю, вы хотите, но подход немного отличается от того, что вы предполагали.
История Git основана на DAG коммитов. Ветви (и вообще «ссылки») - это просто временные метки, которые указывают на конкретные коммиты в постоянно растущей 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
. Тем не менее, родословная не изменилась, изменились только ярлыки.
Если, однако, мы спрашиваем «является ли коммит 6
потомком коммита 3
?» (При условии, что 3
и 6
- полные имена коммитов SHA-1), тогда ответом будет «да». ”, Присутствуют метки bar
и quux
или нет.
Таким образом, вы можете задавать вопросы типа «является ли проталкиваемый коммит потомком текущей вершины ветви development ?», Но вы не можете с уверенностью спросить «какова родительская ветвь проталкиваемого коммита» ?».
Наиболее достоверный вопрос, который, кажется, приближается к тому, что вы хотите:
Для всех предков выдвинутого коммита (исключая текущий наконечник development и его предков), у которых текущий наконечник разрабатывает в качестве родителя:
- существует хотя бы один такой коммит?
- это все такие коммиты с одним родителем?
Что может быть реализовано как:
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
( они включают слияния, но не сливаются с вершиной development ).
Чтобы также отклонить L
и P
, вы можете изменить вопрос и задать
Для всех предков выдвинутого коммита (исключая текущий совет development и его предков):
- есть ли коммиты с двумя родителями?
- если нет, то по крайней мере у одного такого коммита текущая подсказка разрабатывает его (только) родителя?
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