From d201f6ef9c4b937f0ae8ee98dc291d7cfa10da92 Mon Sep 17 00:00:00 2001
From: Yuqian Yang <crupest@crupest.life>
Date: Thu, 27 Feb 2025 01:02:08 +0800
Subject: fix(git): protected branch.

---
 services/docker/git-server/hooks/pre-receive | 51 ----------------------------
 services/docker/git-server/hooks/update      | 38 +++++++++++++++++++++
 2 files changed, 38 insertions(+), 51 deletions(-)
 delete mode 100644 services/docker/git-server/hooks/pre-receive
 create mode 100644 services/docker/git-server/hooks/update

diff --git a/services/docker/git-server/hooks/pre-receive b/services/docker/git-server/hooks/pre-receive
deleted file mode 100644
index c5981dc..0000000
--- a/services/docker/git-server/hooks/pre-receive
+++ /dev/null
@@ -1,51 +0,0 @@
-#!/usr/bin/bash
-
-set -e -o pipefail
-
-if test -n "$GIT_PUSH_OPTION_COUNT"; then
-  i=0
-  while test "$i" -lt "$GIT_PUSH_OPTION_COUNT"; do
-    eval "value=\$GIT_PUSH_OPTION_$i"
-    case "$value" in
-    real-force)
-      REAL_FORCE=1
-      echo "WARNING: Real force is set. All branches will be unprotected."
-      ;;
-    esac
-    i=$((i + 1))
-  done
-fi
-
-stdin_record=$(cat)
-
-handle_line() {
-  old=$(expr substr "$1" 1 8)
-  new=$(expr substr "$2" 1 8)
-  ref_name="$3"
-  protected_file="$GIT_DIR/protected"
-
-  if [[ -f "$protected_file" ]] && ! git merge-base --is-ancestor "$old" "$new"; then
-    while read -r line; do
-      if grep -q "^$ref_name$" <<<"$line"; then
-        echo "ERROR: $ref_name is not fast-forward and protected by rule $line : $old -> $new" 1>&2
-        has_error=1
-      fi
-    done <"$protected_file"
-  fi
-  if [[ -n "$has_error" ]]; then
-    [[ -n "$REAL_FORCE" ]] || exit 1
-    echo "WARNING: Real force is set. Continuing with the push."
-  fi
-}
-
-while read -r line; do
-  handle_line $line
-done <<<"$stdin_record"
-
-if [[ -x /git/private/git/hooks/pre-receive ]]; then
-  /git/private/git/hooks/pre-receive "$@"
-fi
-
-if [[ -x "$GIT_DIR/hooks/pre-receive" ]]; then
-  "$GIT_DIR/hooks/pre-receive" "$@"
-fi
diff --git a/services/docker/git-server/hooks/update b/services/docker/git-server/hooks/update
new file mode 100644
index 0000000..4cfcacc
--- /dev/null
+++ b/services/docker/git-server/hooks/update
@@ -0,0 +1,38 @@
+#!/usr/bin/bash
+
+set -e -o pipefail
+
+ref="$1"
+old="$2"
+new="$3"
+protected_file="$GIT_DIR/protected"
+
+die() {
+  echo "error: $*" > /dev/stderr
+  exit 1
+}
+
+if [[ -f "$protected_file" ]]; then
+  while read -r line; do
+    if grep -q -E "$line" - <<< "$ref" ; then
+      if grep -q -E "^0+$" <<< "$new"; then
+        die "protected branch $ref (rule: $line) cannot be deleted"
+      fi
+
+      if ! git merge-base --is-ancestor "$old" "$new"; then
+        die "protected branch $ref (rule: $line) is not fast-forward $(expr substr "$old" 1 8) -> $(expr substr "$new" 1 8)"
+      fi
+    fi
+  done <"$protected_file"
+fi
+
+global_hook="/git/private/git/hooks/update"
+local_hook="$GIT_DIR/hooks/update"
+
+if [[ -x "$global_hook" ]]; then
+  "$global_hook" "$ref" "$old" "$new"
+fi
+
+if [[ -x "$local_hook" ]]; then
+  "$local_hook" "$ref" "$old" "$new"
+fi
-- 
cgit v1.2.3