Releases: desktop/dugite
v3.0.0
What's included
Git: v2.47.3
Git for Windows: v2.47.3.windows.1
Git LFS: v3.7.1
Git Credential Manager: v2.6.1
What's Changed
The API has been significantly reworked, removing the static class GitProcess in favor of more idiomatic exec and spawn functions (#591). These new functions support cancellation via AbortSignal that gets passed down to the underlying spawn allowing termination of Git processes via signals.
Breaking changes
- Drop support for node 14 and 16 by @niik in #566
- Use dugite system config by @niik in #563
- Handle env vars in a case-preserving, case-insensitive manner on Windows by @niik in #574
- For macOS and Linux dugite now overrides the system level
gitconfigwith its own (which inherits the system config) in order for us to be able to provide sane defaults for credential managers, see https://github.com/desktop/dugite-native/blob/main/resources/posix.gitconfig - maxBuffer is now
Infinityby default - Exceptions returned from
execare now of theExecErrortype which includes the raw stdout and stderr
Notable changes
- Removed jest in favor of Node test runner by @niik in #583
- Add support for detecting push with secrets error by @tidy-dev in #608
Migration guide
API Restructuring
Removed: GitProcess Class
2.7.1:
import { GitProcess } from 'dugite'
// Using static methods
const result = await GitProcess.exec(['status'], '/path/to/repo')
const child = GitProcess.spawn(['log'], '/path/to/repo')
const error = GitProcess.parseError(stderr)3.0.0:
import { exec, spawn, parseError } from 'dugite'
// Using standalone functions
const result = await exec(['status'], '/path/to/repo')
const child = spawn(['log'], '/path/to/repo')
const error = parseError(stderr)Migration: Replace all GitProcess.method() calls with direct function imports and calls.
Removed: GitProcess.execTask() and IGitTask
The execTask() method and its associated IGitTask interface have been removed entirely in 3.0.0. It's sole purpose
was to provide cancellation support, which is now handled via passing an AbortSignal to exec() or spawn().
2.7.1:
const task = GitProcess.execTask(['clone', url], '/path/to/repo')
// Access result promise
const result = await task.result
// Cancel the task
const cancelResult = await task.cancel()3.0.0 Alternative:
// Use AbortController for cancellation
const controller = new AbortController()
const resultPromise = exec(['clone', url], '/path/to/repo', {
signal: controller.signal,
})
// Cancel if needed
controller.abort()
try {
const result = await resultPromise
} catch (error) {
// Handle cancellation
}Migration:
- Replace
execTask()withexec() - Use
AbortControllerandsignaloption for cancellation support - Remove references to
IGitTaskandGitTaskCancelResult
Removed: GitTaskCancelResult Enum
The GitTaskCancelResult enum has been removed along with IGitTask.
Migration: Handle cancellation using standard promise rejection with AbortController.
Type System Changes
1. Environment Variable Types
2.7.1:
interface IGitExecutionOptions {
readonly env?: object // Generic object type
}
interface IGitSpawnExecutionOptions {
readonly env?: object // Generic object type
}3.0.0:
interface IGitExecutionOptions {
readonly env?: Record<string, string | undefined> // More specific type
}
interface IGitSpawnOptions {
readonly env?: Record<string, string | undefined> // More specific type
}Migration: Ensure environment variables are typed as Record<string, string | undefined> instead of generic object.
2. Encoding support
Both exec and spawn now support returning output as either string or Buffer based on the encoding option.
2.7.1:
interface IGitResult {
readonly stdout: string // Always string
readonly stderr: string // Always string
readonly exitCode: number
}3.0.0:
interface IGitResult {
readonly stdout: string | Buffer // Can be Buffer
readonly stderr: string | Buffer // Can be Buffer
readonly exitCode: number
}
// New specialized interfaces
interface IGitStringResult extends IGitResult {
readonly stdout: string
readonly stderr: string
}
interface IGitBufferResult extends IGitResult {
readonly stdout: Buffer
readonly stderr: Buffer
}Migration:
- If you need string output (default), use type narrowing or the
IGitStringResulttype - For buffer output, explicitly set
encoding: 'buffer'and useIGitBufferResult - Update code that assumes
stdout/stderrare always strings
3. Execution Options Enhancements
New in 3.0.0:
interface IGitExecutionOptions {
// New options
readonly encoding?: BufferEncoding | 'buffer' // Control output encoding
readonly signal?: AbortSignal // AbortController support
readonly killSignal?: ExecFileOptions['killSignal'] // Custom kill signal
// Changed: maxBuffer now defaults to Infinity instead of 10MB
readonly maxBuffer?: number
}Migration:
- The default
maxBufferchanged from 10MB (10485760 bytes) toInfinity - If you relied on the 10MB limit, explicitly set
maxBuffer: 10485760 - Use
encodingoption to control output format (string vs buffer) - Use
signaloption withAbortControllerfor cancellation
4. Interface Renames
2.7.1:
IGitSpawnExecutionOptions // For spawn options3.0.0:
IGitSpawnOptions // Renamed, shorter nameMigration: Rename IGitSpawnExecutionOptions to IGitSpawnOptions.
Function Changes
1. New Exported Functions
3.0.0 exposes several new utility functions:
// Git directory resolution
function resolveEmbeddedGitDir(): string
function resolveGitDir(localGitDir?: string): string
function resolveGitBinary(localGitDir?: string): string
function resolveGitExecPath(localGitDir?: string, gitExecPath?: string): string
// Input stream handling
function ignoreClosedInputStream({ stdin }: ChildProcess): voidMigration: These are new utilities you can optionally use for advanced scenarios.
2. New Export: EnvMap Class
A platform-aware environment variable map (case-insensitive on Windows):
class EnvMap implements Map<string, string | undefined> {
// Standard Map interface
}New Features
1. New Error Class: ExecError
3.0.0 introduces a structured error class for execution failures:
class ExecError extends Error {
readonly message: string
readonly stdout: Buffer | string
readonly stderr: Buffer | string
readonly code?: string
readonly signal?: string
readonly killed?: boolean
}3. AbortController Support
You can now cancel long-running git operations:
const controller = new AbortController()
const result = exec(['clone', 'https://...'], '/path', {
signal: AbortController.timeout(5000), // Auto-cancel after 5 seconds
})Migration Guide
Step 1: Update Imports
Before (2.7.1):
import {
GitProcess,
IGitResult,
IGitExecutionOptions,
IGitTask,
GitTaskCancelResult,
GitError,
} from 'dugite'After (3.0.0):
import {
exec,
spawn,
parseError,
parseBadConfigValueErrorInfo,
IGitResult,
IGitStringResult,
IGitBufferResult,
IGitExecutionOptions,
IGitSpawnOptions,
GitError,
ExecError,
} from 'dugite'Step 2: Replace GitProcess Static Methods
Before:
const result = await GitProcess.exec(args, path, options)
const child = GitProcess.spawn(args, path, options)
const error = GitProcess.parseError(stderr)After:
const result = await exec(args, path, options)
const child = spawn(args, path, options)
const error = parseError(stderr)Step 3: Replace execTask() with exec() + AbortController
Before:
const task = GitProcess.execTask(['clone', url], path)
// Later...
await task.cancel()
const result = await task.resultAfter:
const controller = new AbortController()
const resultPromise = exec(['clone', url], path, {
signal: controller.signal,
})
// Later...
controller.abort()Step 4: Review maxBuffer Usage
If you were relying on the default 10MB limit:
Before (2.7.1):
// Default maxBuffer was 10485760 (10MB)
const result = await GitProcess.exec(args, path)After (3.0.0):
// Default is now Infinity, explicitly set if needed
const result = await exec(args, path, {
maxBuffer: 10485760, // Restore old default
})Summary
The migration from 2.7.1 to 3.0.0 primarily involves:
- ✅ Replace
GitProcess.method()with standalone function imports - ✅ Remove usage of
execTask(),IGitTask, andGitTaskCancelResult - ✅ Use
AbortControllerfor cancellation - ✅ Update environment variable types to
Record<string, string | undefined> - ✅ Handle
stdout/stderras potentiallyBufferor use specialized result types - ✅ Rename
IGitSpawnExecutionOptionstoIGitSpawnOptions - ✅ Review and explicitly set
maxBufferif the old 10MB default was important - ✅ Update
setupEnvironment()calls wi...