能否通过Grunt自动检查发布所用源文件的Git状态?
用Grunt自动检查发布源文件的Git提交状态
刚好碰到过类似的痛点——靠人工核对文件提交状态太容易漏,尤其是发布次数多了之后。既然Grunt已经握了所有发布需要的源文件信息,咱们完全可以直接复用这些配置,不用额外维护独立的文件列表,还能跨Windows和Linux用。
核心思路
- 从Grunt的现有任务配置里,把所有要发布的源文件路径提取出来
- 调用Git命令检查这些文件的状态,看看有没有未提交/未跟踪的
- 在发布任务跑起来之前拦截,如果有问题直接终止流程,给你明确提示
具体实现步骤
1. 先装必要的依赖
需要两个工具:grunt-exec用来执行Git命令,glob帮我们解析Grunt里的文件通配符(比如src/**/*.js这种)。执行下面的命令安装:
npm install grunt-exec glob --save-dev
2. 写自定义的Grunt检查任务
在你的Gruntfile.js里加一个check-git-status任务,这个任务会自动读取你现有发布任务的配置,不用你再写一遍文件列表。直接上代码,注释里写清楚了逻辑:
module.exports = function(grunt) { const glob = require('glob'); const path = require('path'); // 工具函数:从Grunt任务配置里提取所有源文件 function getTaskSourceFiles(taskConfig) { let files = []; // 处理Grunt里常见的几种src配置格式 if (typeof taskConfig.src === 'string' || Array.isArray(taskConfig.src)) { const patterns = Array.isArray(taskConfig.src) ? taskConfig.src : [taskConfig.src]; patterns.forEach(pattern => { // 解析通配符,拿到实际的文件路径 files = files.concat(glob.sync(pattern, { cwd: '.' })); }); } else if (taskConfig.files) { // 处理files对象格式的配置(比如copy任务常用的格式) Object.values(taskConfig.files).forEach(fileGroup => { if (fileGroup.src) { const patterns = Array.isArray(fileGroup.src) ? fileGroup.src : [fileGroup.src]; patterns.forEach(pattern => { files = files.concat(glob.sync(pattern, { cwd: '.' })); }); } }); } // 去重并转成绝对路径,避免跨平台的路径格式问题 return [...new Set(files.map(file => path.resolve(file)))]; } // 注册检查Git状态的任务 grunt.registerTask('check-git-status', '确保所有发布用的源文件都已提交到Git', function() { const done = this.async(); // 这里填你实际用来发布的任务名,比如uglify、cssmin、copy这些 const releaseRelatedTasks = ['uglify', 'cssmin', 'copy:html', 'copy:cs']; let allReleaseFiles = []; releaseRelatedTasks.forEach(taskName => { const taskConfig = grunt.config.get(taskName); if (taskConfig) { allReleaseFiles = allReleaseFiles.concat(getTaskSourceFiles(taskConfig)); } }); if (allReleaseFiles.length === 0) { grunt.log.warn('没找到要检查的源文件,确认下发布任务的配置哦'); done(); return; } // 执行Git命令,用grunt.util.spawn兼容Windows和Linux grunt.util.spawn({ cmd: 'git', args: ['status', '--porcelain'], opts: { stdio: 'inherit' } }, function(error, stdout) { if (error) { grunt.fail.fatal(`Git命令执行失败:${error.message}`); done(false); return; } // 解析git status的输出,找出所有未提交/未跟踪的文件 const uncommittedFiles = stdout.trim().split('\n') .filter(line => line.trim() !== '') .map(line => line.split(/\s+/)[1]) .map(file => path.resolve(file)); // 对比咱们要发布的文件,找出没提交的 const missingCommits = allReleaseFiles.filter(file => uncommittedFiles.includes(file)); if (missingCommits.length > 0) { grunt.fail.fatal(`以下发布必需的文件还没提交到Git,请先提交再发布:\n${missingCommits.join('\n')}`); done(false); } else { grunt.log.ok('所有发布用的源文件都已提交,放心继续吧!'); done(); } }); }); // 修改你的发布任务,让它先跑检查再执行发布流程 grunt.registerTask('release', ['check-git-status', 'uglify', 'cssmin', 'copy:html', 'copy:cs', 'build']); };
3. 关键细节说明
- 跨平台兼容:用
grunt.util.spawn执行Git命令,不管是Windows还是Linux都能正常跑,而且git status --porcelain的输出格式在两个系统下是一致的,解析逻辑不用改。 - 完全复用现有配置:直接读取你已经写好的发布任务的src配置,不用再重复维护一份文件列表,以后改发布文件只要改Grunt任务配置就行,检查逻辑自动同步。
- 拦截发布流程:只要有未提交的文件,任务直接失败,不会继续执行发布,从根源上避免遗漏文件的问题。
额外优化小技巧
- 如果有时候需要紧急发布,想跳过这个检查,可以给任务加个跳过参数:
在check-git-status任务开头加这段代码:
然后执行发布的时候用const skipCheck = grunt.option('skip-git-check'); if (skipCheck) { grunt.log.warn('已跳过Git提交状态检查,请注意风险!'); this.async()(); return; }grunt release --skip-git-check就能跳过了。 - 不用担心
.gitignore里的文件,git status --porcelain不会把已忽略的文件算进去,只会检查需要跟踪的文件。
内容的提问来源于stack exchange,提问作者Ferenc Moricz
相关产品推荐
相关产品推荐

