Commençons immédiatement avec un morceau du crochet pre-receive
que je l'ai déjà écrit:crochet Git « pré-recevoir » et script « git-clang format » de rejeter de manière fiable pousse qui violent les conventions de style de code
#!/bin/sh
##
format_bold='\033[1m'
format_red='\033[31m'
format_yellow='\033[33m'
format_normal='\033[0m'
##
format_error="${format_bold}${format_red}%s${format_normal}"
format_warning="${format_bold}${format_yellow}%s${format_normal}"
##
stdout() {
format="${1}"
shift
printf "${format}" "${@}"
}
##
stderr() {
stdout "${@}" 1>&2
}
##
output() {
format="${1}"
shift
stdout "${format}\n" "${@}"
}
##
error() {
format="${1}"
shift
stderr "${format_error}: ${format}\n" 'error' "${@}"
}
##
warning() {
format="${1}"
shift
stdout "${format_warning}: ${format}\n" 'warning' "${@}"
}
##
die() {
error "${@}"
exit 1
}
##
git() {
command git --no-pager "${@}"
}
##
list() {
git rev-list "${@}"
}
##
clang_format() {
git clang-format --style='file' "${@}"
}
##
while read sha1_old sha1_new ref; do
case "${ref}" in
refs/heads/*)
branch="$(expr "${ref}" : 'refs/heads/\(.*\)')"
if [ "$(expr "${sha1_new}" : '0*$')" -ne 0 ]; then # delete
unset sha1_new
# ...
else # update
if [ "$(expr "${sha1_old}" : '0*$')" -ne 0 ]; then # create
unset sha1_old
sha1_range="${sha1_new}"
else
sha1_range="${sha1_old}..${sha1_new}"
# ...
fi
fi
# ...
GIT_WORK_TREE="$(mktemp --tmpdir -d 'gitXXXXXX')"
export GIT_WORK_TREE
GIT_DIR="${GIT_WORK_TREE}/.git"
export GIT_DIR
mkdir -p "${GIT_DIR}"
cp -a * "${GIT_DIR}/"
ln -s "${PWD}/../.clang-format" "${GIT_WORK_TREE}/"
error=
for sha1 in $(list "${sha1_range}"); do
git checkout --force "${sha1}" > '/dev/null' 2>&1
if [ "$(list --count "${sha1}")" -eq 1 ]; then
# What should I put here?
else
git reset --soft 'HEAD~1' > '/dev/null' 2>&1
fi
diff="$(clang_format --diff)"
if [ "${diff%% *}" = 'diff' ]; then
error=1
error '%s: %s\n%s' \
'Code style issues detected' \
"${sha1}" \
"${diff}" \
1>&2
fi
done
if [ -n "${error}" ]; then
die '%s' 'Code style issues detected'
fi
fi
;;
refs/tags/*)
tag="$(expr "${ref}" : 'refs/tags/\(.*\)')"
# ...
;;
*)
# ...
;;
esac
done
exit 0
REMARQUE:
Les zones dont le code n'est pas pertinent sont tronquées avec # ...
.
REMARQUE:
Si vous n'êtes pas familier avec git-clang-format
, un coup d'oeil here.
Ce crochet fonctionne comme prévu, et jusqu'à présent, je n'ai pas remarqué de bugs, mais si vous remarquez un problème ou avez une suggestion d'amélioration, j'apprécierais tout rapport. Probablement, je devrais faire un commentaire sur quelle est l'intention derrière ce crochet. Eh bien, il vérifie la conformité de chaque révision poussée avec les conventions de style de code en utilisant git-clang-format
, et si l'une d'entre elles n'est pas conforme, elle affichera le diff pertinent (celui indiquant aux développeurs ce qui doit être corrigé) pour chacun d'entre eux. Fondamentalement, j'ai deux questions en profondeur concernant ce crochet. Tout d'abord, notez que j'effectue une copie du dépôt nu (serveur) de la télécommande vers un répertoire temporaire et que j'expérimente le code à des fins d'analyse. Laissez-moi vous expliquer l'intention de cela. Notez que je fais plusieurs git checkout
s et git reset
s (en raison de la boucle for
) afin d'analyser individuellement toutes les révisions poussées avec git-clang-format
. Ce que j'essaie d'éviter ici, c'est le problème de concurrence (possible) sur l'accès push au dépôt nu (serveur) de la télécommande. C'est-à-dire, je suis sous l'impression que si plusieurs développeurs essayent de pousser en même temps vers une télécommande avec ce hook pre-receive
installé, cela pourrait causer des problèmes si chacun de ces push "sessions" ne fait pas git checkout
s et s avec sa copie privée du référentiel. Donc, pour simplifier, git-daemon
dispose-t-il d'une gestion intégrée des verrous pour les "sessions" push simultanées? Va-t-il exécuter les instances de hook pre-receive
correspondantes de manière strictement séquentielle ou il y a une possibilité d'entrelacement (ce qui peut potentiellement causer un comportement indéfini)? Quelque chose me dit qu'il devrait y avoir une solution intégrée pour ce problème avec des garanties concrètes, sinon comment les télécommandes fonctionneraient-elles en général (même sans crochets complexes) étant soumises à des poussées simultanées? S'il existe une telle solution intégrée, la copie est redondante et la simple réutilisation du référentiel nu accélèrerait réellement le traitement. En passant, toute référence à la documentation officielle concernant cette question est la bienvenue.
En second lieu, les processus git-clang-format
ne mis en scène (mais pas engagé) change par rapport à engager spécifiques (HEAD
par défaut). Ainsi, vous pouvez facilement voir où se trouve un boîtier de coin. Oui, c'est avec le racine commits (révisions). En fait, git reset --soft 'HEAD~1'
ne peut pas être appliqué aux validations racine car ils n'ont pas de parents à réinitialiser. Par conséquent, le contrôle suivant ma deuxième question est là:
if [ "$(list --count "${sha1}")" -eq 1 ]; then
# What should I put here?
else
git reset --soft 'HEAD~1' > '/dev/null' 2>&1
fi
J'ai essayé git update-ref -d 'HEAD'
mais cela brise le dépôt de telle sorte que git-clang-format
n'est pas en mesure de traiter plus. Je crois que ceci est lié au fait que toutes ces révisions poussées qui sont en cours d'analyse (y compris celle de la version racine) n'appartiennent vraiment à aucune branche pour le moment. Autrement dit, ils sont en détachéHEAD
état.Il serait parfait de trouver une solution à ce cas de coin, de sorte que initiales commits peuvent également subir la même vérification par git-clang-format
pour la conformité avec les conventions de style de code.
Paix.