Skip to content

Instantly share code, notes, and snippets.

@emilio-martinez
Last active September 19, 2023 18:04
Show Gist options
  • Save emilio-martinez/660df7609583f4a7c7f4fc87ad110770 to your computer and use it in GitHub Desktop.
Save emilio-martinez/660df7609583f4a7c7f4fc87ad110770 to your computer and use it in GitHub Desktop.
npx-git-diff-name-status

This script calls git diff --name-status and optionally adds --diff-filter when using --filter.

Examples: npx ./index.js v1.0.0 npx ./index.js v1.0.0 --filter mr

An argument of <revision>, <revision>..<revision>, or <revision>...<revision> is required to pass to git diff. See https://git-scm.com/docs/git-diff for more info.

--filter argument expects a value containing any of the following:

  • Added (A)
  • Copied (C)
  • Deleted (D)
  • Modified (M)
  • Renamed (R)
  • Type (i.e. regular file, symlink, submodule, …​) changed (T)
  • Unmerged (U)
  • Unknown (X)
  • Pairing Broken (B)

For example, pass 'ad' to exclude added and deleted results. See 'diff-filter' documentation on https://git-scm.com/docs/git-diff for more info.

#!/usr/bin/env node
const argv = require('minimist')(process.argv.slice(2), {
string: ['filter']
});
const chalk = require('chalk');
const exec = require('child_process').exec;
const FILTER_REGEXP = /^[ACDMRTUXB]*$/i;
const ADDED_REGEXP = /^(A.*)$/gm;
const DELETED_REGEXP = /^(D.*)$/gm;
const MODIFIED_REGEXP = /^(M.*)$/gm;
const RENAMED_REGEXP = /^([R|C].*)$/gm;
const help = !!argv.help;
const revisions = argv._ && typeof argv._[0] === 'string' && argv._[0].length > 0 ? argv._[0] : null;
const filter = argv.filter === undefined ? '' : FILTER_REGEXP.test(argv.filter) ? argv.filter : null;
const callHelpMsg = `
Call this script with \`--help\` to see all options.`;
const revisionsMsg = `
An argument of \`<revision>\`, \`<revision>..<revision>\`, or \`<revision>...<revision>\` is required to pass to \`git diff\`.
See https://git-scm.com/docs/git-diff for more info.`
const filterMsg = `
\`--filter\` argument expects a value containing any of the following:
- Added (A)
- Copied (C)
- Deleted (D)
- Modified (M)
- Renamed (R)
- Type (i.e. regular file, symlink, submodule, …​) changed (T)
- Unmerged (U)
- Unknown (X)
- Pairing Broken (B)
For example, pass 'ad' to exclude added and deleted results.
See 'diff-filter' documentation on https://git-scm.com/docs/git-diff for more info.`;
/**
* Handle `--help`
*/
if (help) {
const helpMsg = `
This script calls \`git diff --name-status\` and optionally adds \`--diff-filter\` when using \`--filter\`.
Examples:
npx ./index.js v1.0.0
npx ./index.js v1.0.0 --filter mr
${revisionsMsg}
${filterMsg}`;
console.log(helpMsg)
process.exit(0);
}
/**
* Check revisions argument
*/
if (!revisions) {
const revisionsErrorMsg = `${revisionsMsg}${callHelpMsg}`
emitError(TypeError(revisionsErrorMsg));
}
/**
* Check `filter` argument
*/
if (filter === null) {
const filterErrorMsg = `${filterMsg}${callHelpMsg}`;
emitError(TypeError(filterErrorMsg));
}
/**
* Colorizes `git diff --name-status` terminal output
* @param {string} input
*/
function gitNameStatusColorize(input) {
let output = input.replace(ADDED_REGEXP, chalk.green('$&'));
output = output.replace(DELETED_REGEXP, chalk.red('$&'));
output = output.replace(MODIFIED_REGEXP, chalk.cyan('$&'));
output = output.replace(RENAMED_REGEXP, chalk.yellow('$&'));
console.log(output)
}
/**
* Prints error in red and exists
* @param {any} err
*/
function emitError(err) {
console.log(chalk.red.bold(err));
process.exit(1);
}
/**
* Execute `git diff`
*/
exec(`git diff --name-status ${revisions}` + (filter.length > 0 ? ` --diff-filter ${filter}` : ''),
(error, stdout, stderr) => {
if (error !== null) {
emitError(error, stderr);
}
gitNameStatusColorize(stdout);
});
{
"name": "npx-git-diff-name-status",
"version": "0.0.0",
"bin": "./index.js",
"dependencies": {
"minimist": "^1.2.0",
"chalk": "^2.3.0"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment