@@ -53,11 +53,72 @@ if [[ -z "${RANGE}" ]]; then
5353 exit 0
5454fi
5555
56+ ensure_allowed_merge_refs () {
57+ local missing=()
58+ local branch=" "
59+ for branch in dev beta; do
60+ if git rev-parse --verify " refs/remotes/origin/${branch} ^{commit}" > /dev/null 2>&1 ; then
61+ continue
62+ fi
63+ missing+=(" ${branch} " )
64+ done
65+
66+ if [[ " ${# missing[@]} " -eq 0 ]]; then
67+ return
68+ fi
69+
70+ git fetch --no-tags origin " ${missing[@]} " > /dev/null 2>&1 || true
71+ }
72+
73+ merge_commit_allowed () {
74+ local commit=" ${1:- } "
75+ local parent_refs=" "
76+ local parent_list=()
77+ local parent_index=0
78+ local parent_commit=" "
79+ local allowed_ref=" "
80+
81+ parent_refs=" $( git show -s --format=%P " ${commit} " 2> /dev/null || true) "
82+ if [[ -z " ${parent_refs} " ]]; then
83+ return 1
84+ fi
85+
86+ # Non-first parents identify the merged branch tip(s).
87+ read -r -a parent_list <<< " ${parent_refs}"
88+ for (( parent_index= 1 ; parent_index< ${# parent_list[@]} ; parent_index++ )) ; do
89+ parent_commit=" ${parent_list[$parent_index]} "
90+ for allowed_ref in refs/remotes/origin/dev refs/heads/dev refs/remotes/origin/beta refs/heads/beta; do
91+ if ! git rev-parse --verify " ${allowed_ref} ^{commit}" > /dev/null 2>&1 ; then
92+ continue
93+ fi
94+ if git merge-base --is-ancestor " ${parent_commit} " " ${allowed_ref} " ; then
95+ return 0
96+ fi
97+ done
98+ done
99+
100+ return 1
101+ }
102+
56103MERGES=" $( git rev-list --merges " ${RANGE} " || true) "
57104if [[ -n " ${MERGES} " ]]; then
58- echo " ERROR: merge commits are not allowed in the checked main-branch range (${RANGE} )." >&2
59- echo " ${MERGES} " >&2
60- exit 1
105+ BAD_MERGES=()
106+ MERGE_COMMIT=" "
107+
108+ ensure_allowed_merge_refs
109+
110+ while IFS= read -r MERGE_COMMIT; do
111+ [[ -z " ${MERGE_COMMIT} " ]] && continue
112+ if ! merge_commit_allowed " ${MERGE_COMMIT} " ; then
113+ BAD_MERGES+=(" ${MERGE_COMMIT} " )
114+ fi
115+ done <<< " ${MERGES}"
116+
117+ if [[ " ${# BAD_MERGES[@]} " -gt 0 ]]; then
118+ echo " ERROR: main-branch merge commits must promote only dev/beta history in the checked range (${RANGE} )." >&2
119+ printf ' %s\n' " ${BAD_MERGES[@]} " >&2
120+ exit 1
121+ fi
61122fi
62123
63124echo " Main branch history guard passed: range=${RANGE} "
0 commit comments