Skip to content

Commit 81f12db

Browse files
committed
updateCommitMappings: run only one big range-diff
Over the time, GitGitGadget accumulated _quite_ a few open PRs. For all of them, the commit mappings are updated whenever `pu` changed. But that can take _quite_ a long time, due to an ancient merge base. See e.g. gitgitgadget/git#15, which still awaits the time when this developer can do some fun stuff again. Even worse: since this task is run on a low-powered Azure VM, it takes quite a few resources, and quite a long time just to update the commit mappings. Let's coalesce all the ranges that need to be compared into a single one, and run only a single range-diff (which will still take something like 90 seconds, but that is way better than the 30 minutes the many range-diffs take right now). To do so, we construct a throw-away octopus merge of all the base commits, and another octopus merge of all the head commits, and then use the range between these octopus merges as the first commit range for the `git range-diff` command. To make sure that we're not missing anything (e.g. when one of the PRs has `pu` as its base commit), we do not use the first octopus merge in the second commit range. Instead, we use `maint~100..pu`, which should be plenty enough. Signed-off-by: Johannes Schindelin <[email protected]>
1 parent 233dded commit 81f12db

File tree

2 files changed

+29
-5
lines changed

2 files changed

+29
-5
lines changed

lib/ci-helper.ts

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as fs from "fs";
22
import * as util from "util";
33
import { ILintError, LintCommit } from "./commit-lint";
4-
import { commitExists, git } from "./git";
4+
import { commitExists, git, emptyTreeName } from "./git";
55
import { GitNotes } from "./git-notes";
66
import { GitGitGadget, IGitGitGadgetOptions } from "./gitgitgadget";
77
import { GitHubGlue, IGitHubUser, IPRCommit,
@@ -159,6 +159,8 @@ export class CIHelper {
159159
{ workDir: this.workDir })).split("\n"),
160160
);
161161
let result = false;
162+
const bases = [];
163+
const heads = [];
162164
for (const pullRequestURL of Object.keys(options.openPRs)) {
163165
const info = await this.getPRMetadata(pullRequestURL);
164166
if (info === undefined || info.latestTag === undefined ||
@@ -183,24 +185,45 @@ export class CIHelper {
183185
meta.commitInGitGit = undefined;
184186
result = true;
185187
}
188+
bases.push(info.baseCommit);
189+
heads.push(info.headCommit);
190+
}
191+
192+
if (heads.length > 0) {
193+
let base = bases[0];
194+
let head = heads[0];
195+
if (heads.length > 1) {
196+
/*
197+
* Generate throw-away octopus merges to combine multiple
198+
* commit ranges into a single one.
199+
*/
200+
base = await git(["commit-tree", ...bases.map(h => `-p${h}`),
201+
emptyTreeName],
202+
{ workDir: this.workDir, stdin: "()" });
203+
head = await git(["commit-tree", ...heads.map(h => `-p${h}`),
204+
emptyTreeName],
205+
{ workDir: this.workDir, stdin: "()" });
206+
}
186207

208+
const range1 = `${base}..${head}`;
209+
const range2 =
210+
"refs/remotes/upstream/maint~100..refs/remotes/upstream/pu";
187211
const start = Date.now();
188212
const out = await git(["-c", "core.abbrev=40", "range-diff", "-s",
189-
info.baseCommit, info.headCommit,
190-
"refs/remotes/upstream/pu"],
213+
range1, range2],
191214
{ workDir: this.workDir });
192215
const duration = Date.now() - start;
193216
if (duration > 2000)
194217
console.log(`warning: \`git range-diff ${
195-
info.baseCommit} ${info.headCommit} upstream/pu\` took ${
218+
range1} ${range2}\` took ${
196219
duration / 1000} seconds`);
197220
for (const line of out.split("\n")) {
198221
const match =
199222
line.match(/^[^:]*: *([^ ]*) [!=][^:]*: *([^ ]*)/);
200223
if (!match) {
201224
continue;
202225
}
203-
const messageID2 = match[1] === info.headCommit ? messageID :
226+
const messageID2: string | undefined =
204227
await this.getMessageIdForOriginalCommit(match[1]);
205228
if (messageID2 === undefined) {
206229
continue;

lib/git.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export interface IGitOptions {
1313
}
1414

1515
export const emptyBlobName = "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391";
16+
export const emptyTreeName = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
1617

1718
function trimTrailingNewline(str: string): string {
1819
return str.replace(/\r?\n$/, "");

0 commit comments

Comments
 (0)