不使用 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 扩展商店:

👉 点击访问

相关推荐
程序员小寒1 天前
前端高频面试题之Vue(高级篇)
前端·javascript·vue.js
YDS8291 天前
苍穹外卖 —— Spring Task和WebSocket的运用以及订单统一处理、订单的提醒和催单功能的实现
java·spring boot·后端·websocket·spring
m0_639817151 天前
基于springboot纺织品企业财务管理系统【带源码和文档】
java·服务器·前端
石小石Orz1 天前
qinkun的缓存机制也有弊端,建议官方个参数控制
前端
q***31831 天前
Spring Boot(快速上手)
java·spring boot·后端
用户4099322502121 天前
Vue浅响应式如何解决深层响应式的性能问题?适用场景有哪些?
前端·ai编程·trae
CC码码1 天前
重生之我在浏览器里“蹦迪”
前端·javascript·three.js
爱分享的鱼鱼1 天前
Java进阶(二:Maven——Java项目管理工具)
后端
阡陌昏晨1 天前
H5性能优化-打开效率提升了62%
前端·javascript·vue.js
鹏北海1 天前
TypeScript 类型工具与 NestJS Mapped Types
前端·后端·typescript