1
1
mirror of https://github.com/kahole/edamagit.git synced 2024-09-11 07:15:31 +03:00

Merge pull request #257 from bjackman/optimise

Fix status view for very out-of-sync repos
This commit is contained in:
Kristian Andersen Hole 2023-05-19 14:18:55 +02:00 committed by GitHub
commit 0c1d9513db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 68 additions and 36 deletions

View File

@ -6,7 +6,7 @@ import GitTextUtils from '../utils/gitTextUtils';
import MagitUtils from '../utils/magitUtils';
import MagitStatusView from '../views/magitStatusView';
import { Status, Commit, RefType, Repository, Change, Ref } from '../typings/git';
import { MagitBranch, MagitUpstreamRef } from '../models/magitBranch';
import { MagitBranch, MagitCommitList, MagitUpstreamRef } from '../models/magitBranch';
import { gitRun, LogLevel } from '../utils/gitRawRunner';
import * as Constants from '../common/constants';
import { getCommit } from '../utils/commitCache';
@ -19,6 +19,8 @@ import { MagitRepository } from '../models/magitRepository';
import ViewUtils from '../utils/viewUtils';
import { scheduleForgeStatusAsync, forgeStatusCached } from '../forge';
const maxCommitsAheadBehind = 50;
export async function magitRefresh() { }
export async function magitStatus(): Promise<any> {
@ -70,18 +72,18 @@ export async function internalMagitStatus(repository: Repository): Promise<Magit
const logTask = repository.state.HEAD?.commit ? repository.log({ maxEntries: 100 }) : Promise.resolve([]);
if (repository.state.HEAD?.commit) {
getCommit(repository, repository.state.HEAD?.commit);
}
let ahead, behind: Promise<MagitCommitList> | undefined;
let commitsAheadUpstream: string[] = [], commitsBehindUpstream: string[] = [];
if (repository.state.HEAD?.ahead || repository.state.HEAD?.behind) {
const ref = repository.state.HEAD.name;
const args = ['rev-list', '--left-right', `${ref}...${ref}@{u}`];
const res = (await gitRun(repository, args, {}, LogLevel.None)).stdout;
[commitsAheadUpstream, commitsBehindUpstream] = GitTextUtils.parseRevListLeftRight(res);
commitsAheadUpstream.map(c => getCommit(repository, c));
commitsBehindUpstream.map(c => getCommit(repository, c));
const ref = repository.state.HEAD?.name;
const upstream = `${ref}@{u}`;
// We actually must have a named ref if there is "ahead"/"behind"; you can't
// have an "upstream" without being on a named branch. So the && ref is just
// to satisfy the type checker.
if (repository.state.HEAD?.ahead && ref) {
ahead = getCommitRange(repository, upstream, ref, maxCommitsAheadBehind);
}
if (repository.state.HEAD?.behind && ref) {
behind = getCommitRange(repository, ref, upstream, maxCommitsAheadBehind);
}
const workingTreeChanges_NoUntracked = repository.state.workingTreeChanges
@ -150,8 +152,12 @@ export async function internalMagitStatus(repository: Repository): Promise<Magit
HEAD.upstreamRemote = HEAD.upstream;
HEAD.upstreamRemote.commit = await upstreamRemoteCommitDetails;
HEAD.upstreamRemote.commitsAhead = await Promise.all(commitsAheadUpstream.map(hash => getCommit(repository, hash)));
HEAD.upstreamRemote.commitsBehind = await Promise.all(commitsBehindUpstream.map(hash => getCommit(repository, hash)));
if (ahead) {
HEAD.upstreamRemote.ahead = await ahead;
}
if (behind) {
HEAD.upstreamRemote.behind = await behind;
}
HEAD.upstreamRemote.rebase = (await isRebaseUpstream) === 'true';
}
} catch { }
@ -201,6 +207,22 @@ function toMagitChange(repository: Repository, change: Change, diff?: string): M
return magitChange;
}
async function getCommitRange(repository: Repository, from: string, to: string, maxResults: number): Promise<MagitCommitList> {
const args = ['log', '--format=format:%H', `${from}...${to}`, '-n', `${Math.trunc(maxResults) + 1}`];
let result;
try {
result = await gitRun(repository, args, {}, LogLevel.Error);
} catch (error) {
return {commits: [], truncated: false};
}
// Slice removes empty string after final newline.
const hashes = result.stdout.trim().split(Constants.LineSplitterRegex);
return {
commits: await Promise.all(hashes.slice(0, maxResults).map(hash => getCommit(repository, hash))),
truncated: hashes.length > maxResults,
};
}
async function pushRemoteStatus(repository: Repository): Promise<MagitUpstreamRef | undefined> {
try {
const HEAD = repository.state.HEAD;
@ -208,17 +230,20 @@ async function pushRemoteStatus(repository: Repository): Promise<MagitUpstreamRe
if (HEAD?.name && pushRemote) {
const args = ['rev-list', '--left-right', `${HEAD.name}...${pushRemote}/${HEAD.name}`];
const res = (await gitRun(repository, args, {}, LogLevel.None)).stdout;
const [commitsAheadPushRemote, commitsBehindPushRemote] = GitTextUtils.parseRevListLeftRight(res);
const commitsAhead = await Promise.all(commitsAheadPushRemote.map(c => getCommit(repository, c)));
const commitsBehind = await Promise.all(commitsBehindPushRemote.map(c => getCommit(repository, c)));
const ahead = getCommitRange(repository, `${pushRemote}/${HEAD.name}`, HEAD.name, maxCommitsAheadBehind);
const behind = getCommitRange(repository, HEAD.name, `${pushRemote}/${HEAD.name}`, maxCommitsAheadBehind);
const refs = await getRefs(repository);
const pushRemoteCommit = refs.find(ref => ref.remote === pushRemote && ref.name === `${pushRemote}/${HEAD.name}`)?.commit;
const pushRemoteCommitDetails = pushRemoteCommit ? getCommit(repository, pushRemoteCommit) : Promise.resolve(undefined);
return { remote: pushRemote, name: HEAD.name, commit: await pushRemoteCommitDetails, commitsAhead, commitsBehind };
return {
remote: pushRemote,
name: HEAD.name,
commit: await pushRemoteCommitDetails,
ahead: await ahead,
behind: await behind,
};
}
} catch { }
}

View File

@ -7,9 +7,13 @@ export interface MagitBranch extends Branch {
tag?: Ref;
}
export interface MagitCommitList {
commits: Commit[];
truncated: boolean;
}
export interface MagitUpstreamRef extends UpstreamRef {
commit?: Commit;
commitsAhead?: Commit[];
commitsBehind?: Commit[];
ahead?: MagitCommitList;
behind?: MagitCommitList;
rebase?: boolean;
}

View File

@ -3,17 +3,20 @@ import { Section, SectionHeaderView } from '../general/sectionHeader';
import { Commit, UpstreamRef, Ref } from '../../typings/git';
import { LineBreakView } from '../general/lineBreakView';
import { CommitItemView } from './commitSectionView';
import { MagitCommitList } from '../../models/magitBranch';
export class UnsourcedCommitSectionView extends View {
isFoldable = true;
static maxEntries = 256;
get id() { return this.section.toString(); }
constructor(private section: Section, upstream: UpstreamRef, commits: Commit[], refs: Ref[]) {
constructor(private section: Section, upstream: UpstreamRef, list: MagitCommitList, refs: Ref[]) {
super();
this.subViews = [
new SectionHeaderView(section, commits.length, `${upstream.remote}/${upstream.name}`),
...commits.map(commit => new CommitItemView(commit, undefined, refs)),
new SectionHeaderView(section, list.commits.length, `${upstream.remote}/${upstream.name}`, list.truncated),
...list.commits.map(commit => new CommitItemView(commit, undefined, refs)),
new LineBreakView()
];
}

View File

@ -22,7 +22,7 @@ export enum Section {
export class SectionHeaderView extends UnclickableTextView {
constructor(section: Section, count?: number, extraText?: string) {
super(`${section.valueOf()}${extraText ? ' ' + extraText + '' : ''}${count ? ' (' + count + ')' : ''}`);
constructor(section: Section, count?: number, extraText?: string, truncated=false) {
super(`${section.valueOf()}${extraText ? ' ' + extraText : ''}${count ? ` (${count}${truncated ? '+': ''})` : ''}`);
}
}

View File

@ -77,19 +77,19 @@ export default class MagitStatusView extends DocumentView {
const refs = magitState.remotes.reduce((prev, remote) => remote.branches.concat(prev), magitState.branches.concat(magitState.tags));
if (magitState.HEAD?.upstreamRemote?.commitsAhead?.length && !magitConfig.hiddenStatusSections.has('unmerged')) {
this.addSubview(new UnsourcedCommitSectionView(Section.UnmergedInto, magitState.HEAD.upstreamRemote, magitState.HEAD.upstreamRemote.commitsAhead, refs));
} else if (magitState.HEAD?.pushRemote?.commitsAhead?.length && !magitConfig.hiddenStatusSections.has('unpushed')) {
this.addSubview(new UnsourcedCommitSectionView(Section.UnpushedTo, magitState.HEAD.pushRemote, magitState.HEAD.pushRemote.commitsAhead, refs));
if (magitState.HEAD?.upstreamRemote?.ahead?.commits.length && !magitConfig.hiddenStatusSections.has('unmerged')) {
this.addSubview(new UnsourcedCommitSectionView(Section.UnmergedInto, magitState.HEAD.upstreamRemote, magitState.HEAD.upstreamRemote.ahead, refs));
} else if (magitState.HEAD?.pushRemote?.ahead?.commits.length && !magitConfig.hiddenStatusSections.has('unpushed')) {
this.addSubview(new UnsourcedCommitSectionView(Section.UnpushedTo, magitState.HEAD.pushRemote, magitState.HEAD.pushRemote.ahead, refs));
}
if (magitState.log.length > 0 && !magitState.HEAD?.upstreamRemote?.commitsAhead?.length && !magitConfig.hiddenStatusSections.has('recent commits')) {
if (magitState.log.length > 0 && !magitState.HEAD?.upstreamRemote?.ahead?.commits.length && !magitConfig.hiddenStatusSections.has('recent commits')) {
this.addSubview(new CommitSectionView(Section.RecentCommits, magitState.log.slice(0, 10), refs));
}
if (magitState.HEAD?.upstreamRemote?.commitsBehind?.length && !magitConfig.hiddenStatusSections.has('unpulled')) {
this.addSubview(new UnsourcedCommitSectionView(Section.UnpulledFrom, magitState.HEAD.upstreamRemote, magitState.HEAD.upstreamRemote.commitsBehind, refs));
} else if (magitState.HEAD?.pushRemote?.commitsBehind?.length) {
this.addSubview(new UnsourcedCommitSectionView(Section.UnpulledFrom, magitState.HEAD.pushRemote, magitState.HEAD.pushRemote.commitsBehind, refs));
if (magitState.HEAD?.upstreamRemote?.behind?.commits.length && !magitConfig.hiddenStatusSections.has('unpulled')) {
this.addSubview(new UnsourcedCommitSectionView(Section.UnpulledFrom, magitState.HEAD.upstreamRemote, magitState.HEAD.upstreamRemote.behind, refs));
} else if (magitState.HEAD?.pushRemote?.behind?.commits.length) {
this.addSubview(new UnsourcedCommitSectionView(Section.UnpulledFrom, magitState.HEAD.pushRemote, magitState.HEAD.pushRemote.behind, refs));
}
if (magitState.forgeState?.pullRequests?.length && !magitConfig.hiddenStatusSections.has('pull requests')) {