Skip to content

Instantly share code, notes, and snippets.

@KoenBrouwer
Created April 19, 2024 12:46
Show Gist options
  • Save KoenBrouwer/e9d15a1ad1c27c4698e0cdf8255556e2 to your computer and use it in GitHub Desktop.
Save KoenBrouwer/e9d15a1ad1c27c4698e0cdf8255556e2 to your computer and use it in GitHub Desktop.
Script that can be used in a pipeline to ensure that it's been rebased onto master before merging.
import { execSync } from "child_process";
import gitlog from "gitlog";
const main = () => {
const getBase = () => execSync("git merge-base origin/master HEAD").toString().trim();
const getDesiredBase = () => execSync("git ls-remote origin master").toString().trim().split("\t")[0];
const shouldRebase = (): boolean => {
try {
const base = getBase();
const desiredBase = getDesiredBase();
return base !== desiredBase;
} catch (err) {
console.error(
"Could not find base. Probably because the base is too far away. Please reduce the number of commits in this branch.",
);
process.exit(1);
}
};
const hasIllegalCommits = () => {
// Collect all commits in the branch
const base = getBase();
const commits = gitlog({
repo: __dirname,
number: 9999,
branch: `${base}..HEAD`,
fields: ["hash", "subject", "authorName", "parentHashes"],
});
// Find all merge commits by checking if they have more than one parent, indicating that it's a merge commit
const mergeCommits = commits
.map((c) => ({
...c,
parentHashes: c.parentHashes.split(" "),
}))
.filter((c) => c.parentHashes.length > 1);
console.info(`The current branch has ${commits.length} commit(s).`);
if (mergeCommits.length > 0) {
console.info(`Found ${mergeCommits.length} merge commit(s).`);
}
const illegalMergeCommits = mergeCommits.filter((mc) => {
for (const p of mc.parentHashes) {
const isParentInBranch = commits.map((c) => c.hash).includes(p);
if (!isParentInBranch) {
console.info(`Merge commit ${mc.hash} has parent ${p} that is not in the current branch.`);
return true;
}
}
return false;
});
return illegalMergeCommits.length > 0;
};
if (shouldRebase()) {
try {
const base = getBase();
const desiredBase = getDesiredBase();
console.info(
`This branch is based on ${base}. Desired base is ${desiredBase}. This branch is behind. Please rebase this branch on top of master.`,
);
process.exit(1);
} catch (err) {
console.error(
"Could not find base. Probably because the base is too far away. Please reduce the number of commits in this branch.",
);
process.exit(1);
}
}
if (hasIllegalCommits()) {
console.info(
"This branch has one or more illegal merge commits. Please remove any merge commits and instead rebase this branch on top of master.",
);
process.exit(1);
} else {
console.info("This branch has no illegal merge commits.");
process.exit(0);
}
};
main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment