add git branch picker + status bar indicator
git.branches and git.checkout IPC verbs. Status bar shows current branch with ahead/behind count; clicking opens a branch picker dialog for checkout. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -218,6 +218,37 @@ void registerGitCommands(
|
||||
return _gitError(req.id, e);
|
||||
}
|
||||
});
|
||||
|
||||
d.register('git.branches', (req) async {
|
||||
final branches = await gitBranches(workDir);
|
||||
return IpcResponse.ok(id: req.id, data: {
|
||||
'branches': [
|
||||
for (final b in branches)
|
||||
{'name': b.name, 'current': b.current},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
d.register('git.checkout', (req) async {
|
||||
final branch = req.args['branch'] as String?;
|
||||
if (branch == null || branch.isEmpty) {
|
||||
return IpcResponse.err(
|
||||
id: req.id,
|
||||
error: IpcError(
|
||||
code: IpcExitCode.userError,
|
||||
kind: IpcErrorKind.userError,
|
||||
message: 'git.checkout requires a branch',
|
||||
),
|
||||
);
|
||||
}
|
||||
try {
|
||||
await gitCheckout(workDir, branch);
|
||||
_emitChanged(events);
|
||||
return IpcResponse.ok(id: req.id, data: {'branch': branch});
|
||||
} on GitException catch (e) {
|
||||
return _gitError(req.id, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
List<String> _pathList(Object? raw) {
|
||||
|
||||
@@ -194,6 +194,37 @@ Future<String> gitPush(
|
||||
return ((r.stdout as String) + (r.stderr as String)).trim();
|
||||
}
|
||||
|
||||
/// List local branches. Returns (name, isCurrent) pairs.
|
||||
Future<List<({String name, bool current})>> gitBranches(
|
||||
Directory workDir) async {
|
||||
final r = await Process.run(
|
||||
'git',
|
||||
['branch', '--format=%(refname:short)\x00%(HEAD)'],
|
||||
workingDirectory: workDir.path,
|
||||
);
|
||||
if (r.exitCode != 0) return const [];
|
||||
final out = <({String name, bool current})>[];
|
||||
for (final line in (r.stdout as String).split('\n')) {
|
||||
if (line.trim().isEmpty) continue;
|
||||
final parts = line.split('\x00');
|
||||
if (parts.length < 2) continue;
|
||||
out.add((name: parts[0], current: parts[1].trim() == '*'));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/// Checkout a branch.
|
||||
Future<void> gitCheckout(Directory workDir, String branch) async {
|
||||
final r = await Process.run(
|
||||
'git',
|
||||
['checkout', branch],
|
||||
workingDirectory: workDir.path,
|
||||
);
|
||||
if (r.exitCode != 0) {
|
||||
throw GitException('git checkout failed', stderr: r.stderr as String);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the current branch name.
|
||||
Future<String?> gitCurrentBranch(Directory workDir) async {
|
||||
final r = await Process.run(
|
||||
|
||||
Reference in New Issue
Block a user