Предполагая, что удаленный репозиторий имеет копию ветви разработки (ваше первоначальное описание описывает ее в локальном репозитории, но похоже, что она также существует в удаленном), вы должны быть в состоянии достичь того, что я думаю, что вы хотите, но подход немного отличается от того, что вы предполагали.
История 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
метки присутствуют или нет.
Таким образом, вы можете задать такие вопросы, как «является ли проталкиваемый коммит потомком текущего кончика ветви разработки ?», Но вы не можете с уверенностью спросить «какова родительская ветвь проталкиваемого коммита?».
Наиболее надежный вопрос, который, кажется, приближается к тому, что вы хотите:
Для всех предков выдвинутого коммита (за исключением текущего наконечника развертки и его предков), у которых текущий наконечник развития является родительским:
- существует хотя бы один такой коммит?
- все ли такие коммиты с одним родителем?
Который может быть реализован как:
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
, вы можете изменить вопрос и спросить
Для всех предков push-коммитов (исключая текущий наконечник Develop и его предков):
- есть ли коммиты с двумя родителями?
- если нет, имеет ли хотя бы один такой коммит текущий совет развития своего (единственного) родителя?
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