Skip to main content

Plugin Git Module

The Plugin Git Module (@ever-works/plugin/git) provides a complete git operations layer for plugin development. It wraps isomorphic-git to provide clone, pull, push, branch management, and file status tracking operations. Git provider plugins (e.g., GitHub) use this module to handle all local repository manipulation.

Package Overview​

PropertyValue
Import path@ever-works/plugin/git
Locationplatform/packages/plugin/src/git/
Dependenciesisomorphic-git, isomorphic-git/http/node
Used byGitHub plugin, and any future git provider plugins

Module Exports​

export { GitOperations, type GitOperationsConfig } from './git-operations.js';

export type {
IGitOperations,
IGitProviderPlugin,
GitAuth,
GitCommitter,
GitRepository,
GitBranch,
GitCommit,
GitFileStatus,
GitFileChange,
GitCloneOptions,
GitPushOptions,
CreateRepoOptions,
ForkRepositoryOptions,
CreatePROptions,
MergeOptions,
MergeResult,
GitUser,
GitOrganization,
GitPullRequest,
GitRepositoryPermissions,
GitRepositoryWithPermissions,
ListRepositoriesOptions,
GitPullRequestFile,
ListPullRequestsOptions
} from '../contracts/capabilities/git-provider.interface.js';

export { isGitProviderPlugin } from '../contracts/capabilities/git-provider.interface.js';

GitOperations Class​

The core class implementing the IGitOperations interface. It is constructed with authentication and URL generation callbacks, making it provider-agnostic.

Configuration​

interface GitOperationsConfig {
readonly baseDir?: string; // default: os.tmpdir()/ever-works-repos
readonly defaultCommitter?: GitCommitter; // default: Ever Works Bot
}

interface GitCommitter {
name: string;
email: string;
}

Constructor​

const gitOps = new GitOperations(
(token) => ({ username: 'x-access-token', password: token }), // getAuth
(owner, repo) => `https://github.com/${owner}/${repo}.git`, // getCloneUrl
{ baseDir: '/tmp/repos' } // optional config
);

Core Operations​

Clone and Pull​

MethodDescription
cloneOrPull(options)Clones a repo or pulls if already cloned. Auto-switches to main branch.
pull(dir, token, committer?)Pulls latest changes from remote
cloneBranch(params)Clones a specific branch into a unique work

The cloneOrPull method handles several edge cases:

  • If the work exists, attempts a pull first; on failure, removes and re-clones
  • If the remote repository is empty or not found, initializes a new repo with git init
  • Automatically switches to the main branch before pulling
const dir = await gitOps.cloneOrPull({
owner: 'my-org',
repo: 'my-work',
token: 'ghp_...',
branch: 'main',
autoSwitchToMainBranch: true
});
// => '/tmp/ever-works-repos/my-org-my-work'

Staging and Committing​

MethodDescription
add(dir, paths)Stage specific file paths
addAll(dir)Stage all changed, new, and deleted files
commit(dir, message, committer?)Create a commit

The addAll method uses git.statusMatrix to correctly handle additions, modifications, and deletions:

await gitOps.addAll(dir);
await gitOps.commit(dir, 'Update work content', {
name: 'Ever Works Bot',
email: 'bot@ever.works'
});

Pushing​

The push method includes automatic retry with exponential backoff for transient failures:

await gitOps.push({
dir,
token: 'ghp_...',
force: false,
maxRetries: 3 // default
});

Retryable errors: cannot lock ref, failed to lock, ETIMEDOUT, ECONNRESET

Branch Management​

MethodDescription
getCurrentBranch(dir)Get the current branch name
getMainBranch(dir)Find main or master branch
switchBranch(dir, branch, create?)Switch to or create a branch
renameBranch(dir, oldName, newName)Rename a branch
createAndSwitchToRandomBranch(dir, prefix?)Create a unique timestamped branch
// Create a feature branch with unique name
const branchName = await gitOps.createAndSwitchToRandomBranch(dir, 'feature');
// => 'feature-1709567234567-a1b2c3'

The renameBranch method handles edge cases:

  • If the new branch already exists, checks out to it and deletes the old one
  • Preserves commit history by resolving the commit SHA before renaming

File Status​

const changes = await gitOps.getStatus(dir);
// [
// { path: 'README.md', status: 'modified' },
// { path: 'new-item.md', status: 'added' },
// { path: 'old-item.md', status: 'deleted' },
// ]

Status types: added, deleted, modified, untracked

Remote Management​

MethodDescription
remoteAdd(dir, remote, url)Add a remote
remoteRemove(dir, remote)Remove a remote
replaceRemote(dir, remote, url)Replace a remote (remove + add)
fetch(dir, token, remote?)Fetch from remote
merge(dir, ours, theirs, committer?)Merge branches

Work Management​

MethodDescription
getLocalDir(owner, repo)Get the local work path for a repo
removeLocalDir(owner, repo)Remove the local clone

The local work path is generated by slugifying {owner}-{repo} and placing it under the configured baseDir.

Error Handling​

The class implements robust error handling:

  • Clone failures for empty/missing repos fall back to git init + addRemote
  • Push failures retry up to 3 times with exponential backoff (1s, 2s, 4s)
  • Work removal retries up to 3 times, handling ENOTEMPTY by removing .git first
  • Branch operations gracefully handle missing branches

Default Branch Detection​

The module uses ['main', 'master'] as the ordered list of default branch names. The switchToMainBranch private method checks the current branch, then searches for a default branch to switch to.

Type Exports​

The module re-exports all git-related types from the contracts package for convenience:

TypeDescription
GitAuthAuthentication credentials (username/password)
GitRepositoryRepository metadata
GitBranchBranch information
GitCommitCommit data
GitPullRequestPull request details
CreateRepoOptionsOptions for creating repositories
CreatePROptionsOptions for creating pull requests
ListRepositoriesOptionsOptions for listing repositories

File Structure​

plugin/src/git/
index.ts # Public exports and type re-exports
git-operations.ts # GitOperations class implementation