diff --git a/CHANGELOG.md b/CHANGELOG.md index 49001fba26c65..e02f4e0af7e88 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ### Changed +- Changes how GitLens handles creating and renaming branches to avoid using the terminal — refs [#3528](https://github.com/gitkraken/vscode-gitlens/issues/3528) + ### Fixed - Fixes [#3592](https://github.com/gitkraken/vscode-gitlens/issues/3592) - Connecting to an integration via Remotes view (but likely others) doesn't work diff --git a/src/commands/git/branch.ts b/src/commands/git/branch.ts index b6938ca8cea9b..8712422e81e89 100644 --- a/src/commands/git/branch.ts +++ b/src/commands/git/branch.ts @@ -5,11 +5,13 @@ import { getNameWithoutRemote, getReferenceLabel, isRevisionReference } from '.. import { Repository } from '../../git/models/repository'; import type { GitWorktree } from '../../git/models/worktree'; import { getWorktreesByBranch } from '../../git/models/worktree'; +import { showGenericErrorMessage } from '../../messages'; import type { QuickPickItemOfT } from '../../quickpicks/items/common'; import { createQuickPickSeparator } from '../../quickpicks/items/common'; import type { FlagsQuickPickItem } from '../../quickpicks/items/flags'; import { createFlagsQuickPickItem } from '../../quickpicks/items/flags'; import { ensureArray } from '../../system/array'; +import { Logger } from '../../system/logger'; import { pluralize } from '../../system/string'; import type { ViewsWithRepositoryFolders } from '../../views/viewBase'; import type { @@ -393,7 +395,13 @@ export class BranchGitCommand extends QuickCommand { if (state.flags.includes('--switch')) { await state.repo.switch(state.reference.ref, { createBranch: state.name }); } else { - state.repo.branch(...state.flags, state.name, state.reference.ref); + try { + await state.repo.git.createBranch(state.name, state.reference.ref); + } catch (ex) { + Logger.error(ex); + // TODO likely need some better error handling here + return showGenericErrorMessage('Unable to create branch'); + } } } } @@ -614,7 +622,13 @@ export class BranchGitCommand extends QuickCommand { state.flags = result; endSteps(state); - state.repo.branch(...state.flags, state.reference.ref, state.name); + try { + await state.repo.git.renameBranch(state.reference.ref, state.name); + } catch (ex) { + Logger.error(ex); + // TODO likely need some better error handling here + return showGenericErrorMessage('Unable to rename branch'); + } } } diff --git a/src/env/node/git/git.ts b/src/env/node/git/git.ts index 3bbba673336bc..b4c0904884173 100644 --- a/src/env/node/git/git.ts +++ b/src/env/node/git/git.ts @@ -506,6 +506,10 @@ export class Git { } } + branch(repoPath: string, ...args: string[]) { + return this.git({ cwd: repoPath }, 'branch', ...args); + } + branch__set_upstream(repoPath: string, branch: string, remote: string, remoteBranch: string) { return this.git({ cwd: repoPath }, 'branch', '--set-upstream-to', `${remote}/${remoteBranch}`, branch); } diff --git a/src/env/node/git/localGitProvider.ts b/src/env/node/git/localGitProvider.ts index 14c72acd7944d..23a51475eb05f 100644 --- a/src/env/node/git/localGitProvider.ts +++ b/src/env/node/git/localGitProvider.ts @@ -1230,6 +1230,16 @@ export class LocalGitProvider implements GitProvider, Disposable { } } + @log() + async createBranch(repoPath: string, name: string, ref: string): Promise { + await this.git.branch(repoPath, name, ref); + } + + @log() + async renameBranch(repoPath: string, oldName: string, newName: string): Promise { + await this.git.branch(repoPath, '-m', oldName, newName); + } + @log() async checkout( repoPath: string, diff --git a/src/git/gitProvider.ts b/src/git/gitProvider.ts index 233925e19301c..62fe2e32b697d 100644 --- a/src/git/gitProvider.ts +++ b/src/git/gitProvider.ts @@ -113,9 +113,13 @@ export interface RepositoryVisibilityInfo { } export interface GitProviderRepository { + createBranch?(repoPath: string, name: string, ref: string): Promise; + renameBranch?(repoPath: string, oldName: string, newName: string): Promise; + addRemote?(repoPath: string, name: string, url: string, options?: { fetch?: boolean }): Promise; pruneRemote?(repoPath: string, name: string): Promise; removeRemote?(repoPath: string, name: string): Promise; + applyUnreachableCommitForPatch?( repoPath: string, ref: string, diff --git a/src/git/gitProviderService.ts b/src/git/gitProviderService.ts index 50f94495e5ee8..1bf5c1144bec7 100644 --- a/src/git/gitProviderService.ts +++ b/src/git/gitProviderService.ts @@ -1338,6 +1338,22 @@ export class GitProviderService implements Disposable { return provider.applyUnreachableCommitForPatch(path, ref, options); } + @log() + createBranch(repoPath: string | Uri, name: string, ref: string): Promise { + const { provider, path } = this.getProvider(repoPath); + if (provider.createBranch == null) throw new ProviderNotSupportedError(provider.descriptor.name); + + return provider.createBranch(path, name, ref); + } + + @log() + renameBranch(repoPath: string | Uri, oldName: string, newName: string): Promise { + const { provider, path } = this.getProvider(repoPath); + if (provider.renameBranch == null) throw new ProviderNotSupportedError(provider.descriptor.name); + + return provider.renameBranch(path, oldName, newName); + } + @log() checkout( repoPath: string | Uri, diff --git a/src/git/models/repository.ts b/src/git/models/repository.ts index 238e8506cbd00..633462a3d414d 100644 --- a/src/git/models/repository.ts +++ b/src/git/models/repository.ts @@ -560,11 +560,6 @@ export class Repository implements Disposable { return remote; } - @log() - branch(...args: string[]) { - void this.runTerminalCommand('branch', ...args); - } - @log() branchDelete(branches: GitBranchReference | GitBranchReference[], options?: { force?: boolean; remote?: boolean }) { if (!Array.isArray(branches)) {