Skip to content

Instantly share code, notes, and snippets.

@joyeecheung
Last active February 7, 2025 13:57
Show Gist options
  • Select an option

  • Save joyeecheung/7889b89265dc66a6889f7f7167efb89f to your computer and use it in GitHub Desktop.

Select an option

Save joyeecheung/7889b89265dc66a6889f7f7167efb89f to your computer and use it in GitHub Desktop.
diff of diff, for double checking that you didn't mess up the backport you prepared
// Code is mostly written by ChatGPT
// git checkout backport-require-esm-20-3
// git rev-list origin/v20.x-staging...HEAD | node match.js
// node diff.js
const { execSync } = require('child_process');
const fs = require('fs');
const path = require('path');
const os = require('os');
function getCommitDiff(commitHash) {
try {
return execSync(
`git show --no-prefix --pretty=format: ${commitHash} | grep -v '^index ' | grep -v '^@@'`,
{ encoding: 'utf-8' }
);
} catch (err) {
console.error(`Error fetching diff for ${commitHash}:`, err.message);
return null;
}
}
let count = 0;
function compareCommits(commit1, commit2) {
const diff1 = getCommitDiff(commit1);
const diff2 = getCommitDiff(commit2);
if (!diff1 || !diff2) {
console.error(`Skipping comparison for ${commit1} and ${commit2} due to missing diffs.`);
return;
}
const tempDir = os.tmpdir();
const file1 = path.join(tempDir, `diff_${commit1}.patch`);
const file2 = path.join(tempDir, `diff_${commit2}.patch`);
fs.writeFileSync(file1, diff1);
fs.writeFileSync(file2, diff2);
const message = execSync(`git log -n 1 --pretty=format:%B ${commit1}`, { encoding: 'utf-8' }).trim();
const title = message.split('\n')[0];
try {
const diffOutput = execSync(`diff -c ${file1} ${file2}`, { encoding: 'utf-8' }).trim();
if (!diffOutput) {
console.log(`${title} is clean`);
}
} catch (err) {
if (err.status === 1) {
count++;
const prefix = count.toString().padStart(4, '0');
const diff = err.stdout;
const filename = `diffs/` + prefix + '-' + title.replaceAll(/\s/g, '-').replaceAll(/[:\/]/g, '') + '.diff'
const output = `${message}\n-----------------\n${diff}`;
fs.writeFileSync(filename, output, 'utf-8');
console.log(`Writing diff ${commit1.slice(0, 8)} and ${commit2.slice(0, 8)} to ${filename}`);
} else {
console.error(`Error running diff for ${commit1} and ${commit2}:`, err.message);
}
} finally {
fs.unlinkSync(file1);
fs.unlinkSync(file2);
}
}
async function processCommits() {
const commitPairs = JSON.parse(fs.readFileSync('commits.json', 'utf-8')).reverse();
for (const [commit1, commit2] of commitPairs) {
compareCommits(commit1, commit2);
}
}
fs.rmSync('./diffs', { recursive: true });
fs.mkdirSync('./diffs');
processCommits().catch(console.error);
// Code is mostly written by ChatGPT
// git checkout backport-require-esm-20-3
// git rev-list origin/v20.x-staging...HEAD | node match.js
// node diff.js
const { execSync, spawn } = require('child_process');
const readline = require('readline');
const fs = require('fs');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
terminal: false
});
async function getCommitInfo(commitHash) {
try {
const commitMessage = execSync(`git log -n 1 --pretty=format:%B ${commitHash}`, { encoding: 'utf-8' });
const lines = commitMessage.split('\n').map(line => line.trim()).filter(line => line);
if (lines.length === 0) return null;
const title = lines[0];
const prUrlLine = lines.find(line => line.startsWith('PR-URL: https://github.com/nodejs/node/pull/'));
const prMatch = prUrlLine ? prUrlLine.match(/PR-URL: https:\/\/github.com\/nodejs\/node\/pull\/(\d+)/) : null;
const prNumber = prMatch ? prMatch[1] : null;
return { commitHash, title, prNumber };
} catch (err) {
console.error(`Error fetching commit info for ${commitHash}:`, err.message);
return null;
}
}
async function findMatchingCommitOnMain(title, prNumber) {
return new Promise((resolve) => {
const gitLog = spawn('git', ['log', 'origin/main', '--pretty=format:码%H%n%B']);
const rl = readline.createInterface({ input: gitLog.stdout });
let mainCommitHash = null;
let mainTitle = null;
let mainPrNumber = null;
let found = true;
rl.on('line', (line) => {
line = line.trim();
if (!line) return;
if (line.startsWith('码')) {
mainCommitHash = line.slice(1);
mainTitle = null;
mainPrNumber = null;
return;
}
if (line === title) {
mainTitle = line;
return;
}
if (mainCommitHash && mainTitle && !mainPrNumber) {
const mainPrMatch = line.match(/PR-URL: https:\/\/github.com\/nodejs\/node\/pull\/(\d+)/);
if (mainPrMatch) {
mainPrNumber = mainPrMatch[1];
if (mainPrNumber === prNumber) {
found = true;
rl.close();
resolve(mainCommitHash);
}
}
}
});
rl.on('close', () => {
if (!found) {
resolve(null);
}
gitLog.kill();
});
});
}
(async () => {
const data = [];
for await (const line of rl) {
const commitHash = line.trim();
if (!commitHash) continue;
const commitInfo = await getCommitInfo(commitHash);
if (!commitInfo || !commitInfo.title || !commitInfo.prNumber) {
console.log(`${commitHash}: No matching info found`);
continue;
}
const matchingCommit = await findMatchingCommitOnMain(commitInfo.title, commitInfo.prNumber);
if (matchingCommit) {
data.push([commitHash, matchingCommit]);
console.log(commitHash, '->', matchingCommit);
} else {
console.log(`${commitHash}: No match found on main`);
}
}
console.log('writting commits to commits.json');
fs.writeFileSync('commits.json', JSON.stringify(data, null, 2), 'utf-8');
})();
// Code is mostly written by ChatGPT
const { execSync } = require('child_process');
const fs = require('fs');
const path = require('path');
const os = require('os');
function getCommitDiff(commitHash) {
try {
return execSync(
`git show --no-prefix --pretty=format: ${commitHash} | grep -v '^index ' | grep -v '^@@'`,
{ encoding: 'utf-8' }
);
} catch (err) {
console.error(`Error fetching diff for ${commitHash}:`, err.message);
return null;
}
}
let count = 0;
function compareCommits(commit1, commit2) {
const diff1 = getCommitDiff(commit1);
const diff2 = getCommitDiff(commit2);
if (!diff1 || !diff2) {
console.error(`Skipping comparison for ${commit1} and ${commit2} due to missing diffs.`);
return;
}
const tempDir = os.tmpdir();
const file1 = path.join(tempDir, `diff_${commit1}.patch`);
const file2 = path.join(tempDir, `diff_${commit2}.patch`);
fs.writeFileSync(file1, diff1);
fs.writeFileSync(file2, diff2);
const message = execSync(`git log -n 1 --pretty=format:%B ${commit1}`, { encoding: 'utf-8' }).trim();
const pr = message.match(/PR-URL: (.+)/)[1];
try {
const diffOutput = execSync(`diff -c ${file1} ${file2}`, { encoding: 'utf-8' }).trim();
if (!diffOutput) {
return `- ${pr}: no modifications\n`;
}
} catch (err) {
if (err.status === 1) {
return `- ${pr}: TODO\n`;
} else {
console.error(`Error running diff for ${commit1} and ${commit2}:`, err.message);
}
} finally {
fs.unlinkSync(file1);
fs.unlinkSync(file2);
}
}
async function processCommits() {
const commitPairs = JSON.parse(fs.readFileSync('commits.json', 'utf-8')).reverse();
let text = '';
for (const [commit1, commit2] of commitPairs) {
const t = compareCommits(commit1, commit2);
fs.writeSync(1, t);
}
fs.writeFileSync('./summary.md', text, 'utf-8');
}
processCommits().catch(console.error);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment