Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion designs/connect.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
"Cherry-pick": "cherry-pick",
"Rebase": "rebase",
"Files": "file-tree",
"GitHub": "hosting"
"GitHub": "hosting",
"Submodules": "submodules",
"Worktrees": "worktrees"
}
},
{
Expand Down
2 changes: 2 additions & 0 deletions src-tauri/src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,6 @@ pub mod reset;
pub mod revert;
pub mod search;
pub mod stash;
pub mod submodule;
pub mod tag;
pub mod worktree;
60 changes: 60 additions & 0 deletions src-tauri/src/commands/submodule.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
use tauri::State;

use crate::git::types::SubmoduleInfo;
use crate::state::AppState;

#[tauri::command]
pub fn list_submodules(state: State<'_, AppState>) -> Result<Vec<SubmoduleInfo>, String> {
let repo_lock = state
.repo
.lock()
.map_err(|e| format!("Lock poisoned: {e}"))?;
let backend = repo_lock.as_ref().ok_or("No repository opened")?;
backend.list_submodules().map_err(|e| e.to_string())
}

#[tauri::command]
pub fn add_submodule(url: String, path: String, state: State<'_, AppState>) -> Result<(), String> {
let repo_lock = state
.repo
.lock()
.map_err(|e| format!("Lock poisoned: {e}"))?;
let backend = repo_lock.as_ref().ok_or("No repository opened")?;
backend
.add_submodule(&url, &path)
.map_err(|e| e.to_string())
}

#[tauri::command]
pub fn update_submodule(path: String, state: State<'_, AppState>) -> Result<(), String> {
let repo_lock = state
.repo
.lock()
.map_err(|e| format!("Lock poisoned: {e}"))?;
let backend = repo_lock.as_ref().ok_or("No repository opened")?;
backend
.update_submodule(&path)
.map_err(|e| e.to_string())
}

#[tauri::command]
pub fn update_all_submodules(state: State<'_, AppState>) -> Result<(), String> {
let repo_lock = state
.repo
.lock()
.map_err(|e| format!("Lock poisoned: {e}"))?;
let backend = repo_lock.as_ref().ok_or("No repository opened")?;
backend.update_all_submodules().map_err(|e| e.to_string())
}

#[tauri::command]
pub fn remove_submodule(path: String, state: State<'_, AppState>) -> Result<(), String> {
let repo_lock = state
.repo
.lock()
.map_err(|e| format!("Lock poisoned: {e}"))?;
let backend = repo_lock.as_ref().ok_or("No repository opened")?;
backend
.remove_submodule(&path)
.map_err(|e| e.to_string())
}
42 changes: 42 additions & 0 deletions src-tauri/src/commands/worktree.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use tauri::State;

use crate::git::types::WorktreeInfo;
use crate::state::AppState;

#[tauri::command]
pub fn list_worktrees(state: State<'_, AppState>) -> Result<Vec<WorktreeInfo>, String> {
let repo_lock = state
.repo
.lock()
.map_err(|e| format!("Lock poisoned: {e}"))?;
let backend = repo_lock.as_ref().ok_or("No repository opened")?;
backend.list_worktrees().map_err(|e| e.to_string())
}

#[tauri::command]
pub fn add_worktree(
path: String,
branch: String,
state: State<'_, AppState>,
) -> Result<(), String> {
let repo_lock = state
.repo
.lock()
.map_err(|e| format!("Lock poisoned: {e}"))?;
let backend = repo_lock.as_ref().ok_or("No repository opened")?;
backend
.add_worktree(&path, &branch)
.map_err(|e| e.to_string())
}

#[tauri::command]
pub fn remove_worktree(path: String, state: State<'_, AppState>) -> Result<(), String> {
let repo_lock = state
.repo
.lock()
.map_err(|e| format!("Lock poisoned: {e}"))?;
let backend = repo_lock.as_ref().ok_or("No repository opened")?;
backend
.remove_worktree(&path)
.map_err(|e| e.to_string())
}
15 changes: 14 additions & 1 deletion src-tauri/src/git/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ use crate::git::types::{
CommitLogResult, CommitResult, ConflictFile, ConflictResolution, DiffOptions, FetchResult,
FileDiff, HunkIdentifier, LineRange, LogFilter, MergeBaseContent, MergeOption, MergeResult,
PullOption, PushResult, RebaseResult, RebaseState, RebaseTodoEntry, ReflogEntry, RemoteInfo,
RepoStatus, ResetMode, ResetResult, RevertMode, RevertResult, StashEntry, TagInfo,
RepoStatus, ResetMode, ResetResult, RevertMode, RevertResult, StashEntry, SubmoduleInfo,
TagInfo, WorktreeInfo,
};

pub trait GitBackend: Send + Sync {
Expand Down Expand Up @@ -114,4 +115,16 @@ pub trait GitBackend: Send + Sync {
fn search_code(&self, query: &str, is_regex: bool) -> GitResult<Vec<CodeSearchResult>>;
fn search_commits(&self, query: &str, search_diff: bool) -> GitResult<Vec<CommitSearchResult>>;
fn search_filenames(&self, query: &str) -> GitResult<Vec<FilenameSearchResult>>;

// Submodule operations
fn list_submodules(&self) -> GitResult<Vec<SubmoduleInfo>>;
fn add_submodule(&self, url: &str, path: &str) -> GitResult<()>;
fn update_submodule(&self, path: &str) -> GitResult<()>;
fn update_all_submodules(&self) -> GitResult<()>;
fn remove_submodule(&self, path: &str) -> GitResult<()>;

// Worktree operations
fn list_worktrees(&self) -> GitResult<Vec<WorktreeInfo>>;
fn add_worktree(&self, path: &str, branch: &str) -> GitResult<()>;
fn remove_worktree(&self, path: &str) -> GitResult<()>;
}
6 changes: 6 additions & 0 deletions src-tauri/src/git/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,12 @@ pub enum GitError {

#[error("search failed: {0}")]
SearchFailed(#[source] Box<dyn std::error::Error + Send + Sync>),

#[error("submodule operation failed: {0}")]
SubmoduleFailed(#[source] Box<dyn std::error::Error + Send + Sync>),

#[error("worktree operation failed: {0}")]
WorktreeFailed(#[source] Box<dyn std::error::Error + Send + Sync>),
}

pub type GitResult<T> = Result<T, GitError>;
37 changes: 36 additions & 1 deletion src-tauri/src/git/git2_backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ use crate::git::auth::create_credentials_callback;
use crate::git::backend::GitBackend;
use crate::git::error::{GitError, GitResult};
use crate::git::search::{self, CodeSearchResult, CommitSearchResult, FilenameSearchResult};
use crate::git::submodule;
use crate::git::worktree;
use crate::git::types::{
BlameLine, BlameResult, BranchInfo, CherryPickMode, CherryPickResult, CommitDetail,
CommitFileChange, CommitFileStatus, CommitGraphRow, CommitInfo, CommitLogResult, CommitRef,
Expand All @@ -17,7 +19,8 @@ use crate::git::types::{
FileStatusKind, GraphEdge, GraphNodeType, HunkIdentifier, LineRange, LogFilter,
MergeBaseContent, MergeKind, MergeOption, MergeResult, PullOption, PushResult, RebaseAction,
RebaseResult, RebaseState, RebaseTodoEntry, ReflogEntry, RemoteInfo, RepoStatus, ResetMode,
ResetResult, RevertMode, RevertResult, StagingState, StashEntry, TagInfo, WordSegment,
ResetResult, RevertMode, RevertResult, StagingState, StashEntry, SubmoduleInfo, TagInfo,
WordSegment, WorktreeInfo,
};

pub struct Git2Backend {
Expand Down Expand Up @@ -2041,6 +2044,38 @@ impl GitBackend for Git2Backend {
fn search_filenames(&self, query: &str) -> GitResult<Vec<FilenameSearchResult>> {
search::search_filenames(&self.workdir, query)
}

fn list_submodules(&self) -> GitResult<Vec<SubmoduleInfo>> {
submodule::list_submodules(&self.workdir)
}

fn add_submodule(&self, url: &str, path: &str) -> GitResult<()> {
submodule::add_submodule(&self.workdir, url, path)
}

fn update_submodule(&self, path: &str) -> GitResult<()> {
submodule::update_submodule(&self.workdir, path)
}

fn update_all_submodules(&self) -> GitResult<()> {
submodule::update_all_submodules(&self.workdir)
}

fn remove_submodule(&self, path: &str) -> GitResult<()> {
submodule::remove_submodule(&self.workdir, path)
}

fn list_worktrees(&self) -> GitResult<Vec<WorktreeInfo>> {
worktree::list_worktrees(&self.workdir)
}

fn add_worktree(&self, path: &str, branch: &str) -> GitResult<()> {
worktree::add_worktree(&self.workdir, path, branch)
}

fn remove_worktree(&self, path: &str) -> GitResult<()> {
worktree::remove_worktree(&self.workdir, path)
}
}

impl Git2Backend {
Expand Down
2 changes: 2 additions & 0 deletions src-tauri/src/git/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@ pub mod dispatcher;
pub mod error;
pub mod git2_backend;
pub mod search;
pub mod submodule;
pub mod types;
pub mod worktree;
Loading
Loading