Skip to content

Commit 47a3d44

Browse files
authored
Git branch flow improvements (#370)
1 parent eb10910 commit 47a3d44

File tree

20 files changed

+851
-412
lines changed

20 files changed

+851
-412
lines changed

crates-tauri/yaak-app/src/git_ext.rs

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,32 +6,47 @@ use crate::error::Result;
66
use std::path::{Path, PathBuf};
77
use tauri::command;
88
use yaak_git::{
9-
GitCommit, GitRemote, GitStatusSummary, PullResult, PushResult, git_add, git_add_credential,
10-
git_add_remote, git_checkout_branch, git_commit, git_create_branch, git_delete_branch,
11-
git_fetch_all, git_init, git_log, git_merge_branch, git_pull, git_push, git_remotes,
9+
BranchDeleteResult, CloneResult, GitCommit, GitRemote, GitStatusSummary, PullResult,
10+
PushResult, git_add, git_add_credential, git_add_remote, git_checkout_branch, git_clone,
11+
git_commit, git_create_branch, git_delete_branch, git_delete_remote_branch, git_fetch_all,
12+
git_init, git_log, git_merge_branch, git_pull, git_push, git_remotes, git_rename_branch,
1213
git_rm_remote, git_status, git_unstage,
1314
};
1415

1516
// NOTE: All of these commands are async to prevent blocking work from locking up the UI
1617

1718
#[command]
1819
pub async fn cmd_git_checkout(dir: &Path, branch: &str, force: bool) -> Result<String> {
19-
Ok(git_checkout_branch(dir, branch, force)?)
20+
Ok(git_checkout_branch(dir, branch, force).await?)
2021
}
2122

2223
#[command]
23-
pub async fn cmd_git_branch(dir: &Path, branch: &str) -> Result<()> {
24-
Ok(git_create_branch(dir, branch)?)
24+
pub async fn cmd_git_branch(dir: &Path, branch: &str, base: Option<&str>) -> Result<()> {
25+
Ok(git_create_branch(dir, branch, base).await?)
2526
}
2627

2728
#[command]
28-
pub async fn cmd_git_delete_branch(dir: &Path, branch: &str) -> Result<()> {
29-
Ok(git_delete_branch(dir, branch)?)
29+
pub async fn cmd_git_delete_branch(
30+
dir: &Path,
31+
branch: &str,
32+
force: Option<bool>,
33+
) -> Result<BranchDeleteResult> {
34+
Ok(git_delete_branch(dir, branch, force.unwrap_or(false)).await?)
35+
}
36+
37+
#[command]
38+
pub async fn cmd_git_delete_remote_branch(dir: &Path, branch: &str) -> Result<()> {
39+
Ok(git_delete_remote_branch(dir, branch).await?)
3040
}
3141

3242
#[command]
33-
pub async fn cmd_git_merge_branch(dir: &Path, branch: &str, force: bool) -> Result<()> {
34-
Ok(git_merge_branch(dir, branch, force)?)
43+
pub async fn cmd_git_merge_branch(dir: &Path, branch: &str) -> Result<()> {
44+
Ok(git_merge_branch(dir, branch).await?)
45+
}
46+
47+
#[command]
48+
pub async fn cmd_git_rename_branch(dir: &Path, old_name: &str, new_name: &str) -> Result<()> {
49+
Ok(git_rename_branch(dir, old_name, new_name).await?)
3550
}
3651

3752
#[command]
@@ -49,6 +64,11 @@ pub async fn cmd_git_initialize(dir: &Path) -> Result<()> {
4964
Ok(git_init(dir)?)
5065
}
5166

67+
#[command]
68+
pub async fn cmd_git_clone(url: &str, dir: &Path) -> Result<CloneResult> {
69+
Ok(git_clone(url, dir).await?)
70+
}
71+
5272
#[command]
5373
pub async fn cmd_git_commit(dir: &Path, message: &str) -> Result<()> {
5474
Ok(git_commit(dir, message).await?)
@@ -87,12 +107,11 @@ pub async fn cmd_git_unstage(dir: &Path, rela_paths: Vec<PathBuf>) -> Result<()>
87107

88108
#[command]
89109
pub async fn cmd_git_add_credential(
90-
dir: &Path,
91110
remote_url: &str,
92111
username: &str,
93112
password: &str,
94113
) -> Result<()> {
95-
Ok(git_add_credential(dir, remote_url, username, password).await?)
114+
Ok(git_add_credential(remote_url, username, password).await?)
96115
}
97116

98117
#[command]

crates-tauri/yaak-app/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ struct AppMetaData {
101101
app_data_dir: String,
102102
app_log_dir: String,
103103
vendored_plugin_dir: String,
104+
default_project_dir: String,
104105
feature_updater: bool,
105106
feature_license: bool,
106107
}
@@ -111,13 +112,15 @@ async fn cmd_metadata(app_handle: AppHandle) -> YaakResult<AppMetaData> {
111112
let app_log_dir = app_handle.path().app_log_dir()?;
112113
let vendored_plugin_dir =
113114
app_handle.path().resolve("vendored/plugins", BaseDirectory::Resource)?;
115+
let default_project_dir = app_handle.path().home_dir()?.join("YaakProjects");
114116
Ok(AppMetaData {
115117
is_dev: is_dev(),
116118
version: app_handle.package_info().version.to_string(),
117119
name: app_handle.package_info().name.to_string(),
118120
app_data_dir: app_data_dir.to_string_lossy().to_string(),
119121
app_log_dir: app_log_dir.to_string_lossy().to_string(),
120122
vendored_plugin_dir: vendored_plugin_dir.to_string_lossy().to_string(),
123+
default_project_dir: default_project_dir.to_string_lossy().to_string(),
121124
feature_license: cfg!(feature = "license"),
122125
feature_updater: cfg!(feature = "updater"),
123126
})
@@ -1747,10 +1750,13 @@ pub fn run() {
17471750
git_ext::cmd_git_checkout,
17481751
git_ext::cmd_git_branch,
17491752
git_ext::cmd_git_delete_branch,
1753+
git_ext::cmd_git_delete_remote_branch,
17501754
git_ext::cmd_git_merge_branch,
1755+
git_ext::cmd_git_rename_branch,
17511756
git_ext::cmd_git_status,
17521757
git_ext::cmd_git_log,
17531758
git_ext::cmd_git_initialize,
1759+
git_ext::cmd_git_clone,
17541760
git_ext::cmd_git_commit,
17551761
git_ext::cmd_git_fetch_all,
17561762
git_ext::cmd_git_push,

crates/yaak-git/bindings/gen_git.ts

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/yaak-git/index.ts

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { invoke } from '@tauri-apps/api/core';
33
import { createFastMutation } from '@yaakapp/app/hooks/useFastMutation';
44
import { queryClient } from '@yaakapp/app/lib/queryClient';
55
import { useMemo } from 'react';
6-
import { GitCommit, GitRemote, GitStatusSummary, PullResult, PushResult } from './bindings/gen_git';
6+
import { BranchDeleteResult, CloneResult, GitCommit, GitRemote, GitStatusSummary, PullResult, PushResult } from './bindings/gen_git';
77

88
export * from './bindings/gen_git';
99

@@ -59,7 +59,6 @@ export const gitMutations = (dir: string, callbacks: GitCallbacks) => {
5959
if (creds == null) throw new Error('Canceled');
6060

6161
await invoke('cmd_git_add_credential', {
62-
dir,
6362
remoteUrl: result.url,
6463
username: creds.username,
6564
password: creds.password,
@@ -90,21 +89,31 @@ export const gitMutations = (dir: string, callbacks: GitCallbacks) => {
9089
mutationFn: (args) => invoke('cmd_git_rm_remote', { dir, ...args }),
9190
onSuccess,
9291
}),
93-
branch: createFastMutation<void, string, { branch: string }>({
92+
createBranch: createFastMutation<void, string, { branch: string; base?: string }>({
9493
mutationKey: ['git', 'branch', dir],
9594
mutationFn: (args) => invoke('cmd_git_branch', { dir, ...args }),
9695
onSuccess,
9796
}),
98-
mergeBranch: createFastMutation<void, string, { branch: string; force: boolean }>({
97+
mergeBranch: createFastMutation<void, string, { branch: string }>({
9998
mutationKey: ['git', 'merge', dir],
10099
mutationFn: (args) => invoke('cmd_git_merge_branch', { dir, ...args }),
101100
onSuccess,
102101
}),
103-
deleteBranch: createFastMutation<void, string, { branch: string }>({
102+
deleteBranch: createFastMutation<BranchDeleteResult, string, { branch: string, force?: boolean }>({
104103
mutationKey: ['git', 'delete-branch', dir],
105104
mutationFn: (args) => invoke('cmd_git_delete_branch', { dir, ...args }),
106105
onSuccess,
107106
}),
107+
deleteRemoteBranch: createFastMutation<void, string, { branch: string }>({
108+
mutationKey: ['git', 'delete-remote-branch', dir],
109+
mutationFn: (args) => invoke('cmd_git_delete_remote_branch', { dir, ...args }),
110+
onSuccess,
111+
}),
112+
renameBranch: createFastMutation<void, string, { oldName: string, newName: string }>({
113+
mutationKey: ['git', 'rename-branch', dir],
114+
mutationFn: (args) => invoke('cmd_git_rename_branch', { dir, ...args }),
115+
onSuccess,
116+
}),
108117
checkout: createFastMutation<string, string, { branch: string; force: boolean }>({
109118
mutationKey: ['git', 'checkout', dir],
110119
mutationFn: (args) => invoke('cmd_git_checkout', { dir, ...args }),
@@ -144,7 +153,6 @@ export const gitMutations = (dir: string, callbacks: GitCallbacks) => {
144153
if (creds == null) throw new Error('Canceled');
145154

146155
await invoke('cmd_git_add_credential', {
147-
dir,
148156
remoteUrl: result.url,
149157
username: creds.username,
150158
password: creds.password,
@@ -166,3 +174,28 @@ export const gitMutations = (dir: string, callbacks: GitCallbacks) => {
166174
async function getRemotes(dir: string) {
167175
return invoke<GitRemote[]>('cmd_git_remotes', { dir });
168176
}
177+
178+
/**
179+
* Clone a git repository, prompting for credentials if needed.
180+
*/
181+
export async function gitClone(
182+
url: string,
183+
dir: string,
184+
promptCredentials: (args: { url: string; error: string | null }) => Promise<GitCredentials | null>,
185+
): Promise<CloneResult> {
186+
const result = await invoke<CloneResult>('cmd_git_clone', { url, dir });
187+
if (result.type !== 'needs_credentials') return result;
188+
189+
// Prompt for credentials
190+
const creds = await promptCredentials({ url: result.url, error: result.error });
191+
if (creds == null) return {type: 'cancelled'};
192+
193+
// Store credentials and retry
194+
await invoke('cmd_git_add_credential', {
195+
remoteUrl: result.url,
196+
username: creds.username,
197+
password: creds.password,
198+
});
199+
200+
return invoke<CloneResult>('cmd_git_clone', { url, dir });
201+
}

crates/yaak-git/src/binary.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,15 @@ use std::process::Stdio;
55
use tokio::process::Command;
66
use yaak_common::command::new_xplatform_command;
77

8+
/// Create a git command that runs in the specified directory
89
pub(crate) async fn new_binary_command(dir: &Path) -> Result<Command> {
10+
let mut cmd = new_binary_command_global().await?;
11+
cmd.arg("-C").arg(dir);
12+
Ok(cmd)
13+
}
14+
15+
/// Create a git command without a specific directory (for global operations)
16+
pub(crate) async fn new_binary_command_global() -> Result<Command> {
917
// 1. Probe that `git` exists and is runnable
1018
let mut probe = new_xplatform_command("git");
1119
probe.arg("--version").stdin(Stdio::null()).stdout(Stdio::null()).stderr(Stdio::null());
@@ -17,8 +25,6 @@ pub(crate) async fn new_binary_command(dir: &Path) -> Result<Command> {
1725
}
1826

1927
// 2. Build the reusable git command
20-
let mut cmd = new_xplatform_command("git");
21-
cmd.arg("-C").arg(dir);
22-
28+
let cmd = new_xplatform_command("git");
2329
Ok(cmd)
2430
}

0 commit comments

Comments
 (0)