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:
commit
0c1d9513db
@ -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 { }
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
@ -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()
|
||||
];
|
||||
}
|
||||
|
@ -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 ? '+': ''})` : ''}`);
|
||||
}
|
||||
}
|
@ -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')) {
|
||||
|
Loading…
Reference in New Issue
Block a user