Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 11 additions & 25 deletions DOCS.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,10 @@ apk add git
#### 2. Install Plugin

1. Open Acode → Settings → Plugins
2. Search "Git SCM" or "Version Control GitPro"
2. Search "Git SCM"
3. Install plugin
4. Restart

#### 4. Optional: Install inotify-tools

For automatic file change detection:

```bash
apk add inotify-tools
```

Enable in plugin settings `GIt: Use inotifywait` and restart

## Getting Started

### Opening a Git Repository
Expand Down Expand Up @@ -187,13 +177,13 @@ const scm = acode.require('scm');

```javascript
const sourceControl = scm.createSourceControl(
'my-scm-id', // Unique ID
'My SCM Label' // Display label,
'/public' // Root URI
'my-scm-id',
'My SCM Label',
'/public'
);

// Set icon
sourceControl.icon = 'git-branch';
sourceControl.icon = 'scm';

// Set root URI
sourceControl.rootUri = '/path/to/repo';
Expand Down Expand Up @@ -222,19 +212,15 @@ changes.resourceStates = [
{
resourceUri: '/path/to/file1.js',
decorations: {
letter: 'M',
color: '#ffa500',
strikeThrough: false,
icon: 'modified'
icon: 'file'
},
command: {
id: 'my.command',
title: 'My Command',
arguments: ['arg1']
}
},
{
resourceUri: '/path/to/file2.js',
decorations: {
letter: 'A',
color: '#00ff00'
}
}
];
```

Expand Down
9 changes: 9 additions & 0 deletions changelogs.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# ChangeLog

## [2.7.1] - 2026-26-06

- Added new setting: `showCommitHistoryResourceGroup` default=true
- Fixed errors like: `find: .: Permission denied`

## [2.7.0] - 2026-26-06

- Added commit history feature with detailed commit view and resource management by [@UnschooledGamer](https://github.com/UnschooledGamer)

## [2.6.1] - 2026-21-06

- Add 'add to .gitignore' scm menu for CodeMirror
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "acode.plugin.version.control.gitpro",
"version": "2.6.1",
"version": "2.7.1",
"description": "Plugin for Acode to provide Git SCM features",
"main": "dist/main.js",
"repository": "https://github.com/dikidjatar/acode-plugin-version-control-gitpro",
Expand Down
16 changes: 14 additions & 2 deletions plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"id": "acode.plugin.version.control.gitpro",
"name": "Git SCM",
"main": "main.js",
"version": "2.6.1",
"version": "2.7.1",
"repository": "https://github.com/dikidjatar/acode-plugin-version-control-gitpro.git",
"icon": "icon.png",
"files": [
Expand Down Expand Up @@ -32,5 +32,17 @@
"name": "Diki Djatar",
"email": "dikidjatar@gmail.com",
"github": "dikidjatar"
}
},
"contributors": [
{
"name": "UnschooledGamer",
"github": "UnschooledGamer",
"role": "contributor"
},
{
"name": "Victor Elijha",
"github": "Victozee26",
"role": "contributor"
}
]
}
2 changes: 1 addition & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# Acode Plugin Git SCM

![Version](https://img.shields.io/badge/version-2.6.1-blue.svg)
![Version](https://img.shields.io/badge/version-2.7.1-blue.svg)
![License](https://img.shields.io/badge/license-MIT-green.svg)
![Acode](https://img.shields.io/badge/Acode-Compatible-orange.svg)

Expand Down
15 changes: 9 additions & 6 deletions src/base/executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,12 +135,15 @@ export function getExecutor(): Executor {
return Executor;
}

function getExecutorType(): 'BackgroundExecutor' | 'Executor' {
if (typeof Executor.BackgroundExecutor !== 'undefined') {
return 'BackgroundExecutor';
function filterOutput(type: ExecutorOutputType, data: string): boolean {
if (type !== 'stderr') {
return false;
}

return 'Executor';
return (
/proot warning: can't sanitize binding/.test(data) ||
/find: .: Permission denied/.test(data)
);
}

class AcodeProcess implements Process {
Expand Down Expand Up @@ -206,9 +209,9 @@ class AcodeProcess implements Process {

this._pid = await getExecutor().start(
command,
(type: string, data: string) => {
(type: ExecutorOutputType, data: string) => {
// Filter out proot warnings
if (type === 'stderr' && data.includes("proot warning: can't sanitize binding")) {
if (filterOutput(type, data)) {
return;
}

Expand Down
110 changes: 109 additions & 1 deletion src/git/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ import { Disposable, IDisposable } from "../base/disposable";
import { toFileUrl, uriToPath } from "../base/uri";
import { SourceControl, SourceControlResourceState } from "../scm/api/sourceControl";
import { ApiRepository } from "./api/api1";
import { Branch, CommitOptions, ForcePushMode, GitErrorCodes, Ref, RefType, Remote, RemoteSourcePublisher, Status } from "./api/git";
import { Branch, Commit, CommitOptions, ForcePushMode, GitErrorCodes, Ref, RefType, Remote, RemoteSourcePublisher, Status } from "./api/git";
import { item, showDialogMessage } from "./dialog";
import { UnifiedDiff } from "./diff";
import { Git, GitError, Stash, Worktree } from "./git";
import { getInputHintResult, HintItem, InputHint, showInputHints } from "./hints";
import { LogOutputChannel } from "./logger";
import { Model } from "./model";
import { Repository, Resource, ResourceGroupType } from "./repository";
import { formatCommitDetails } from "./commitDetails";
import { toGitUri } from "./uri";
import { coalesce, fromNow, getModeForFile, grep, isDescendant, pathEquals, toFullPath } from "./utils";

Expand Down Expand Up @@ -342,6 +343,38 @@ class RepositoryItem implements HintItem {
constructor(public readonly path: string) { }
}

class CommitHistoryItem implements HintItem {

get label(): string {
return this.subject || this.shortHash;
}

get icon(): string {
return 'vscode-codicons_git_commit';
}

get description(): string {
return `${this.shortHash} • ${this.commit.commitDate ? fromNow(this.commit.commitDate, true, true) : 'No Date'}`;
}

get detail(): string | undefined {
return this.commit.authorName;
}

get shortHash(): string {
return this.commit.hash.substring(0, this.shortCommitLength);
}

private get subject(): string {
return this.commit.message.split(/\r?\n/)[0]?.trim() || '';
}

constructor(
readonly commit: Commit,
private readonly shortCommitLength: number
) { }
}

class StashItem implements HintItem {

get label(): string { return `#${this.stash.index}: ${this.stash.description}`; }
Expand All @@ -368,6 +401,21 @@ function sanitizeRemoteName(name: string) {
return name && name.replace(/^\.|\/\.|\.\.|~|\^|:|\/$|\.lock$|\.lock\/|\\|\*|\s|^\s*$|\.$|\[|\]$/g, '-');
}

async function copyText(value: string): Promise<void> {
if (navigator.clipboard?.writeText) {
await navigator.clipboard.writeText(value);
return;
}

const textarea = tag('textarea', { value });
textarea.style.position = 'fixed';
textarea.style.opacity = '0';
document.body.appendChild(textarea);
textarea.select();
document.execCommand('copy');
textarea.remove();
}

enum PushType {
Push,
PushTo,
Expand Down Expand Up @@ -685,6 +733,66 @@ export class CommandCenter {
await repository.refresh();
}

@command('Show Commit', { repository: true })
async showCommit(repository: Repository | null, commit: Commit): Promise<void> {

if(!commit && repository) {
const gitConfig = config.get('vcgit')!;
const shortCommitLength = gitConfig.commitShortHashLength;
const commits = await repository.log({ maxEntries: 100, shortStats: true, silent: true });

if (commits.length === 0) {
window.toast('No commit history found', 2000);
return;
}

const commitItem = await showInputHints(
commits.map(commit => new CommitHistoryItem(commit, shortCommitLength)),
{ placeholder: 'Select a commit to view' }
);

if (!commitItem) {
return;
}

commit = commitItem.commit;
}

const box = DialogBox('Commit Details', formatCommitDetails(commit), 'OK', '');
box.ok(() => box.hide());
}

@command('History', { repository: true })
async history(repository: Repository): Promise<void> {
const gitConfig = config.get('vcgit')!;
const shortCommitLength = gitConfig.commitShortHashLength;
const commits = await repository.log({ maxEntries: 100, shortStats: true, silent: true });

if (commits.length === 0) {
window.toast('No commit history found', 3000);
return;
}

const commitItem = await showInputHints(
commits.map(commit => new CommitHistoryItem(commit, shortCommitLength)),
{ placeholder: 'Select a commit to view' }
);

if (!commitItem) {
return;
}

const showDetails = 'Show Details';
const copyHash = 'Copy Hash';
const action = await select('', [showDetails, copyHash]);

if (action === showDetails) {
await this.showCommit(null, commitItem.commit);
} else if (action === copyHash) {
await copyText(commitItem.commit.hash);
window.toast('Commit hash copied', 3000);
}
}
@command('Open Repository', { repository: false })
async openRepository(path?: string): Promise<void> {
if (!path) {
Expand Down
47 changes: 47 additions & 0 deletions src/git/commitDetails.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
interface CommitLike {
readonly hash: string;
readonly message: string;
readonly parents: readonly string[];
readonly authorName?: string;
readonly authorEmail?: string;
readonly commitDate?: Date;
readonly refNames?: readonly string[];
readonly shortStat?: {
readonly files: number;
readonly insertions: number;
readonly deletions: number;
};
}

function escapeHtml(value: string): string {
return value.replace(/[&<>"']/g, char => {
switch (char) {
case '&': return '&amp;';
case '<': return '&lt;';
case '>': return '&gt;';
case '"': return '&quot;';
case "'": return '&#39;';
default: return char;
}
});
}

export function formatCommitDetails(commit: CommitLike): string {
const shortStat = commit.shortStat
? `${commit.shortStat.files} files changed, ${commit.shortStat.insertions} insertions(+), ${commit.shortStat.deletions} deletions(-)`
: 'No file change statistics available';
const parents = commit.parents.length > 0 ? commit.parents.join(', ') : 'None';
const refs = commit.refNames?.filter(Boolean).join(', ') || 'None';
const commitAuthor = commit.authorName ? `${commit.authorName} <${commit.authorEmail}>` : 'Unknown Author';
const commitDate = commit.commitDate ? commit.commitDate.toLocaleString() : 'Unknown Date';

return [
`<strong>Commit</strong><br>${escapeHtml(commit.hash)}`,
`<strong>Author</strong><br>${escapeHtml(commitAuthor)}`,
`<strong>Date</strong><br>${escapeHtml(commitDate)}`,
`<strong>Parents</strong><br>${escapeHtml(parents)}`,
`<strong>Refs</strong><br>${escapeHtml(refs)}`,
`<strong>Stats</strong><br>${escapeHtml(shortStat)}`,
`<strong>Message</strong><br><pre style="white-space: pre-wrap; word-break: break-word;">${escapeHtml(commit.message)}</pre>`
].join('<br><br>');
}
Loading