Lassen Sie uns sofort mit einem Schrott des pre-receive
Haken beginnen, die ich bereits geschrieben habe:Git ‚pre-receive‘ Haken und ‚git-Klirren-Format‘ Skript Schübe zuverlässig ablehnen, die Code-Stil Konventionen verletzen
#!/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
HINWEIS:
Orte mit irrelevantem Code sind mit # ...
stubbed.
HINWEIS:
Wenn Sie mit git-clang-format
nicht vertraut sind, werfen Sie einen Blick here.
Dieser Hook funktioniert wie erwartet, und bisher habe ich keine Bugs bemerkt, aber wenn Sie irgendein Problem entdecken oder einen Verbesserungsvorschlag haben, würde ich mich über jeden Bericht freuen. Wahrscheinlich sollte ich einen Kommentar geben, was hinter diesem Haken steckt. Nun, es überprüft jede Push-Version auf Übereinstimmung mit den Codestilkonventionen unter Verwendung von git-clang-format
, und wenn einer von ihnen nicht den Anforderungen entspricht, gibt es für jeden von ihnen den entsprechenden diff aus (der den Entwicklern sagt, was behoben werden sollte). Grundsätzlich habe ich zwei eingehende Fragen zu diesem Haken.
Beachten Sie zunächst, dass ich eine Kopie des (barrierefreien) (remotes) Server-Repositorys in ein temporäres Verzeichnis überführe und dort den Code für die Analyse auschecke. Lassen Sie mich die Absicht erklären. Beachten Sie, dass ich mehrere git checkout
s und git reset
s (aufgrund for
Schleife), um alle Push-Revisionen einzeln mit git-clang-format
zu analysieren. Was ich hier zu vermeiden versuche, ist das (mögliche) Nebenläufigkeitsproblem beim Push-Zugriff auf das bare Repository des Servers (der Server). Das heißt, ich habe den Eindruck, dass, wenn mehrere Entwickler versuchen werden, gleichzeitig zu einer Fernbedienung mit diesem pre-receive
Haken zu drücken, dies Probleme verursachen kann, wenn jede dieser Push "Sitzungen" git checkout
s und s nicht tut seine private Kopie des Repositories. Also, um es einfach zu machen, hat git-daemon
integrierte Lock-Management für gleichzeitige Push "Sitzungen"? Wird es die entsprechenden pre-receive
Hook-Instanzen strikt sequentiell ausführen oder besteht die Möglichkeit von Interleaving (was möglicherweise zu undefiniertem Verhalten führen kann)? Etwas sagt mir, dass es eine eingebaute Lösung für dieses Problem mit konkreten Garantien geben sollte, sonst wie würden Fernbedienungen im Allgemeinen (auch ohne komplexe Haken) dem gleichzeitigen Drücken unterworfen werden? Wenn es eine solche integrierte Lösung gibt, ist die Kopie redundant, und die einfache Wiederverwendung des blanken Repositorys würde die Verarbeitung beschleunigen. Übrigens ist jeder Hinweis auf offizielle Dokumente zu dieser Frage sehr willkommen.
Zweitens git-clang-format
Prozesse nur inszeniert (aber nicht verpflichtet) ändert sich gegenüber spezifischen (HEAD
Standardeinstellung) begehen. So können Sie leicht sehen, wo ein Eckfall liegt. Ja, es ist mit dem root commits (Revisionen). Tatsächlich kann git reset --soft 'HEAD~1'
nicht auf root-Commits angewendet werden, da sie keine Eltern haben, auf die sie zurückgesetzt werden können. Daher ist die folgende Prüfung mit meiner zweiten Frage gibt:
if [ "$(list --count "${sha1}")" -eq 1 ]; then
# What should I put here?
else
git reset --soft 'HEAD~1' > '/dev/null' 2>&1
fi
Ich habe versucht, git update-ref -d 'HEAD'
aber das bricht das Repository so dass git-clang-format
nicht in der Lage ist, es nicht mehr zu verarbeiten. Ich glaube, dass dies mit der Tatsache zusammenhängt, dass all diese gedrängten Revisionen, die analysiert werden (einschließlich dieser Wurzel), eigentlich noch keinem Zweig angehören. Das heißt, sie sind in gelöstHEAD
Zustand.Es wäre auch perfekt, eine Lösung für diesen Eckfall zu finden, so dass initial commits können auch die gleiche Prüfung von git-clang-format
für die Einhaltung von Code-Stil Konventionen unterzogen werden.
Frieden.