不使用 Husky 和 Lint-staged,实现 Git 提交前自动格式化代码

大家好,我是农村程序员,独立开发者,行业观察员,VSCode 插件批发商,前端之虎陈随易。

我会在这里分享关于 独立开发编程技术思考感悟 等内容,欢迎关注。

技术群与交朋友请在个人网站 👆 联系我,如果你觉得本文有用,一键三连 (点赞评论转发),就是对我最大的支持~


在前端项目中,代码格式化是保证代码质量和团队协作的重要环节。

很多团队使用 husky + lint-staged 来实现 Git 提交前的自动格式化,但这种方案需要安装额外的依赖,增加了项目的复杂度。

本文将介绍如何直接使用 Git 原生的 Hooks 机制,不依赖任何第三方库,实现同样的功能。

为什么不用 Husky?

传统方案的问题

使用 husky + lint-staged 的典型配置:

json 复制代码
{
    "devDependencies": {
        "husky": "^9.0.0",
        "lint-staged": "^15.0.0",
        "prettier": "^3.0.0"
    },
    "scripts": {
        "prepare": "husky install"
    },
    "lint-staged": {
        "*.{js,ts,jsx,tsx}": "prettier --write"
    }
}

缺点:

  1. 需要安装多个依赖包(husky、lint-staged)
  2. 需要额外的配置文件(.husky 目录)
  3. 团队成员克隆项目后需要运行 npm install 才能启用 hooks
  4. 依赖包的版本更新可能带来兼容性问题

原生方案的优势

直接使用 Git Hooks:

  1. 零依赖 - 只需要 prettier(或其他格式化工具)
  2. 简单直接 - 一个 shell 脚本文件即可
  3. 性能更好 - 没有额外的 Node.js 进程启动开销
  4. 完全控制 - 可以自定义任何逻辑

Git Hooks 基础知识

什么是 Git Hooks?

Git Hooks 是 Git 在特定事件(如提交、推送等)发生时自动执行的脚本。这些脚本存放在项目的 .git/hooks/ 目录下。

常用的 Hooks:

  • pre-commit - 提交前执行(本文重点)
  • commit-msg - 提交信息验证
  • pre-push - 推送前执行
  • post-merge - 合并后执行

为什么 .git/hooks/ 不在版本控制中?

.git/ 目录默认不被 Git 跟踪,所以 .git/hooks/ 中的脚本无法通过 Git 共享给团队成员

这也是 husky 存在的主要原因之一 - 它通过在 package.json 中配置,让团队成员在 npm install 时自动设置 hooks。

如何分享 Git Hooks?

有几种方法:

  1. 文档说明 - 在 README 中说明如何手动复制脚本
  2. 初始化脚本 - 提供一个设置脚本,团队成员运行一次即可
  3. Git 2.9+ 的 core.hooksPath - 将 hooks 目录设置为可追踪的路径

实现方案

直接修改 .git/hooks/pre-commit

创建 pre-commit 脚本

.git/hooks/pre-commit 文件中写入以下内容:

bash 复制代码
#!/usr/bin/env sh
# Git pre-commit hook - 自动格式化暂存的文件

echo "正在检查暂存文件..."

# 获取所有暂存的文件(只包括添加和修改的文件)
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(js|ts|jsx|tsx|vue|json|md|yaml|yml|css|scss|less|html)$')

if [ -z "$STAGED_FILES" ]; then
    echo "没有需要格式化的文件"
    exit 0
fi

echo "正在格式化以下文件:"
echo "$STAGED_FILES"

# 将文件列表转换为数组并逐个格式化
echo "$STAGED_FILES" | while IFS= read -r file; do
    if [ -f "$file" ]; then
        bunx prettier --write "$file"
        git add "$file"
    fi
done

echo "✓ 代码格式化完成"
exit 0

安装 Prettier

只需要一个依赖:

bash 复制代码
npm install -D prettier
# 或
bun add -d prettier

测试

创建一个格式不规范的测试文件:

javascript 复制代码
// test.js
const obj = { a: 1, b: 2, c: 3 };
const fn = (x, y) => {
    return x + y;
};
console.log(obj);

提交文件:

bash 复制代码
git add test.js
git commit -m "测试自动格式化"

Hook 会自动运行,输出类似:

csharp 复制代码
正在检查暂存文件...
正在格式化以下文件:
test.js
test.js 24ms
✓ 代码格式化完成
[main abc1234] 测试自动格式化
 1 file changed, 3 insertions(+)

查看格式化后的文件:

javascript 复制代码
// test.js - 已格式化
const obj = { a: 1, b: 2, c: 3 };
const fn = (x, y) => {
    return x + y;
};
console.log(obj);

高级用法

支持多种格式化工具

bash 复制代码
#!/usr/bin/env sh

echo "正在格式化代码..."

STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM)

# JavaScript/TypeScript 文件使用 Prettier
JS_FILES=$(echo "$STAGED_FILES" | grep -E '\.(js|ts|jsx|tsx)$')
if [ -n "$JS_FILES" ]; then
    echo "$JS_FILES" | xargs bunx prettier --write
    echo "$JS_FILES" | xargs git add
fi

# CSS/SCSS 文件使用 stylelint
CSS_FILES=$(echo "$STAGED_FILES" | grep -E '\.(css|scss)$')
if [ -n "$CSS_FILES" ]; then
    echo "$CSS_FILES" | xargs bunx stylelint --fix
    echo "$CSS_FILES" | xargs git add
fi

# Python 文件使用 black
PY_FILES=$(echo "$STAGED_FILES" | grep -E '\.py$')
if [ -n "$PY_FILES" ]; then
    echo "$PY_FILES" | xargs black
    echo "$PY_FILES" | xargs git add
fi

echo "✓ 格式化完成"
exit 0

添加 ESLint 检查

bash 复制代码
#!/usr/bin/env sh

echo "正在检查代码..."

STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(js|ts|jsx|tsx)$')

if [ -z "$STAGED_FILES" ]; then
    exit 0
fi

# 先格式化
echo "$STAGED_FILES" | xargs bunx prettier --write
echo "$STAGED_FILES" | xargs git add

# 再进行 ESLint 检查
echo "运行 ESLint..."
echo "$STAGED_FILES" | xargs bunx eslint

# 如果 ESLint 失败,阻止提交
if [ $? -ne 0 ]; then
    echo "❌ ESLint 检查失败,请修复错误后再提交"
    exit 1
fi

echo "✓ 检查通过"
exit 0

只格式化改动的部分(增量格式化)

对于大型项目,可以使用 prettier--check 选项先检查,只格式化需要修改的文件:

bash 复制代码
#!/usr/bin/env sh

STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(js|ts|jsx|tsx)$')

if [ -z "$STAGED_FILES" ]; then
    exit 0
fi

echo "检查文件格式..."

# 先检查哪些文件需要格式化
NEED_FORMAT=$(echo "$STAGED_FILES" | xargs bunx prettier --list-different)

if [ -n "$NEED_FORMAT" ]; then
    echo "正在格式化以下文件:"
    echo "$NEED_FORMAT"

    # 只格式化需要的文件
    echo "$NEED_FORMAT" | xargs bunx prettier --write
    echo "$NEED_FORMAT" | xargs git add

    echo "✓ 格式化完成"
else
    echo "所有文件格式正确,无需格式化"
fi

exit 0

性能对比

Husky + Lint-staged

bash 复制代码
# 启动时间
$ time git commit -m "test"
real    0m2.341s  # 包括 Node.js 启动、lint-staged 初始化等
user    0m1.234s
sys     0m0.567s

原生 Git Hooks

bash 复制代码
# 启动时间
$ time git commit -m "test"
real    0m0.482s  # 仅 shell 脚本 + prettier 执行
user    0m0.123s
sys     0m0.089s

性能提升约 4-5 倍

总结

何时使用原生 Git Hooks?

适合的场景:

  • 小型团队或个人项目
  • 追求最小依赖和简洁配置
  • 对性能有要求的项目
  • 团队成员都熟悉 Git Hooks

不适合的场景:

  • 需要复杂的 hook 管理(多个 hooks,条件执行等)
  • 团队成员对 Git Hooks 不熟悉
  • 需要跨平台的复杂逻辑

何时使用 Husky?

适合的场景:

  • 大型团队项目
  • 需要管理多个 Git Hooks
  • 团队成员水平参差不齐
  • 需要开箱即用的解决方案

最终建议

对于大多数项目,我推荐:

  1. 开发阶段 - 使用原生 Git Hooks(简单、快速)
  2. 生产项目 - 如果团队较大,可以考虑 Husky(更容易管理)
  3. 两者结合 - 保留原生 hooks 的简洁性,通过文档和脚本帮助团队成员设置

希望这篇文章能帮助你摆脱对第三方 hooks 库的依赖,用最简单的方式实现代码自动格式化!


🔥 我的 VSCode 扩展商店:

👉 点击访问

相关推荐
前端大卫几秒前
如何统一前端项目的 Node 版本和包管理器?
前端
咖啡教室15 分钟前
每日一个计算机小知识:ICMP
后端·网络协议
间彧15 分钟前
OpenStack在混合云架构中通常扮演什么角色?
后端
咖啡教室19 分钟前
每日一个计算机小知识:IGMP
后端·网络协议
间彧21 分钟前
云原生技术栈中的核心组件(如Kubernetes、Docker)具体是如何协同工作的?
后端
清空mega30 分钟前
从零开始搭建 flask 博客实验(3)
后端·python·flask
Hi~晴天大圣32 分钟前
HTML onclick用法
前端·html
努力的小郑1 小时前
Elasticsearch 避坑指南:我在项目中总结的 14 条实用经验
后端·elasticsearch·性能优化
August_._1 小时前
【MySQL】SQL语法详细总结
java·数据库·后端·sql·mysql·oracle
间彧1 小时前
云原生,与云计算、云服务的区别与联系
后端