perf(release): 复用分支补丁核对并固定比较快照
This commit is contained in:
@@ -42,6 +42,15 @@ export function inspectRepository(repository, { fetch = false } = {}) {
|
|||||||
const output = git(repository.path, 'for-each-ref', '--format=%(refname)%00%(objectname)%00%(symref)', `refs/remotes/${remote}/`);
|
const output = git(repository.path, 'for-each-ref', '--format=%(refname)%00%(objectname)%00%(symref)', `refs/remotes/${remote}/`);
|
||||||
const cache = new Map();
|
const cache = new Map();
|
||||||
const knownEquivalent = new Set();
|
const knownEquivalent = new Set();
|
||||||
|
const mergeBases = new Map();
|
||||||
|
const isolatedEquivalence = new Map();
|
||||||
|
const mergeBase = sha => {
|
||||||
|
if (!mergeBases.has(sha)) {
|
||||||
|
try { mergeBases.set(sha, git(repository.path, 'merge-base', result.targetSha, sha)); }
|
||||||
|
catch (error) { if (error.status === 1 && !String(error.stderr || '').trim()) mergeBases.set(sha, null); else throw error; }
|
||||||
|
}
|
||||||
|
return mergeBases.get(sha);
|
||||||
|
};
|
||||||
for (const line of output.split('\n').filter(Boolean)) {
|
for (const line of output.split('\n').filter(Boolean)) {
|
||||||
const [ref, sha, symbolicRef] = line.split('\0');
|
const [ref, sha, symbolicRef] = line.split('\0');
|
||||||
if (symbolicRef || ref === targetRef) continue;
|
if (symbolicRef || ref === targetRef) continue;
|
||||||
@@ -49,20 +58,24 @@ export function inspectRepository(repository, { fetch = false } = {}) {
|
|||||||
try {
|
try {
|
||||||
let comparison = cache.get(sha);
|
let comparison = cache.get(sha);
|
||||||
if (!comparison) {
|
if (!comparison) {
|
||||||
const range = `${targetRef}..${ref}`;
|
// Pin the inventory SHAs so another fetch cannot change this comparison midway.
|
||||||
|
const range = `${result.targetSha}..${sha}`;
|
||||||
const ahead = Number(git(repository.path, 'rev-list', '--count', range));
|
const ahead = Number(git(repository.path, 'rev-list', '--count', range));
|
||||||
comparison = { ahead, unmergedCommits: [], equivalentCommits: [], mergeCommits: [] };
|
comparison = { ahead, unmergedCommits: [], equivalentCommits: [], mergeCommits: [] };
|
||||||
if (ahead > 0) {
|
if (ahead > 0) {
|
||||||
const cherry = git(repository.path, 'cherry', targetRef, ref);
|
const cherry = git(repository.path, 'cherry', result.targetSha, sha);
|
||||||
const equivalence = new Map(cherry.split('\n').filter(Boolean).map(line => [line.slice(2), line[0]]));
|
const equivalence = new Map(cherry.split('\n').filter(Boolean).map(line => [line.slice(2), line[0]]));
|
||||||
comparison.mergeCommits = commits(repository.path, range, '--merges');
|
comparison.mergeCommits = commits(repository.path, range, '--merges');
|
||||||
for (const commit of commits(repository.path, range, '--no-merges')) {
|
for (const commit of commits(repository.path, range, '--no-merges')) {
|
||||||
if (equivalence.get(commit.sha) === '-') knownEquivalent.add(commit.sha);
|
if (equivalence.get(commit.sha) === '-') knownEquivalent.add(commit.sha);
|
||||||
// If the branch merged the target, Git's merge base can hide older
|
// If the branch merged the target, Git's merge base can hide older
|
||||||
// upstream patches. Compare the individual incoming commit too.
|
// upstream patches. Compare the individual incoming commit too.
|
||||||
if (comparison.mergeCommits.length && !knownEquivalent.has(commit.sha)) {
|
if (comparison.mergeCommits.length && !knownEquivalent.has(commit.sha) && mergeBase(sha) !== mergeBase(commit.sha)) {
|
||||||
const isolated = git(repository.path, 'cherry', targetRef, commit.sha);
|
if (!isolatedEquivalence.has(commit.sha)) {
|
||||||
for (const line of isolated.split('\n')) if (line.startsWith('- ')) knownEquivalent.add(line.slice(2));
|
const isolated = git(repository.path, 'cherry', result.targetSha, commit.sha);
|
||||||
|
isolatedEquivalence.set(commit.sha, isolated.split('\n').includes('- ' + commit.sha));
|
||||||
|
}
|
||||||
|
if (isolatedEquivalence.get(commit.sha)) knownEquivalent.add(commit.sha);
|
||||||
}
|
}
|
||||||
// A changed SHA alone does not mean the change is absent from the target branch.
|
// A changed SHA alone does not mean the change is absent from the target branch.
|
||||||
const list = knownEquivalent.has(commit.sha) ? comparison.equivalentCommits : comparison.unmergedCommits;
|
const list = knownEquivalent.has(commit.sha) ? comparison.equivalentCommits : comparison.unmergedCommits;
|
||||||
|
|||||||
Reference in New Issue
Block a user