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
18 changes: 9 additions & 9 deletions docs/roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -430,15 +430,15 @@

**ゴール**: 複雑なプロジェクト構成を管理できる

- [ ] サブモジュール
- [ ] サブモジュール一覧表示(パス、URL、現在のコミット)
- [ ] サブモジュール追加
- [ ] サブモジュール更新(同期)
- [ ] サブモジュール削除
- [ ] ワークツリー
- [ ] ワークツリー一覧表示
- [ ] ワークツリー追加(ブランチ指定)
- [ ] ワークツリー削除
- [x] サブモジュール
- [x] サブモジュール一覧表示(パス、URL、現在のコミット)
- [x] サブモジュール追加
- [x] サブモジュール更新(同期)
- [x] サブモジュール削除
- [x] ワークツリー
- [x] ワークツリー一覧表示
- [x] ワークツリー追加(ブランチ指定)
- [x] ワークツリー削除

**完動品としての価値**: モノレポやサブモジュール構成のプロジェクトを GUI で管理できる

Expand Down
5 changes: 4 additions & 1 deletion src-tauri/src/commands/git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,17 @@ pub fn unstage_all(state: State<'_, AppState>) -> Result<(), String> {
pub fn commit(
message: String,
amend: bool,
sign: bool,
state: State<'_, AppState>,
) -> Result<CommitResult, 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.commit(&message, amend).map_err(|e| e.to_string())
backend
.commit(&message, amend, sign)
.map_err(|e| e.to_string())
}

#[tauri::command]
Expand Down
81 changes: 81 additions & 0 deletions src-tauri/src/commands/gitconfig.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
use tauri::State;

use crate::git::types::{GitConfigEntry, GitConfigScope};
use crate::state::AppState;

#[tauri::command]
pub fn get_gitconfig_entries(
scope: GitConfigScope,
state: State<'_, AppState>,
) -> Result<Vec<GitConfigEntry>, 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
.get_gitconfig_entries(scope)
.map_err(|e| e.to_string())
}

#[tauri::command]
pub fn get_gitconfig_value(
scope: GitConfigScope,
key: String,
state: State<'_, AppState>,
) -> Result<Option<String>, 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
.get_gitconfig_value(scope, &key)
.map_err(|e| e.to_string())
}

#[tauri::command]
pub fn set_gitconfig_value(
scope: GitConfigScope,
key: String,
value: 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
.set_gitconfig_value(scope, &key, &value)
.map_err(|e| e.to_string())
}

#[tauri::command]
pub fn unset_gitconfig_value(
scope: GitConfigScope,
key: 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
.unset_gitconfig_value(scope, &key)
.map_err(|e| e.to_string())
}

#[tauri::command]
pub fn get_gitconfig_path(
scope: GitConfigScope,
state: State<'_, AppState>,
) -> Result<String, 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.get_gitconfig_path(scope).map_err(|e| e.to_string())
}
1 change: 1 addition & 0 deletions src-tauri/src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pub mod cherry_pick;
pub mod config;
pub mod conflict;
pub mod git;
pub mod gitconfig;
pub mod history;
pub mod hosting;
pub mod rebase;
Expand Down
8 changes: 2 additions & 6 deletions src-tauri/src/commands/submodule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,7 @@ pub fn update_submodule(path: String, state: State<'_, AppState>) -> Result<(),
.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())
backend.update_submodule(&path).map_err(|e| e.to_string())
}

#[tauri::command]
Expand All @@ -54,7 +52,5 @@ pub fn remove_submodule(path: String, state: State<'_, AppState>) -> Result<(),
.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())
backend.remove_submodule(&path).map_err(|e| e.to_string())
}
4 changes: 1 addition & 3 deletions src-tauri/src/commands/worktree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,5 @@ pub fn remove_worktree(path: String, state: State<'_, AppState>) -> Result<(), S
.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())
backend.remove_worktree(&path).map_err(|e| e.to_string())
}
20 changes: 15 additions & 5 deletions src-tauri/src/git/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ use crate::git::search::{CodeSearchResult, CommitSearchResult, FilenameSearchRes
use crate::git::types::{
BlameResult, BranchInfo, CherryPickMode, CherryPickResult, CommitDetail, CommitInfo,
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, SubmoduleInfo,
TagInfo, WorktreeInfo,
FileDiff, GitConfigEntry, GitConfigScope, HunkIdentifier, LineRange, LogFilter,
MergeBaseContent, MergeOption, MergeResult, PullOption, PushResult, RebaseResult, RebaseState,
RebaseTodoEntry, ReflogEntry, RemoteInfo, RepoStatus, ResetMode, ResetResult, RevertMode,
RevertResult, SignatureStatus, StashEntry, SubmoduleInfo, TagInfo, WorktreeInfo,
};

pub trait GitBackend: Send + Sync {
Expand All @@ -20,7 +20,7 @@ pub trait GitBackend: Send + Sync {
fn stage_all(&self) -> GitResult<()>;
fn unstage_all(&self) -> GitResult<()>;
fn current_branch(&self) -> GitResult<String>;
fn commit(&self, message: &str, amend: bool) -> GitResult<CommitResult>;
fn commit(&self, message: &str, amend: bool, sign: bool) -> GitResult<CommitResult>;
fn list_branches(&self) -> GitResult<Vec<BranchInfo>>;
fn create_branch(&self, name: &str) -> GitResult<()>;
fn checkout_branch(&self, name: &str) -> GitResult<()>;
Expand Down Expand Up @@ -127,4 +127,14 @@ pub trait GitBackend: Send + Sync {
fn list_worktrees(&self) -> GitResult<Vec<WorktreeInfo>>;
fn add_worktree(&self, path: &str, branch: &str) -> GitResult<()>;
fn remove_worktree(&self, path: &str) -> GitResult<()>;

// Gitconfig operations
fn get_gitconfig_entries(&self, scope: GitConfigScope) -> GitResult<Vec<GitConfigEntry>>;
fn get_gitconfig_value(&self, scope: GitConfigScope, key: &str) -> GitResult<Option<String>>;
fn set_gitconfig_value(&self, scope: GitConfigScope, key: &str, value: &str) -> GitResult<()>;
fn unset_gitconfig_value(&self, scope: GitConfigScope, key: &str) -> GitResult<()>;
fn get_gitconfig_path(&self, scope: GitConfigScope) -> GitResult<String>;

// Signature verification
fn verify_commit_signatures(&self, oids: &[&str]) -> GitResult<Vec<(String, SignatureStatus)>>;
}
6 changes: 6 additions & 0 deletions src-tauri/src/git/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,12 @@ pub enum GitError {

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

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

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

pub type GitResult<T> = Result<T, GitError>;
Loading