Add LFS config and pre-push hook
This commit is contained in:
parent
7a9e8c78bb
commit
bcb7daa62e
6 changed files with 274 additions and 0 deletions
27
.gitattributes
vendored
Normal file
27
.gitattributes
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
# Git LFS 跟踪规则
|
||||||
|
# 提交到每个启用 LFS 的 GitHub 仓库根目录
|
||||||
|
# 策略:按文件类型全覆盖(含小图,可接受此开销)
|
||||||
|
# Issue: OS-GBL-F-002
|
||||||
|
|
||||||
|
# 视频
|
||||||
|
*.mp4 filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.mov filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.avi filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.wmv filter=lfs diff=lfs merge=lfs -text
|
||||||
|
|
||||||
|
# 设计稿
|
||||||
|
*.psd filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.ai filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.sketch filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.fig filter=lfs diff=lfs merge=lfs -text
|
||||||
|
|
||||||
|
# 图片
|
||||||
|
*.png filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.jpg filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.jpeg filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.gif filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.webp filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.tiff filter=lfs diff=lfs merge=lfs -text
|
||||||
|
|
||||||
|
# 如特定仓库需要某类型不走 LFS,在该仓库的 .gitattributes 追加覆盖规则:
|
||||||
|
# *.png -filter -diff -merge
|
||||||
4
.githooks/post-checkout
Executable file
4
.githooks/post-checkout
Executable file
|
|
@ -0,0 +1,4 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# LFS post-checkout passthrough (required when core.hooksPath = .githooks)
|
||||||
|
command -v git-lfs >/dev/null 2>&1 || { git lfs version >/dev/null 2>&1 || exit 0; }
|
||||||
|
git lfs post-checkout "$@"
|
||||||
4
.githooks/post-commit
Executable file
4
.githooks/post-commit
Executable file
|
|
@ -0,0 +1,4 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# LFS post-commit passthrough (required when core.hooksPath = .githooks)
|
||||||
|
command -v git-lfs >/dev/null 2>&1 || { git lfs version >/dev/null 2>&1 || exit 0; }
|
||||||
|
git lfs post-commit "$@"
|
||||||
4
.githooks/post-merge
Executable file
4
.githooks/post-merge
Executable file
|
|
@ -0,0 +1,4 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# LFS post-merge passthrough (required when core.hooksPath = .githooks)
|
||||||
|
command -v git-lfs >/dev/null 2>&1 || { git lfs version >/dev/null 2>&1 || exit 0; }
|
||||||
|
git lfs post-merge "$@"
|
||||||
233
.githooks/pre-push
Executable file
233
.githooks/pre-push
Executable file
|
|
@ -0,0 +1,233 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# LFS Pre-Push Hook — push 前显示 LFS 文件清单并要求确认
|
||||||
|
# Issue: OS-GBL-F-002
|
||||||
|
#
|
||||||
|
# 功能:
|
||||||
|
# 1. 检测本次 push 涉及的 LFS 文件,显示清单和总大小
|
||||||
|
# 2. >500MB 的文件标记警告
|
||||||
|
# 3. 用户确认后执行 git lfs pre-push 上传
|
||||||
|
#
|
||||||
|
# 环境变量:
|
||||||
|
# LFS_PREPUSH_SKIP=1 跳过确认(CI/CD 用)
|
||||||
|
#
|
||||||
|
# 兼容性:POSIX sh + BSD awk(macOS 原生环境)
|
||||||
|
|
||||||
|
REMOTE="$1"
|
||||||
|
URL="$2"
|
||||||
|
|
||||||
|
# --- 捕获 stdin(ref 数据),后续 replay 给 git lfs pre-push ---
|
||||||
|
INPUT=""
|
||||||
|
while IFS= read -r line; do
|
||||||
|
if [ -z "$INPUT" ]; then
|
||||||
|
INPUT="$line"
|
||||||
|
else
|
||||||
|
INPUT="$INPUT
|
||||||
|
$line"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# --- 检查 git-lfs 是否可用 ---
|
||||||
|
if ! command -v git-lfs >/dev/null 2>&1 && ! git lfs version >/dev/null 2>&1; then
|
||||||
|
echo "pre-push: git-lfs not found, skipping LFS check"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- 收集所有 ref 涉及的 LFS 文件 ---
|
||||||
|
LFS_LIST=""
|
||||||
|
|
||||||
|
process_ref() {
|
||||||
|
local_ref="$1"
|
||||||
|
local_sha="$2"
|
||||||
|
remote_ref="$3"
|
||||||
|
remote_sha="$4"
|
||||||
|
|
||||||
|
ZERO="0000000000000000000000000000000000000000"
|
||||||
|
|
||||||
|
# 删除分支 → 跳过
|
||||||
|
if [ "$local_sha" = "$ZERO" ]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 确定比较基准
|
||||||
|
if [ "$remote_sha" = "$ZERO" ]; then
|
||||||
|
# 新分支:找与默认分支的 merge-base
|
||||||
|
base=""
|
||||||
|
for candidate in main master develop; do
|
||||||
|
if git rev-parse --verify "refs/remotes/origin/$candidate" >/dev/null 2>&1; then
|
||||||
|
base=$(git merge-base "refs/remotes/origin/$candidate" "$local_sha" 2>/dev/null)
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ -z "$base" ]; then
|
||||||
|
# 无法找到基准,列出该分支所有 LFS 文件
|
||||||
|
base=""
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
base="$remote_sha"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 获取 LFS 文件列表(带大小)
|
||||||
|
if [ -n "$base" ]; then
|
||||||
|
files=$(git lfs ls-files --size "$base" "$local_sha" 2>/dev/null)
|
||||||
|
else
|
||||||
|
files=$(git lfs ls-files --size "$local_sha" 2>/dev/null)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$files" ]; then
|
||||||
|
LFS_LIST="$LFS_LIST
|
||||||
|
$files"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# 解析每一行 ref 数据
|
||||||
|
if [ -n "$INPUT" ]; then
|
||||||
|
echo "$INPUT" | while IFS=' ' read -r local_ref local_sha remote_ref remote_sha; do
|
||||||
|
if [ -n "$local_ref" ]; then
|
||||||
|
process_ref "$local_ref" "$local_sha" "$remote_ref" "$remote_sha"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 因为上面的 while 在子 shell 中,LFS_LIST 不会传递回来
|
||||||
|
# 重新在当前 shell 处理
|
||||||
|
LFS_LIST=""
|
||||||
|
if [ -n "$INPUT" ]; then
|
||||||
|
set -f # 禁用 glob
|
||||||
|
OLD_IFS="$IFS"
|
||||||
|
IFS='
|
||||||
|
'
|
||||||
|
for line in $INPUT; do
|
||||||
|
IFS="$OLD_IFS"
|
||||||
|
local_ref=$(echo "$line" | awk '{print $1}')
|
||||||
|
local_sha=$(echo "$line" | awk '{print $2}')
|
||||||
|
remote_ref=$(echo "$line" | awk '{print $3}')
|
||||||
|
remote_sha=$(echo "$line" | awk '{print $4}')
|
||||||
|
|
||||||
|
ZERO="0000000000000000000000000000000000000000"
|
||||||
|
|
||||||
|
# 删除分支 → 跳过
|
||||||
|
if [ "$local_sha" = "$ZERO" ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 确定比较基准
|
||||||
|
base=""
|
||||||
|
if [ "$remote_sha" = "$ZERO" ]; then
|
||||||
|
for candidate in main master develop; do
|
||||||
|
if git rev-parse --verify "refs/remotes/origin/$candidate" >/dev/null 2>&1; then
|
||||||
|
base=$(git merge-base "refs/remotes/origin/$candidate" "$local_sha" 2>/dev/null)
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
else
|
||||||
|
base="$remote_sha"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 获取 LFS 文件列表
|
||||||
|
if [ -n "$base" ]; then
|
||||||
|
files=$(git lfs ls-files --size "$base" "$local_sha" 2>/dev/null)
|
||||||
|
else
|
||||||
|
files=$(git lfs ls-files --size "$local_sha" 2>/dev/null)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$files" ]; then
|
||||||
|
LFS_LIST="$LFS_LIST
|
||||||
|
$files"
|
||||||
|
fi
|
||||||
|
|
||||||
|
IFS='
|
||||||
|
'
|
||||||
|
done
|
||||||
|
IFS="$OLD_IFS"
|
||||||
|
set +f
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- 去重并解析 ---
|
||||||
|
# git lfs ls-files --size 输出格式: <oid> <indicator> <path> (<size>)
|
||||||
|
# 示例: abc1234567 * assets/logo.png (1.2 MB)
|
||||||
|
|
||||||
|
if [ -z "$LFS_LIST" ] || [ "$(echo "$LFS_LIST" | sed '/^$/d' | wc -l)" -eq 0 ]; then
|
||||||
|
# 无 LFS 文件 → 静默执行 git lfs pre-push 并放行
|
||||||
|
echo "$INPUT" | git lfs pre-push "$@"
|
||||||
|
exit $?
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 按文件路径去重
|
||||||
|
DEDUPED=$(echo "$LFS_LIST" | sed '/^$/d' | awk '!seen[$3]++')
|
||||||
|
FILE_COUNT=$(echo "$DEDUPED" | wc -l | awk '{print $1}')
|
||||||
|
|
||||||
|
# --- 非 TTY 或 CI 模式 → 自动放行 ---
|
||||||
|
if [ "${LFS_PREPUSH_SKIP:-0}" = "1" ]; then
|
||||||
|
echo "$INPUT" | git lfs pre-push "$@"
|
||||||
|
exit $?
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -t 0 ] && [ ! -t 1 ]; then
|
||||||
|
# 非交互环境,自动放行
|
||||||
|
echo "$INPUT" | git lfs pre-push "$@"
|
||||||
|
exit $?
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- 显示 LFS 文件清单 ---
|
||||||
|
echo ""
|
||||||
|
echo "=========================================="
|
||||||
|
echo " LFS Pre-Push: $FILE_COUNT file(s) detected"
|
||||||
|
echo "=========================================="
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
TOTAL_BYTES=0
|
||||||
|
HAS_LARGE=0
|
||||||
|
|
||||||
|
echo "$DEDUPED" | while IFS= read -r entry; do
|
||||||
|
# 提取路径和大小
|
||||||
|
path=$(echo "$entry" | awk '{print $3}')
|
||||||
|
size_str=$(echo "$entry" | sed 's/.*(\(.*\))/\1/')
|
||||||
|
|
||||||
|
# 解析大小为字节数(用于判断 >500MB)
|
||||||
|
size_num=$(echo "$size_str" | awk '{print $1}')
|
||||||
|
size_unit=$(echo "$size_str" | awk '{print $2}')
|
||||||
|
|
||||||
|
bytes=0
|
||||||
|
case "$size_unit" in
|
||||||
|
B) bytes=$(echo "$size_num" | awk '{printf "%.0f", $1}') ;;
|
||||||
|
KB) bytes=$(echo "$size_num" | awk '{printf "%.0f", $1 * 1024}') ;;
|
||||||
|
MB) bytes=$(echo "$size_num" | awk '{printf "%.0f", $1 * 1048576}') ;;
|
||||||
|
GB) bytes=$(echo "$size_num" | awk '{printf "%.0f", $1 * 1073741824}') ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# 检查是否超过 500MB (524288000 bytes)
|
||||||
|
is_large=$(echo "$bytes" | awk '{if ($1 > 524288000) print 1; else print 0}')
|
||||||
|
|
||||||
|
if [ "$is_large" = "1" ]; then
|
||||||
|
printf " %-50s %s %s\n" "$path" "$size_str" "[!] >500MB"
|
||||||
|
else
|
||||||
|
printf " %-50s %s\n" "$path" "$size_str"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "------------------------------------------"
|
||||||
|
echo " Total: $FILE_COUNT file(s)"
|
||||||
|
echo "------------------------------------------"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# --- 确认提示 ---
|
||||||
|
printf "Proceed with LFS upload? [y/N] "
|
||||||
|
|
||||||
|
# 从 /dev/tty 读取用户输入(因为 stdin 已被 git 占用)
|
||||||
|
if read -r answer < /dev/tty 2>/dev/null; then
|
||||||
|
case "$answer" in
|
||||||
|
[yY]|[yY][eE][sS])
|
||||||
|
echo "Uploading LFS files..."
|
||||||
|
echo "$INPUT" | git lfs pre-push "$@"
|
||||||
|
exit $?
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Push aborted by user."
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
else
|
||||||
|
echo "Cannot read from terminal, aborting."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
2
.lfsconfig
Normal file
2
.lfsconfig
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
[lfs]
|
||||||
|
url = http://silicon:5e2aa6ff8dd2042a65eaaac0e8e5028bf3c99968@100.64.144.118:3000/silicon/lfs-hook-test.git/info/lfs
|
||||||
Loading…
Add table
Reference in a new issue