Supponendo che il repository remoto abbia una copia del ramo di sviluppo (la descrizione iniziale lo descrive in un repository locale, ma sembra che esista anche nel telecomando), dovresti essere in grado di ottenere ciò che penso tu voglia, ma l'approccio è un po 'diverso da quello che hai immaginato.
La storia di Git si basa su un DAG di commit. Le filiali (e "ref" in generale) sono solo etichette temporanee che indicano impegni specifici nel DAG di commit in continua crescita. In quanto tale, la relazione tra filiali può variare nel tempo, ma la relazione tra commit non lo fa.
---o---1 foo
\
2---3---o bar
\
4
\
5---6 baz
Sembra che baz
sia basato su (una vecchia versione di) bar
? E se cancellassimo bar
?
---o---1 foo
\
2---3
\
4
\
5---6 baz
Ora sembra che baz
sia basato su foo
. Ma la discendenza di baz
non è cambiata, abbiamo semplicemente rimosso un'etichetta (e il conseguente commit penzolante). E se aggiungessimo una nuova etichetta su 4
?
---o---1 foo
\
2---3
\
4 quux
\
5---6 baz
Ora sembra che baz
sia basato su quux
. Tuttavia, la discendenza non è cambiata, sono cambiate solo le etichette.
Se, tuttavia, ci chiedessimo "è commettere 6
un discendente di commettere 3
?" (supponendo 3
che 6
siano nomi di commit SHA-1 completi), la risposta sarebbe "sì", indipendentemente dal fatto bar
che quux
siano presenti le etichette e .
Quindi, potresti porre domande come "il commit push è un discendente della punta corrente del ramo di sviluppo ?", Ma non puoi chiedere in modo affidabile "qual è il ramo parent del commit push?".
Una domanda per lo più affidabile che sembra avvicinarsi a ciò che vuoi è:
Per tutti gli antenati del commit spinto (escluso l'attuale suggerimento di sviluppo e i suoi antenati), che hanno l'attuale suggerimento di sviluppo come genitore:
- esiste almeno un tale commit?
- sono tutti commit di questo tipo?
Che potrebbe essere implementato come:
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
Questo coprirà parte di ciò che vuoi limitato, ma forse non tutto.
Per riferimento, ecco una cronologia di esempio estesa:
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
Il codice di cui sopra potrebbe essere usato per respingere H
e S
accettando H'
, J
, K
, o N
, ma sarebbe anche accettare L
e P
(che coinvolgerà le unioni, ma non unire la punta di sviluppo ).
Per rifiutare anche L
e P
, è possibile modificare la domanda e porre
Per tutti gli antenati del commit spinto (escluso l'attuale suggerimento di sviluppo e i suoi antenati):
- ci sono impegni con due genitori?
- in caso contrario, almeno uno di questi commit ha l'attuale suggerimento di sviluppare il suo (unico) genitore?
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