#!/usr/bin/env python3 from __future__ import annotations import argparse from pathlib import Path import stat import subprocess import sys PROJECT_DIR = Path(__file__).resolve().parents[1] def parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser(description="安装提交后自动推送到 Gitea 的 Git hook") parser.add_argument("--remote", default="origin", help="Gitea remote 名称,默认 origin") parser.add_argument("--force", action="store_true", help="覆盖已有 post-commit hook") parser.add_argument("--dry-run", action="store_true", help="只打印将要写入的 hook 内容") return parser.parse_args() def run_git(args: list[str]) -> str: result = subprocess.run( ["git", *args], cwd=PROJECT_DIR, text=True, capture_output=True, check=False, ) if result.returncode != 0: raise RuntimeError(result.stderr.strip() or result.stdout.strip()) return result.stdout.strip() def hook_text(remote: str) -> str: return f"""#!/bin/sh set -eu remote={remote!r} branch=$(git symbolic-ref --quiet --short HEAD || true) if [ -z "$branch" ]; then echo "[gitea-backup] detached HEAD,跳过自动推送" >&2 exit 0 fi if ! git remote get-url "$remote" >/dev/null 2>&1; then echo "[gitea-backup] remote '$remote' 不存在,跳过自动推送" >&2 exit 0 fi echo "[gitea-backup] pushing $branch to $remote" if ! git push "$remote" "HEAD:$branch"; then echo "[gitea-backup] push 失败;本地提交已保留,请检查 SSH key 或远端权限" >&2 exit 0 fi """ def main() -> int: args = parse_args() git_dir = Path(run_git(["rev-parse", "--git-dir"])) if not git_dir.is_absolute(): git_dir = PROJECT_DIR / git_dir hook_path = git_dir / "hooks" / "post-commit" try: remote_url = run_git(["remote", "get-url", args.remote]) except RuntimeError: remote_url = "" content = hook_text(args.remote) if args.dry_run: print(content) if remote_url: print(f"# remote {args.remote}: {remote_url}") else: print(f"# remote {args.remote}: 未配置") return 0 if hook_path.exists() and not args.force: raise RuntimeError(f"{hook_path} 已存在;如需覆盖,请加 --force") hook_path.parent.mkdir(parents=True, exist_ok=True) hook_path.write_text(content, encoding="utf-8") mode = hook_path.stat().st_mode hook_path.chmod(mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH) print(f"已安装 {hook_path}") if remote_url: print(f"提交后将自动推送到 {args.remote}: {remote_url}") else: print(f"注意:当前尚未配置 remote '{args.remote}',请先设置 Gitea SSH 地址") return 0 if __name__ == "__main__": try: raise SystemExit(main()) except Exception as exc: print(f"安装失败: {exc}", file=sys.stderr) raise SystemExit(1)