Git Hooks实战:提交前检查修改文件中是否包含调试代码

说在前面

不知道大家有没有遇到这样一种情况,平时在写代码调试时有时候会使用到debugger,可能大部分时间在提交代码前会记得把debugger先删除,但可能也会存在将debugger提交上去的情况,那我们该怎么防止出现这种情况呢?

webpack 配置修改

开发过程中,经常需要使用console.logconsole.infoalert等操作来输出内容,测试代码,而在生产环境之中,这些打印的东西最好是不要显示、特别是用户名、密码相关。

一个个去删除、注释显然是很麻烦的一件事,所以我们可以通过修改配置变量,实现在开发环境打印,而生产环境不打印。

修改方法如下:
在项目的build/webpack.prod.conf.js文件之中,找到UglifyJsPlugin配置,在compress中添加如下代码即可。

new UglifyJsPlugin({uglifyOptions: { compress: { warnings: false, // 打包的时候移除console、debugger drop_debugger: true, // 移除debugger drop_console: true, // 移除console pure_funcs: ['console.log','console.info']}},sourceMap: config.build.productionSourceMap,parallel: true
}),

git hook监测删除

除了直接在webpack中配置之外,我们还可以在git提交前进行监测,将修改文件中的相关语句清除,这里以清除修改文件中的debugger语句为例子:

git hook简单了解

Git钩子是一组脚本,这些脚本对应着Git仓库中的特定事件,每一次事件发生时,钩子会被触发。这允许你可以定制化Git的内部行为,在开发周期中的关键点上触发执行定制化的脚本。

image.png

钩子脚本文件通常放置于项目目录的.git/hooks文件夹下。Git会在初始化项目时自动在这个文件夹下放置一些样例脚本。如果你查看.git/hooks文件夹下,会找到如下的文件:

image.png

我们可以简单了解一下这些钩子的触发时机:

  • applypatch-msg

这个钩子由git-am调用。它接受一个参数,即保存提议的提交日志消息的文件的名称。以非零状态退出导致git am在应用补丁之前中止。

允许钩子就地编辑消息文件,并可用于将消息规范化为某种项目标准格式。它还可以用于在检查消息文件后拒绝提交。

默认的applypatch-msg钩子在启用时,如果启用了commit-msg钩子,则运行commit-msg钩子。

  • commit-msg

这个钩子由git-commitgit-merge调用,可以通过——no-verify选项绕过。它接受一个参数,即保存提议的提交日志消息的文件的名称。以非零状态退出将导致命令中止。

允许钩子就地编辑消息文件,并可用于将消息规范化为某种项目标准格式。它还可以用于在检查消息文件后拒绝提交。

默认的commit-msg钩子在启用时,会检测到重复的挂件签到,如果发现了,就会中止提交。

  • fsmonitor-watchman

这个钩子在配置选项核心时被调用。根据要使用的钩子的版本,Fsmonitor被设置为.git/hooks/ Fsmonitor -watchman或.git/hooks/ Fsmonitor -watchmanv2。

Version 1有两个参数,一个是Version(1),另一个是自1970年1月1日午夜以来经过的纳秒时间。

Version 2有两个参数,一个是Version(2),另一个是token(用于标识token之后的更改)。对于守望者来说,这是一个时钟id。这个版本必须在文件列表之前向stdout输出新的令牌,后跟一个NUL。

钩子应该向stdout输出工作目录中自请求时间以来可能发生更改的所有文件的列表。逻辑应该是包容性的,这样它就不会错过任何潜在的更改。这些路径应该是相对于工作目录的根目录的,并由单个NUL分隔。

包含实际上没有更改的文件是可以的。应该包括所有更改,包括新创建和删除的文件。当重命名文件时,应该同时包含旧的和新的名称。

Git将根据给定的路径名限制检查更改的文件,以及检查未跟踪文件的目录。

告诉git“所有文件都已更改”的一种优化方法是返回文件名/。

退出状态决定git是否会使用来自钩子的数据来限制它的搜索。如果出现错误,它将退回到验证所有文件和文件夹。

  • post-update

git-receive-pack响应git push并更新其存储库中的引用时,会调用该钩子。当所有引用都被更新后,它会在远程存储库上执行一次。

它接受可变数量的参数,每个参数都是实际更新的ref的名称。

这个钩子主要用于通知,不会影响git receive-pack的结果。

post-update钩子可以告诉我们被推送的头是什么,但它不知道它们的原始值和更新值是什么,所以这是一个糟糕的地方。post-receive钩子获取ref的原始值和更新后的值。如果你需要的话,你可以考虑一下。

当启用时,默认的post-update钩子会运行git update-server-info来保持哑传输(例如HTTP)使用的信息是最新的。如果你要发布一个可以通过HTTP访问的Git存储库,你应该启用这个钩子。

标准输出和标准错误输出都被转发到另一端的git send-pack,因此您可以简单地为用户回显消息。

  • pre-commit

这个钩子由git-commit调用,可以通过——no-verify选项绕过。它不接受任何参数,在获得建议的提交日志消息并进行提交之前调用。以非零状态退出该脚本会导致git commit命令在创建提交之前终止。

默认的预提交钩子在启用时,会捕获带有尾随空格的行,并在找到这样的行时中止提交。

所有的git提交钩子都是用环境变量GIT_EDITOR=:来调用的,如果这个命令不会调出一个编辑器来修改提交消息。

默认的预提交钩子(当启用时)和钩子。allownonascii配置选项取消设置或设置为false -防止使用非ascii文件名。

  • pre-merge-commit

这个钩子由git-merge调用,可以用——no-verify选项绕过。它不接受任何参数,并且在成功执行合并之后,在获得建议的提交日志消息以进行提交之前调用。以非零状态退出该脚本会导致git merge命令在创建提交之前终止。

默认的预合并提交钩子在启用时,如果启用了预提交钩子,则运行预提交钩子。

如果该命令不会调出编辑器来修改提交消息,则使用环境变量GIT_EDITOR=:调用该钩子。

如果合并不能自动执行,则需要解决冲突并单独提交结果(参见git-merge[1])。此时,此钩子将不会被执行,但如果启用了预提交钩子,则会执行。

  • prepare-commit-msg

这个钩子被git-commit调用,在准备默认日志消息之后,在编辑器启动之前。

它需要一到三个参数。第一个是包含提交日志消息的文件的名称。第二个是提交消息的来源,可以是:message(如果给出了-m或-F选项);模板(如果给出了-t选项或配置选项commit)。模板设置);merge(如果提交是merge或者.git/MERGE_MSG文件存在);(如果.git/SQUASH_MSG文件存在);或commit,后跟提交对象名称(如果给出了-c、-c或——amend选项)。

如果退出状态非零,git commit将中止。

钩子的目的是就地编辑消息文件,它不会被——no-verify选项抑制。非零退出意味着钩子失败并终止提交。它不应该被用作预提交钩子的替代品。

Git附带的样例prepare-commit-msg钩子删除了提交模板注释部分中的帮助消息。

  • pre-push

这个钩子由git-push调用,可以用来阻止push的发生。钩子是用两个参数调用的,这两个参数提供了目标远程的名称和位置,如果没有使用命名的远程,两个值将是相同的。

关于要推送的内容的信息在钩子的标准输入中提供,格式如下:

<local ref> SP <local object name> SP <remote ref> SP <remote object name> LF
例如,如果命令git push origin master:foreign被运行,钩子会收到像下面这样的一行:

参考/头/主67890参考/头/外12345
尽管将提供完整的对象名称。如果外部ref还不存在,<远程对象名>将是全零对象名。如果要删除一个ref, <local ref>将作为(delete)提供,<local object name>将是全零对象名称。如果本地提交不是由可以扩展的名称(例如HEAD~,或者对象名称)指定的,那么它将按照最初给出的方式提供。

如果这个钩子以非零状态退出,git push将不推送任何东西而中止。关于拒绝推送的原因的信息可以通过写入标准错误发送给用户。

  • pre-rebase

这个钩子由git-rebase调用,可以用来防止分支被rebase。钩子可以带一个或两个参数调用。第一个参数是序列分叉的上游。第二个参数是正在重基的分支,在重基当前分支时不设置。

  • pre-receive

当git-receive-pack响应git push并更新其存储库中的引用时,会调用该钩子。就在开始更新远程存储库上的引用之前,调用预接收钩子。其退出状态决定了更新的成功或失败。

这个钩子执行一次接收操作。它不接受任何参数,但对于每个要更新的ref,它会在标准输入中接收一行格式如下:

SP <new-value> SP <ref-name> LF
其中<old-value>是存储在ref中的旧对象名称,<new-value>是存储在ref中的新对象名称,<ref-name>是ref的全名。创建新ref时,<old-value>是全零对象名称。

如果钩子以非零状态退出,则不会更新任何引用。如果钩子以0退出,更新钩子仍然可以阻止更新单个引用。

标准输出和标准错误输出都被转发到另一端的git send-pack,因此您可以简单地为用户回显消息。

git push命令行给出的push选项数——push-option=…可以从环境变量GIT_PUSH_OPTION_COUNT中读取,选项本身在GIT_PUSH_OPTION_0, GIT_PUSH_OPTION_1,…中找到,如果协商不使用推送选项阶段,则不会设置环境变量。如果客户端选择使用推送选项,但不传输任何选项,则计数变量将被设置为零,GIT_PUSH_OPTION_COUNT=0。

有关一些注意事项,请参阅gift -receive-pack中的“隔离环境”一节。

  • push-to-checkout

git-receive-pack响应git push并更新其存储库中的引用时,以及当push尝试更新当前签出的分支并且receive.denyCurrentBranch配置变量设置为updateInstead时,该钩子被git-receive- receive-pack调用。默认情况下,如果工作树和远程存储库的索引与当前签出的提交有任何差异,则拒绝这样的推送;当工作树和索引都匹配当前提交时,它们将被更新以匹配新推送的分支尖端。此钩子将用于覆盖默认行为。

钩子接收当前分支的尖端将被更新的提交。它可以以非零状态退出以拒绝推送(当它这样做时,它不能修改索引或工作树)。或者,它可以对工作树和索引进行任何必要的更改,使它们在当前分支的尖端更新到新提交时达到所需的状态,并以零状态退出。

例如,钩子可以简单地运行git read-tree -u -m HEAD "$1",以模拟git fetchgit push相反的方向运行,因为git read-tree -u -m的两树形式本质上与git switchgit checkout相同,它们在切换分支的同时保持工作树中的本地更改,而不会干扰分支之间的差异。

  • update

git-receive-pack响应git push并更新其存储库中的引用时,会调用该钩子。就在更新远程存储库上的ref之前,调用更新钩子。它的退出状态决定了refupdate的成功或失败。

对于每个要更新的ref,钩子执行一次,并接受三个参数:

被更新的ref的名称,

旧的对象名称存储在ref,

以及要存储在ref中的新对象名称。

update钩子的零退出允许更新ref。以非零状态退出会阻止git receive-pack更新该ref。

这个钩子可以用来防止某些refs上的强制更新,通过确保对象名称是一个提交对象,是由旧对象名称命名的提交对象的后代。也就是说,执行“仅快进”策略。

它也可以用来记录新旧状态。然而,它并不知道分支的全部集合,因此在天真地使用时,它最终会为每个ref发送一封电子邮件。post-receive钩子更适合于此。

在限制用户只能通过网络访问git命令的环境中,这个钩子可以用来实现访问控制,而不依赖于文件系统所有权和组成员关系。请参阅git-shell[1]了解如何使用登录shell来限制用户只能访问git命令。

标准输出和标准错误输出都被转发到另一端的git send-pack,因此您可以简单地为用户回显消息。

默认的更新钩子,当启用时——并且带有钩子。允许unannotated配置选项unset或设置为false -防止未注释的标签被推送。

完整钩子说明,请参考官网链接

脚本逻辑

1、声明脚本运行环境

这里我们使用node进行编写,所以脚本运行环境应该声明为node

#!/usr/bin/env node
2、获取当前暂存更改的文件信息

我们可以使用git status来获取当前暂存更改的文件目录,但部分同学可能会出现获取到的文件名中文只显示字符串的情况:

image.png

  • 原因

在默认设置下,中文文件名在工作区状态输出,中文名不能正确显示,而是显示为八进制的字符编码。

  • 解决办法

将git 配置文件 core.quotepath项设置为false。
quotepath表示引用路径
加上–global表示全局配置

git bash 终端输入命令:

git config --global core.quotepath false

image.png

我们可以看到修改过的文件路径。

3、提取 git status 信息中的变动文件路径

上一步我们知道了可以使用git status命令来获取暂存更改的文件信息,但获取到的信息并不是直接得到变动的文件路径,我们需要从获取到的信息中的变动文件路径。

let commitFile = child_process.execSync(command).toString();
commitFile = commitFile.split("\n");
console.log("commitFile: ", commitFile);

image.png

这里前面的五行其实是固定的,我们只需要从第六行开始获取即可,文件路径与变更类型描述是通过:隔开,所以我们分割一下:,再将一些特殊字符去掉即可。

const child_process = require("child_process");
const trimReg = /(\ +)|([ ])|([\r\n]|(["]))/g;
const fileList = [];
for (let i = 5; i < commitFile.length; i++) {const name = commitFile[i].split(":")[1];if (!name) break;fileList.push(decodeURI(name.replace(trimReg, "")));
}
console.log("fileList: ", fileList);

image.png

4、判断文件中是否包含 debugger

通过readFileSync获取文件内容,判断文件内容是否包含debugger,包括的话将文件路径记录并将文件中的debugger全部删除,然后再将修改后的文件重新git add -文件路径提交即可。

const child_process = require("child_process");
const fs = require("fs");
const editFiles = [];
fileList.forEach((file) => {const txt = fs.readFileSync(file, "utf8");if (txt.includes("debugger")) {editFiles.push(file);fs.writeFileSync(file, txt.replace(/(debugger);?(\s*\n)*/g, ""));const commandAdd = "git add " + file;child_process.execSync(commandAdd).toString();}
});
console.log("editFiles: ", editFiles);
console.log("已清除提交文件中的 debugger");

完整代码

#!/usr/bin/env node
const child_process = require("child_process");
const fs = require("fs");
const command = "git status";
const trimReg = /(\ +)|([ ])|([\r\n]|(["]))/g;
let commitFile = child_process.execSync(command).toString();
commitFile = commitFile.split("\n");
const fileList = [];
for (let i = 5; i < commitFile.length; i++) {const name = commitFile[i].split(":")[1];if (!name) break;fileList.push(decodeURI(name.replace(trimReg, "")));
}
const editFiles = [];
fileList.forEach((file) => {const txt = fs.readFileSync(file, "utf8");if (txt.includes("debugger")) {editFiles.push(file);fs.writeFileSync(file, txt.replace(/(debugger);?(\s*\n)*/g, ""));const commandAdd = "git add " + file;child_process.execSync(commandAdd).toString();}
});
console.log("editFiles: ", editFiles);
console.log("已清除提交文件中的 debugger");
process.exit(0);

参考材料

https://zhuanlan.zhihu.com/p/521707440

https://git-scm.com/docs/githooks

源码地址

gitee

https://gitee.com/zheng_yongtao/jyeontu-templates.git

公众号

关注公众号『前端也能这么有趣』,获取更多新鲜内容。

说在后面

🎉 这里是 JYeontu,现在是一名前端工程师,有空会刷刷算法题,平时喜欢打羽毛球 🏸 ,平时也喜欢写些东西,既为自己记录 📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解 🙇,写错的地方望指出,定会认真改进 😊,偶尔也会在自己的公众号『前端也能这么有趣』发一些比较有趣的文章,有兴趣的也可以关注下。在此谢谢大家的支持,我们下文再见 🙌。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/190912.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

css如何设置文本添加下划线

css文本添加下划线 text-decoration: underline;text-decoration相关属性参数 参数描述none默认。定义标准的文本。underline定义文本下的一条线。overline定义文本上的一条线。line-through定义穿过文本下的一条线。blink定义闪烁的文本。inherit规定应该从父元素继承 text-…

享元设计模式

package com.jmj.pattern.flyweight;public abstract class AbstractBox {//获取图形的方法public abstract String getShape();//显示图形及颜色public void diplay(String color){System.out.println("方块形状:"getShape()",颜色:"color);}}package com…

基于SpringBoot实现SSMP整合

&#x1f648;作者简介&#xff1a;练习时长两年半的Java up主 &#x1f649;个人主页&#xff1a;程序员老茶 &#x1f64a; ps:点赞&#x1f44d;是免费的&#xff0c;却可以让写博客的作者开心好久好久&#x1f60e; &#x1f4da;系列专栏&#xff1a;Java全栈&#xff0c;…

23.Python 图形化界面编程

目录 1.认识GUI和使用tkinter2.使用组件2.1 标签2.2 按钮2.3 文本框2.4 单选按钮和复选按钮2.5 菜单和消息2.6 列表框2.7 滚动条2.8 框架2.9 画布 3. 组件布局4.事件处理 1.认识GUI和使用tkinter 人机交互是从人努力适应计算机&#xff0c;到计算机不断适应人的发展过程&#…

[ 蓝桥杯Web真题 ]-年度明星项目

目录 引入 介绍 准备 目标 效果 规定 思路 知识补充 解答参考 引入 hello&#xff0c;大家好&#xff01;我注意到了之前发的一篇蓝桥杯Web应用开发的文章是关注度最高的&#xff0c;可能大部分关注我的小伙伴对蓝桥杯Web应用开发比较感兴趣&#xff0c;或者想要参加…

Flink(九)【时间语义与水位线】

前言 2023-12-02-20:05&#xff0c;终于写完啦&#xff0c;最近状态不错。刚写完又收到了她的消息哈哈哈哈&#xff0c;开心。 再去全力打拼一次&#xff0c;奋战一场&#xff0c;就算最后打了败仗也无所谓&#xff0c;至少你留下了足迹。 《解忧杂货店》 1、时间语义 …

出口贸易媒体发稿7种方法提升转化率的秘密武器解析-华媒舍

出口贸易成为了许多企业发展的重要方向。在这个竞争激烈的市场中&#xff0c;如何让自己的产品脱颖而出&#xff0c;吸引更多客户并提高转化率&#xff0c;成为了每个企业家都面临的挑战。本文将向大家介绍7种提升转化率的秘密武器&#xff1a;出口贸易媒体发稿方法。 1. 出口贸…

LeetCode刷题---合并两个有序链表

个人主页&#xff1a;元清加油_【C】,【C语言】,【数据结构与算法】-CSDN博客 个人专栏&#xff1a;http://t.csdnimg.cn/ZxuNL http://t.csdnimg.cn/c9twt 前言&#xff1a;这个专栏主要讲述递归递归、搜索与回溯算法&#xff0c;所以下面题目主要也是这些算法做的 我讲述…

基于深度学习的肺炎CT图像检测诊断系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 深度学习在肺炎CT图像检测诊断方面具有广泛的应用前景。以下是关于肺炎CT图像检测诊断系统的介绍&#xff1a; 任务…

基于PHP的高中生物学习平台

有需要请加文章底部Q哦 可远程调试 基于PHP的高中生物学习平台 一 介绍 此高中生物学习平台基于原生PHP开发&#xff0c;数据库mysql。系统角色分为用户和管理员。(附带参考设计文档) 技术栈&#xff1a;phpmysqlphpstudyvscode 二 功能 学生 1 注册/登录/注销 2 个人中心 …

人工智能时代:AIGC的横空出世

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;数据结构、网络奇遇记 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 &#x1f4cb;前言一. 什么是AIGC?二. AIGC的主要特征2.1 文本生成2.2 图像生成2.3 语音生成2.4 视…

蓝桥杯第198题 人物相关性分析 C++ 模拟 字符串 双指针

题目 思路和解题方法 程序首先定义了一个函数check&#xff0c;用于判断一个字符是否为字母。接下来&#xff0c;程序读取输入的整数k和一行字符串str。定义了两个空的向量a和b&#xff0c;用于存储满足条件的子串的起始位置。使用for循环遍历字符串str的每个字符&#xff0c;检…

string的模拟

> 作者简介&#xff1a;დ旧言~&#xff0c;目前大二&#xff0c;现在学习Java&#xff0c;c&#xff0c;c&#xff0c;Python等 > 座右铭&#xff1a;松树千年终是朽&#xff0c;槿花一日自为荣。 > 目标&#xff1a;能手撕模拟string类 > 毒鸡汤&#xff1a;时间…

MySQL-视图

一、&#xff1f;看一个需求 emp表的列信息很多&#xff0c;有些信息是个人重要信息(比如 sal,comm,mgr,hiredate),如果我们希望某个用户只能查询emp表的(empno、ename,job和deptno)信息,有什么办法? 》视图 二、基本概念 视图 视图是一个虚拟表&#xff0c;其内容由查…

Linux基础项目开发1:量产工具——UI系统(五)

前言&#xff1a; 前面我们已经把显示系统、输入系统、文字系统搭建好了&#xff0c;现在我们就要给它实现按钮操作了&#xff0c;也就是搭建UI系统&#xff0c;下面让我们一起实现UI系统的搭建吧 目录 一、按钮数据结构抽象 ui.h 二、按键编程 1.button.c 2.disp_manager…

查找算法及哈希表

1 二分查找 1.1 重要概念 拟解决的问题&#xff1a;判断某个区间是否包含某个元素&#xff0c;无法确定区间中包含重复元素的具体位置&#xff1b;使用条件&#xff1a;查找的区间必须符合单调性&#xff1b;本质&#xff1a;采用分治思想&#xff0c;将某个单调区间一分为二…

12.2_黑马Redis实战篇附近商铺用户签到UV统计

实战篇11 实战篇12 要先用test的方式把商铺的数据导入到idea当中&#xff0c;才可以进行查询噢。 代码&#xff1a; 实战篇13 thinking&#xff1a;插件mavenhelper&#xff1f; 方便处理pom文件。 实战篇15 实战篇16 thinking&#xff1a;XX.format(DateTimeFormatter.ofP…

【网络安全技术】实体认证技术Kerberos

一、什么是Kerberos Kerberos解决的是客户端与服务器通信场景中&#xff0c;确保客户端服务器双方的身份可信&#xff0c;并提供对称密钥的分发来加密传输。是一个应用层的协议。 二、一个简单的模型 1.看这个基础的模型&#xff0c;客户端要和服务器通信&#xff0c;他先将自…

《堆》的模拟实现

目录 前言&#xff1a; 模拟实现《堆》&#xff1a; 1.自定义数据类型 2.初始化“堆” 3.销毁“堆” 4.进“堆” 关于AdjustUp() 5.删除堆顶元素 关于AdjustDown() 6.判断“堆”是否为空 7.求“堆”中的数据个数 8.求“堆”顶元素 总结&#xff1a; 前言&#xf…

DOM 事件的传播机制

前端面试大全DOM 事件的传播机制 &#x1f31f;经典真题 &#x1f31f;事件与事件流 事件流 事件冒泡流 事件捕获流 标准 DOM 事件流 &#x1f31f;事件委托 &#x1f31f;真题解答 &#x1f31f;总结 &#x1f31f;经典真题 谈一谈事件委托以及冒泡原理 &#x1f3…