mirror of
https://github.com/kahole/edamagit.git
synced 2024-09-11 07:15:31 +03:00
Compare commits
10 Commits
9fedb1702c
...
95ebda5fb4
Author | SHA1 | Date | |
---|---|---|---|
|
95ebda5fb4 | ||
|
b02b539226 | ||
|
8a9031f21a | ||
|
1f8f3e4ae0 | ||
|
6355baf768 | ||
|
93bf37d150 | ||
|
9d0f6059a9 | ||
|
ca38e31b76 | ||
|
014d615fab | ||
|
42ebfd1b32 |
@ -1,5 +1,10 @@
|
||||
# Changelog
|
||||
|
||||
## [0.6.44]
|
||||
- Improved performance of status view and fix commit ahead/behind list for very out-of-sync repos (@bjackman Brendan Jackman)
|
||||
- add a switch for log --first-parent (@tzemanovic Tomas Zemanovic)
|
||||
- Fold/unfold diff hunks in stash detail view (@vbh Bindu)
|
||||
|
||||
## [0.6.43]
|
||||
- When discarding a file change fails because of resolved conflicts (e.g. during merge) prompt to checkout our stage,
|
||||
their stage or to leave conflicts for manual resolving. @tzemanovic (Tomas Zemanovic)
|
||||
|
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "magit",
|
||||
"version": "0.6.43",
|
||||
"version": "0.6.44",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "magit",
|
||||
"version": "0.6.43",
|
||||
"version": "0.6.44",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vscode/iconv-lite-umd": "^0.7.0",
|
||||
|
@ -7,7 +7,7 @@
|
||||
"author": {
|
||||
"name": "Kristian Andersen Hole"
|
||||
},
|
||||
"version": "0.6.43",
|
||||
"version": "0.6.44",
|
||||
"engines": {
|
||||
"vscode": "^1.50.0"
|
||||
},
|
||||
|
@ -3,6 +3,7 @@ import { MagitRepository } from '../models/magitRepository';
|
||||
import { gitRun } from '../utils/gitRawRunner';
|
||||
import { DiffView } from '../views/diffView';
|
||||
import { MenuUtil, MenuState } from '../menu/menu';
|
||||
import GitTextUtils from '../utils/gitTextUtils';
|
||||
import { PickMenuUtil, PickMenuItem } from '../menu/pickMenu';
|
||||
import { StashDetailView } from '../views/stashDetailView';
|
||||
import MagitUtils from '../utils/magitUtils';
|
||||
@ -14,6 +15,7 @@ import { Status } from '../typings/git';
|
||||
import { MagitChange } from '../models/magitChange';
|
||||
import { Stash } from '../models/stash';
|
||||
import ViewUtils from '../utils/viewUtils';
|
||||
import { constants } from 'buffer';
|
||||
|
||||
const diffingMenu = {
|
||||
title: 'Diffing',
|
||||
@ -102,9 +104,51 @@ async function showStash({ repository }: MenuState) {
|
||||
}
|
||||
}
|
||||
|
||||
function stashToMagitChanges(nameStatusText: string, diff: string): MagitChange[] {
|
||||
const DIFF_PREFIX = 'diff --git';
|
||||
const filesWithStatus = nameStatusText.split(Constants.LineSplitterRegex).filter(t => t !== '').map(s => s.split('\t'));
|
||||
const diffs = diff.split(DIFF_PREFIX).filter(r => r !== '');
|
||||
|
||||
if (filesWithStatus.length !== diffs.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return diffs.map((diff, idx) => {
|
||||
const [status, ...paths] = filesWithStatus[idx];
|
||||
const uri = Uri.file(paths[paths.length - 1]);
|
||||
const fileStatus = getStatusFromString(status);
|
||||
return {
|
||||
diff,
|
||||
uri,
|
||||
originalUri: uri,
|
||||
status: fileStatus,
|
||||
renameUri: undefined,
|
||||
relativePath: paths.join(' -> '),
|
||||
hunks: diff ? GitTextUtils.diffToHunks(diff, uri) : undefined,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function getStatusFromString(status: String): number {
|
||||
switch (status.charAt(0)) {
|
||||
case 'A':
|
||||
return Status.INDEX_ADDED;
|
||||
case 'C':
|
||||
return Status.INDEX_COPIED ;
|
||||
case 'D':
|
||||
return Status.DELETED;
|
||||
case 'R' :
|
||||
return Status.INDEX_RENAMED;
|
||||
case 'M':
|
||||
default:
|
||||
return Status.MODIFIED;
|
||||
}
|
||||
}
|
||||
|
||||
export async function showStashDetail(repository: MagitRepository, stash: Stash) {
|
||||
const uri = StashDetailView.encodeLocation(repository, stash);
|
||||
|
||||
const nameStatusTask = gitRun(repository.gitRepository, ['stash', 'show', '--name-status', `stash@{${stash.index}}`]);
|
||||
const stashShowTask = gitRun(repository.gitRepository, ['stash', 'show', '-p', `stash@{${stash.index}}`]);
|
||||
let stashUntrackedFiles: MagitChange[] = [];
|
||||
try {
|
||||
@ -124,9 +168,10 @@ export async function showStashDetail(repository: MagitRepository, stash: Stash)
|
||||
|
||||
} catch { }
|
||||
|
||||
const nameStatusText = (await nameStatusTask).stdout;
|
||||
const stashDiff = (await stashShowTask).stdout;
|
||||
|
||||
return ViewUtils.showView(uri, new StashDetailView(uri, stash, stashDiff, stashUntrackedFiles));
|
||||
return ViewUtils.showView(uri, new StashDetailView(uri, stash, stashToMagitChanges(nameStatusText, stashDiff), stashUntrackedFiles));
|
||||
}
|
||||
|
||||
async function showCommit({ repository }: MenuState) {
|
||||
|
@ -24,7 +24,8 @@ const loggingMenu = {
|
||||
const switches: Switch[] = [
|
||||
{ key: '-D', name: '--simplify-by-decoration', description: 'Simplify by decoration' },
|
||||
{ key: '-g', name: '--graph', description: 'Show graph', activated: true },
|
||||
{ key: '-d', name: '--decorate', description: 'Show refnames', activated: true }
|
||||
{ key: '-d', name: '--decorate', description: 'Show refnames', activated: true },
|
||||
{ key: '-p', name: '--first-parent', description: 'First parent', activated: false },
|
||||
];
|
||||
|
||||
const options: Option[] = [
|
||||
@ -126,6 +127,9 @@ function createLogArgs(switches: Switch[], options: Option[]) {
|
||||
if (switchMap['-g'].activated) {
|
||||
args.push(switchMap['-g'].name);
|
||||
}
|
||||
if (switchMap['-p'].activated) {
|
||||
args.push(switchMap['-p'].name);
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
|
@ -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};
|
||||
}
|
||||
const out = result.stdout.trim();
|
||||
const hashes = out ? out.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()
|
||||
];
|
||||
}
|
||||
|
@ -18,11 +18,12 @@ export enum Section {
|
||||
Tags = 'Tags',
|
||||
PullRequests = 'Pull Requests',
|
||||
Issues = 'Issues',
|
||||
Changes='Changes',
|
||||
}
|
||||
|
||||
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')) {
|
||||
|
@ -13,7 +13,7 @@ export class StashDetailView extends DocumentView {
|
||||
static UriPath: string = 'stash.magit';
|
||||
needsUpdate = false;
|
||||
|
||||
constructor(public uri: Uri, stash: Stash, diff: string, untrackedFiles: MagitChange[]) {
|
||||
constructor(public uri: Uri, stash: Stash, diffChanges: MagitChange[], untrackedFiles: MagitChange[] ) {
|
||||
super(uri);
|
||||
|
||||
this.addSubview(new TextView(`Stash@{${stash.index}} ${stash.description}`));
|
||||
@ -22,7 +22,7 @@ export class StashDetailView extends DocumentView {
|
||||
this.addSubview(new ChangeSectionView(Section.Untracked, untrackedFiles, `-stashDetail@{${stash.index}}`));
|
||||
}
|
||||
|
||||
this.addSubview(new TextView(diff));
|
||||
this.addSubview(new ChangeSectionView(Section.Changes, diffChanges, `-stashDetail@{${stash.index}}`));
|
||||
}
|
||||
|
||||
public update(state: MagitRepository): void { }
|
||||
|
@ -38,7 +38,7 @@
|
||||
]
|
||||
},
|
||||
"sectionHeader": {
|
||||
"match": "^(Untracked files|((Unstaged|Staged) changes)|Stashes|Recent commits|Unmerged into|Unpushed to|Unpulled from|HEAD|Branches|Remote|Tags|Pull Requests|Issues|GitError!|(Merging .*(?= \\())|(Rebasing .* onto .*$)|Cherry Picking|Reverting|Stash@{\\d+}|(Commits in .*$))",
|
||||
"match": "^(Untracked files|((Unstaged|Staged) changes)|Stashes|Recent commits|Unmerged into|Unpushed to|Unpulled from|HEAD|Branches|Remote|Tags|Pull Requests|Issues|GitError!|(Merging .*(?= \\())|(Rebasing .* onto .*$)|Cherry Picking|Reverting|Stash@{\\d+}|(Commits in .*$))|Changes",
|
||||
"name": "strong keyword.operator.new.section.header.magit magit.header"
|
||||
},
|
||||
"highlight": {
|
||||
|
Loading…
Reference in New Issue
Block a user