你能在 Husky “commit-msg” 挂钩期间 git 添加新文件吗?

Par*_*exe 2 javascript git npm husky git-husky

我正在尝试设置一个自动版本控制系统,如果我git commit使用消息PATCH: {message},应用程序的补丁版本将自动更新(同样对于前缀MINORMAJOR)。我使用Husky作为我的pre-commit钩子pre-push,所以我尝试使用.husky/commit-msg如下所示的钩子来实现它:

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npm run auto-version $1 && git add --all
Run Code Online (Sandbox Code Playgroud)

这可以按照需要进行,我的auto-version.js脚本会自动读取提交消息并进行./version.json相应更新。唯一的问题是提交是用旧version.json文件创建的,我不确定为什么。我可以说它git add是有效的,因为提交后我version.json在该部分中留下了更新的文件Staged Changes。我的.husky/pre-commit钩子看起来像这样,并在提交之前暂存更新的文件:

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npm run lint && npm run format && git add --all
Run Code Online (Sandbox Code Playgroud)

commit-msg我认为这可能与钩子被触发和接受新暂存文件之间的时间有关git,但 Husky 没有提供有关钩子如何commit-msg运行的优秀文档。我也尝试使用钩子进行设置pre-commit,但新的提交消息在这个阶段不会被保存.git/COMMIT_EDITMSG(仅存在旧的提交消息)。

对于一些额外的上下文,我们目前只是立即启动npm version patch --no-git-tag-versionpre-commit然后在需要时手动更改次要版本和主要版本。我想制作一个更强大和自动化的系统,这导致了这个拦截器。

自动版本.js
const { readFileSync, writeFileSync } = require('fs');

const versionJsonPath = './version.json';
const commitMessagePath = '.git/COMMIT_EDITMSG';

const prefixOptions = ['PATCH', 'MINOR', 'MAJOR'];
const postfixMinLength = 12;

(() => {
    // read commit message
    const rawMessage = readFileSync(commitMessagePath, 'utf-8');
    const message = rawMessage.split(/\r?\n/)[0];
    console.log(`Reading commit message "${message}"...`);

    // check for merge commit
    if (message.startsWith('Merge branch')) {
        process.exit();
    }

    // check for core composition
    const messageParts = message.split(':');
    if (messageParts.length != 2) {
        throwError(`Commit message should take the form "{${prefixOptions.join('|')}}: {message}".`);
    }

    // check for valid prefix
    const messagePrefix = messageParts[0];
    if (!prefixOptions.includes(messagePrefix)) {
        throwError(`Commit message prefix must be one of the following version types: [${prefixOptions.join(', ')}].`);
    }

    // check for valid postfix
    const messagePostfix = messageParts[1];
    if (messagePostfix.trim().length < postfixMinLength) {
        throwError(`Commit message postfix must be at least ${postfixMinLength} characters.`);
    }

    // update app version
    const versionJson = JSON.parse(readFileSync(versionJsonPath, 'utf-8'));
    const oldVersion = versionJson.appVersion;
    const versionParts = oldVersion.split('.').map(v => parseInt(v, 10));

    if (messagePrefix == 'MAJOR') {
        versionParts[0]++;
        versionParts[1] = 0;
        versionParts[2] = 0;
    } else if (messagePrefix == 'MINOR') {
        versionParts[1]++;
        versionParts[2] = 0;
    } else {
        versionParts[2]++;
    }

    const newVersion = versionParts.join('.');
    versionJson.appVersion = newVersion;

    console.log(`Updating app version from ${oldVersion} to ${newVersion}...`);
    writeFileSync(versionJsonPath, JSON.stringify(versionJson));

    process.exit();
})();

function throwError(message) {
    console.error(message);
    process.exit(1);
}
Run Code Online (Sandbox Code Playgroud)
版本.json
{
    "appVersion": "0.12.15"
}
Run Code Online (Sandbox Code Playgroud)

Par*_*exe 6

查看另一篇文章(Git hook commit-msg git add file),似乎在钩子阶段git add期间/之后不可能执行此操作commit-msgpost-commit根据那里的答案之一,我通过使用钩子修改提交以包含更新后的version.json文件来解决问题git commit --amend -C HEAD -n version.json

.husky/提交后
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npm run auto-version-post-commit
Run Code Online (Sandbox Code Playgroud)

post-commit脚本确保有一个version.json文件要添加以防止无限 git hook 递归:

var exec = require('child_process').exec;

const versionJsonPath = 'version.json';

(() => {
    exec('git diff --name-only', (error, stdout, stderr) => {
        const modifiedFiles = stdout.trim().split(/\r?\n/);

        // check if version.json has been modified by commit-msg hook
        if (modifiedFiles.includes(versionJsonPath)) {
            // amend the last commit to include the updated version.json
            exec(`git commit --amend -C HEAD -n ${versionJsonPath}`);
        }
    });
})();
Run Code Online (Sandbox Code Playgroud)