sign commits with real git

in the strangest possible way
This commit is contained in:
Scott Chacon 2024-05-07 15:15:25 +02:00
parent ff11fcdb90
commit 51f9769024
14 changed files with 168 additions and 173 deletions

1
Cargo.lock generated
View File

@ -2190,6 +2190,7 @@ dependencies = [
"sysinfo",
"thiserror",
"tokio",
"uuid",
"winapi 0.3.9",
"windows-named-pipe",
]

View File

@ -274,6 +274,29 @@ impl Repository {
.write(git2::ObjectType::Commit, commit_buffer.as_bytes())?;
// check git config for gpg.signingkey
let signing_key = self.0.config()?.get_string("commit.gpgSign");
dbg!(&signing_key);
if let Ok(_should_sign) = signing_key {
dbg!("SIGN IT");
/*
SOMETHING SOMETHING DARK SIDE...
let path = self.path().to_path_buf();
let res = std::thread::spawn(move || {
tokio::runtime::Runtime::new()
.unwrap()
.block_on(gitbutler_git::sign_commit(
path,
gitbutler_git::tokio::TokioExecutor,
oid.to_string(),
handle_git_prompt_sign,
extra,
))
})
.join()
.unwrap()
.map_err(|e| Err(anyhow::anyhow!("fuck you")));
*/
}
// update reference
if let Some(refname) = update_ref {

View File

@ -13,7 +13,6 @@ use crate::{
askpass::AskpassBroker,
error,
git::{self, credentials::HelpError, Url},
keys,
projects::{self, AuthKey},
ssh, users,
virtual_branches::{Branch, BranchId},
@ -344,20 +343,12 @@ impl Repository {
message: &str,
tree: &git::Tree,
parents: &[&git::Commit],
signing_key: Option<&keys::PrivateKey>,
change_id: Option<&str>,
) -> Result<git::Oid> {
let (author, committer) = self.git_signatures(user)?;
if let Some(key) = signing_key {
self.git_repository
.commit_signed(&author, message, tree, parents, key, change_id)
.context("failed to commit signed")
} else {
self.git_repository
.commit(None, &author, &committer, message, tree, parents, change_id)
.context("failed to commit")
}
self.git_repository
.commit(None, &author, &committer, message, tree, parents, change_id)
.context("failed to commit")
}
pub fn push_to_gitbutler_server(

View File

@ -12,7 +12,6 @@ use super::{
};
use crate::{
git::{self, diff},
keys,
project_repository::{self, LogUntil},
projects::FetchResult,
users,
@ -342,7 +341,6 @@ fn _print_tree(repo: &git2::Repository, tree: &git2::Tree) -> Result<()> {
pub fn update_base_branch(
project_repository: &project_repository::Repository,
user: Option<&users::User>,
signing_key: Option<&keys::PrivateKey>,
) -> Result<(), errors::UpdateBaseBranchError> {
if project_repository.is_resolving() {
return Err(errors::UpdateBaseBranchError::Conflict(
@ -513,7 +511,6 @@ pub fn update_base_branch(
.as_str(),
&branch_head_merge_tree,
&[&branch_head_commit, &new_target_commit],
signing_key,
None,
)
.context("failed to commit merge")?;

View File

@ -17,7 +17,7 @@ use super::{
};
use crate::{
askpass::AskpassBroker,
git, keys, project_repository,
git, project_repository,
projects::{self, ProjectId},
users,
};
@ -26,7 +26,6 @@ use crate::{
pub struct Controller {
projects: projects::Controller,
users: users::Controller,
keys: keys::Controller,
helper: git::credentials::Helper,
by_project_id: Arc<tokio::sync::Mutex<HashMap<ProjectId, ControllerInner>>>,
@ -36,7 +35,6 @@ impl Controller {
pub fn new(
projects: projects::Controller,
users: users::Controller,
keys: keys::Controller,
helper: git::credentials::Helper,
) -> Self {
Self {
@ -44,7 +42,6 @@ impl Controller {
projects,
users,
keys,
helper,
}
}
@ -54,9 +51,7 @@ impl Controller {
.lock()
.await
.entry(*project_id)
.or_insert_with(|| {
ControllerInner::new(&self.projects, &self.users, &self.keys, &self.helper)
})
.or_insert_with(|| ControllerInner::new(&self.projects, &self.users, &self.helper))
.clone()
}
@ -430,7 +425,6 @@ struct ControllerInner {
projects: projects::Controller,
users: users::Controller,
keys: keys::Controller,
helper: git::credentials::Helper,
}
@ -438,14 +432,12 @@ impl ControllerInner {
pub fn new(
projects: &projects::Controller,
users: &users::Controller,
keys: &keys::Controller,
helper: &git::credentials::Helper,
) -> Self {
Self {
semaphore: Arc::new(Semaphore::new(1)),
projects: projects.clone(),
users: users.clone(),
keys: keys.clone(),
helper: helper.clone(),
}
}
@ -461,23 +453,11 @@ impl ControllerInner {
let _permit = self.semaphore.acquire().await;
self.with_verify_branch(project_id, |project_repository, user| {
let signing_key = project_repository
.config()
.sign_commits()
.context("failed to get sign commits option")?
.then(|| {
self.keys
.get_or_create()
.context("failed to get private key")
})
.transpose()?;
let result = super::commit(
project_repository,
branch_id,
message,
ownership,
signing_key.as_ref(),
user,
run_hooks,
)
@ -548,22 +528,8 @@ impl ControllerInner {
let _permit = self.semaphore.acquire().await;
self.with_verify_branch(project_id, |project_repository, user| {
let signing_key = project_repository
.config()
.sign_commits()
.context("failed to get sign commits option")?
.then(|| {
self.keys
.get_or_create()
.context("failed to get private key")
})
.transpose()?;
let result = super::create_virtual_branch_from_branch(
project_repository,
branch,
signing_key.as_ref(),
user,
)?;
let result =
super::create_virtual_branch_from_branch(project_repository, branch, user)?;
let _ = project_repository
.project()
.create_snapshot(SnapshotDetails::new(OperationType::CreateBranch));
@ -624,24 +590,8 @@ impl ControllerInner {
let _permit = self.semaphore.acquire().await;
self.with_verify_branch(project_id, |project_repository, user| {
let signing_key = project_repository
.config()
.sign_commits()
.context("failed to get sign commits option")?
.then(|| {
self.keys
.get_or_create()
.context("failed to get private key")
})
.transpose()?;
let result = super::merge_virtual_branch_upstream(
project_repository,
branch_id,
signing_key.as_ref(),
user,
)
.map_err(Into::into);
let result = super::merge_virtual_branch_upstream(project_repository, branch_id, user)
.map_err(Into::into);
let _ = project_repository
.project()
.create_snapshot(SnapshotDetails::new(OperationType::MergeUpstream));
@ -653,19 +603,7 @@ impl ControllerInner {
let _permit = self.semaphore.acquire().await;
self.with_verify_branch(project_id, |project_repository, user| {
let signing_key = project_repository
.config()
.sign_commits()
.context("failed to get sign commits option")?
.then(|| {
self.keys
.get_or_create()
.context("failed to get private key")
})
.transpose()?;
let result = super::update_base_branch(project_repository, user, signing_key.as_ref())
.map_err(Into::into);
let result = super::update_base_branch(project_repository, user).map_err(Into::into);
let _ = project_repository
.project()
.create_snapshot(SnapshotDetails::new(OperationType::UpdateWorkspaceBase));
@ -726,20 +664,8 @@ impl ControllerInner {
let _permit = self.semaphore.acquire().await;
self.with_verify_branch(project_id, |project_repository, user| {
let signing_key = project_repository
.config()
.sign_commits()
.context("failed to get sign commits option")?
.then(|| {
self.keys
.get_or_create()
.context("failed to get private key")
})
.transpose()?;
let result =
super::apply_branch(project_repository, branch_id, signing_key.as_ref(), user)
.map_err(Into::into);
super::apply_branch(project_repository, branch_id, user).map_err(Into::into);
let _ = project_repository
.project()
.create_snapshot(SnapshotDetails::new(OperationType::ApplyBranch));
@ -1083,24 +1009,8 @@ impl ControllerInner {
let _permit = self.semaphore.acquire().await;
self.with_verify_branch(project_id, |project_repository, user| {
let signing_key = project_repository
.config()
.sign_commits()
.context("failed to get sign commits option")?
.then(|| {
self.keys
.get_or_create()
.context("failed to get private key")
})
.transpose()?;
let result = super::move_commit(
project_repository,
target_branch_id,
commit_oid,
user,
signing_key.as_ref(),
)
.map_err(Into::into);
let result = super::move_commit(project_repository, target_branch_id, commit_oid, user)
.map_err(Into::into);
let _ = project_repository
.project()
.create_snapshot(SnapshotDetails::new(OperationType::MoveCommit));

View File

@ -34,7 +34,6 @@ use crate::{
diff::{self},
Commit, Refname, RemoteRefname,
},
keys,
project_repository::{self, conflicts, LogUntil},
reader, users,
};
@ -101,6 +100,7 @@ pub struct VirtualBranchCommit {
pub branch_id: BranchId,
pub change_id: Option<String>,
pub is_signed: bool,
pub stack_points: Option<Vec<HashMap<String, String>>>,
}
// this struct is a mapping to the view `File` type in Typescript
@ -215,7 +215,6 @@ pub fn normalize_branch_name(name: &str) -> String {
pub fn apply_branch(
project_repository: &project_repository::Repository,
branch_id: &BranchId,
signing_key: Option<&keys::PrivateKey>,
user: Option<&users::User>,
) -> Result<(), errors::ApplyBranchError> {
if project_repository.is_resolving() {
@ -359,7 +358,6 @@ pub fn apply_branch(
.as_str(),
&merged_branch_tree,
&[&head_commit, &target_commit],
signing_key,
None,
)?;
@ -429,7 +427,6 @@ pub fn apply_branch(
.as_str(),
&merge_tree,
&[&head_commit, &target_commit],
signing_key,
None,
)
.context("failed to commit merge")?;
@ -1053,6 +1050,7 @@ fn commit_to_vbranch_commit(
branch_id: branch.id,
change_id: commit.change_id(),
is_signed: commit.is_signed(),
stack_points: Some(stack_points),
};
Ok(commit)
@ -1171,7 +1169,6 @@ pub fn create_virtual_branch(
pub fn merge_virtual_branch_upstream(
project_repository: &project_repository::Repository,
branch_id: &BranchId,
signing_key: Option<&keys::PrivateKey>,
user: Option<&users::User>,
) -> Result<(), errors::MergeVirtualBranchUpstreamError> {
if conflicts::is_conflicting::<&Path>(project_repository, None)? {
@ -1364,7 +1361,6 @@ pub fn merge_virtual_branch_upstream(
.as_str(),
&merge_tree,
&[&head_commit, &upstream_commit],
signing_key,
None,
)?;
@ -2312,7 +2308,6 @@ pub fn commit(
branch_id: &BranchId,
message: &str,
ownership: Option<&branch::BranchOwnershipClaims>,
signing_key: Option<&keys::PrivateKey>,
user: Option<&users::User>,
run_hooks: bool,
) -> Result<git::Oid, errors::CommitError> {
@ -2415,15 +2410,12 @@ pub fn commit(
message,
&tree,
&[&parent_commit, &merge_parent],
signing_key,
None,
)?;
conflicts::clear(project_repository).context("failed to clear conflicts")?;
commit_oid
}
None => {
project_repository.commit(user, message, &tree, &[&parent_commit], signing_key, None)?
}
None => project_repository.commit(user, message, &tree, &[&parent_commit], None)?,
};
if run_hooks {
@ -3340,8 +3332,7 @@ pub fn insert_blank_commit(
}
let commit_tree = commit.tree().unwrap();
let blank_commit_oid =
project_repository.commit(user, "", &commit_tree, &[&commit], None, None)?;
let blank_commit_oid = project_repository.commit(user, "", &commit_tree, &[&commit], None)?;
if commit.id() == branch.head && offset < 0 {
// inserting before the first commit
@ -3983,7 +3974,6 @@ pub fn move_commit(
target_branch_id: &BranchId,
commit_oid: git::Oid,
user: Option<&users::User>,
signing_key: Option<&keys::PrivateKey>,
) -> Result<(), errors::MoveCommitError> {
if project_repository.is_resolving() {
return Err(errors::MoveCommitError::Conflicted(
@ -4140,7 +4130,6 @@ pub fn move_commit(
.git_repository
.find_commit(destination_branch.head)
.context("failed to get dst branch head commit")?],
signing_key,
change_id.as_deref(),
)
.context("failed to commit")?;
@ -4158,7 +4147,6 @@ pub fn move_commit(
pub fn create_virtual_branch_from_branch(
project_repository: &project_repository::Repository,
upstream: &git::Refname,
signing_key: Option<&keys::PrivateKey>,
user: Option<&users::User>,
) -> Result<BranchId, errors::CreateVirtualBranchFromBranchError> {
if !matches!(upstream, git::Refname::Local(_) | git::Refname::Remote(_)) {
@ -4297,7 +4285,7 @@ pub fn create_virtual_branch_from_branch(
project_repository.add_branch_reference(&branch)?;
match apply_branch(project_repository, &branch.id, signing_key, user) {
match apply_branch(project_repository, &branch.id, user) {
Ok(()) => Ok(branch.id),
Err(errors::ApplyBranchError::BranchConflicts(_)) => {
// if branch conflicts with the workspace, it's ok. keep it unapplied

View File

@ -3,14 +3,13 @@ use super::*;
#[tokio::test]
async fn twice() {
let data_dir = paths::data_dir();
let keys = keys::Controller::from_path(data_dir.path());
let projects = projects::Controller::from_path(data_dir.path());
let users = users::Controller::from_path(data_dir.path());
let helper = git::credentials::Helper::from_path(data_dir.path());
let test_project = TestProject::default();
let controller = Controller::new(projects.clone(), users, keys, helper);
let controller = Controller::new(projects.clone(), users, helper);
{
let project = projects

View File

@ -1,7 +1,7 @@
use std::{fs, path, str::FromStr};
use gitbutler_core::{
git, keys,
git,
projects::{self, ProjectId},
users,
virtual_branches::{branch, errors, Controller},
@ -29,7 +29,6 @@ impl Drop for Test {
impl Default for Test {
fn default() -> Self {
let data_dir = paths::data_dir();
let keys = keys::Controller::from_path(data_dir.path());
let projects = projects::Controller::from_path(data_dir.path());
let users = users::Controller::from_path(data_dir.path());
let helper = git::credentials::Helper::from_path(data_dir.path());
@ -42,7 +41,7 @@ impl Default for Test {
Self {
repository: test_project,
project_id: project.id,
controller: Controller::new(projects.clone(), users, keys, helper),
controller: Controller::new(projects.clone(), users, helper),
projects,
data_dir: Some(data_dir),
}

View File

@ -64,7 +64,6 @@ fn commit_on_branch_then_change_file_then_get_status() -> Result<()> {
"test commit",
None,
None,
None,
false,
)?;
@ -123,7 +122,6 @@ fn signed_commit() -> Result<()> {
&branch1_id,
"test commit",
None,
Some(suite.keys.get_or_create()?).as_ref(),
None,
false,
)?;
@ -212,7 +210,6 @@ fn track_binary_files() -> Result<()> {
"test commit",
None,
None,
None,
false,
)?;
@ -244,7 +241,6 @@ fn track_binary_files() -> Result<()> {
"test commit",
None,
None,
None,
false,
)?;
@ -811,12 +807,7 @@ fn merge_vbranch_upstream_clean_rebase() -> Result<()> {
assert_eq!(branch1.commits.len(), 1);
// assert_eq!(branch1.upstream.as_ref().unwrap().commits.len(), 1);
merge_virtual_branch_upstream(
project_repository,
&branch1.id,
Some(suite.keys.get_or_create()?).as_ref(),
None,
)?;
merge_virtual_branch_upstream(project_repository, &branch1.id, None)?;
let (branches, _) = virtual_branches::list_virtual_branches(project_repository)?;
let branch1 = &branches[0];
@ -931,7 +922,7 @@ fn merge_vbranch_upstream_conflict() -> Result<()> {
assert_eq!(branch1.commits.len(), 1);
// assert_eq!(branch1.upstream.as_ref().unwrap().commits.len(), 1);
merge_virtual_branch_upstream(project_repository, &branch1.id, None, None)?;
merge_virtual_branch_upstream(project_repository, &branch1.id, None)?;
let (branches, _) = virtual_branches::list_virtual_branches(project_repository)?;
let branch1 = &branches[0];
@ -963,7 +954,6 @@ fn merge_vbranch_upstream_conflict() -> Result<()> {
"fix merge conflict",
None,
None,
None,
false,
)?;
@ -1095,7 +1085,7 @@ fn unapply_branch() -> Result<()> {
assert_eq!(branch.files.len(), 1);
assert!(!branch.active);
apply_branch(project_repository, &branch1_id, None, None)?;
apply_branch(project_repository, &branch1_id, None)?;
let contents = std::fs::read(Path::new(&project.path).join(file_path))?;
assert_eq!(
"line1\nline2\nline3\nline4\nbranch1\n",
@ -1168,11 +1158,11 @@ fn apply_unapply_added_deleted_files() -> Result<()> {
// check that file3 is gone
assert!(!Path::new(&project.path).join(file_path3).exists());
apply_branch(project_repository, &branch2_id, None, None)?;
apply_branch(project_repository, &branch2_id, None)?;
// check that file2 is gone
assert!(!Path::new(&project.path).join(file_path2).exists());
apply_branch(project_repository, &branch3_id, None, None)?;
apply_branch(project_repository, &branch3_id, None)?;
// check that file3 is back
let contents = std::fs::read(Path::new(&project.path).join(file_path3))?;
assert_eq!("file3\n", String::from_utf8(contents)?);
@ -1461,7 +1451,6 @@ fn upstream_integrated_vbranch() -> Result<()> {
"integrated commit",
None,
None,
None,
false,
)?;
commit(
@ -1470,7 +1459,6 @@ fn upstream_integrated_vbranch() -> Result<()> {
"non-integrated commit",
None,
None,
None,
false,
)?;
@ -1531,7 +1519,6 @@ fn commit_same_hunk_twice() -> Result<()> {
"first commit to test.txt",
None,
None,
None,
false,
)?;
@ -1567,7 +1554,6 @@ fn commit_same_hunk_twice() -> Result<()> {
"second commit to test.txt",
None,
None,
None,
false,
)?;
@ -1626,7 +1612,6 @@ fn commit_same_file_twice() -> Result<()> {
"first commit to test.txt",
None,
None,
None,
false,
)?;
@ -1662,7 +1647,6 @@ fn commit_same_file_twice() -> Result<()> {
"second commit to test.txt",
None,
None,
None,
false,
)?;
@ -1721,7 +1705,6 @@ fn commit_partial_by_hunk() -> Result<()> {
"first commit to test.txt",
Some(&"test.txt:1-6".parse::<BranchOwnershipClaims>().unwrap()),
None,
None,
false,
)?;
@ -1740,7 +1723,6 @@ fn commit_partial_by_hunk() -> Result<()> {
"second commit to test.txt",
Some(&"test.txt:16-22".parse::<BranchOwnershipClaims>().unwrap()),
None,
None,
false,
)?;
@ -1799,7 +1781,6 @@ fn commit_partial_by_file() -> Result<()> {
"branch1 commit",
None,
None,
None,
false,
)?;
@ -1867,7 +1848,6 @@ fn commit_add_and_delete_files() -> Result<()> {
"branch1 commit",
None,
None,
None,
false,
)?;
@ -1933,7 +1913,6 @@ fn commit_executable_and_symlinks() -> Result<()> {
"branch1 commit",
None,
None,
None,
false,
)?;
@ -2110,7 +2089,6 @@ fn pre_commit_hook_rejection() -> Result<()> {
&branch1_id,
"test commit",
None,
Some(suite.keys.get_or_create()?).as_ref(),
None,
true,
);
@ -2175,7 +2153,6 @@ fn post_commit_hook() -> Result<()> {
&branch1_id,
"test commit",
None,
Some(suite.keys.get_or_create()?).as_ref(),
None,
true,
)?;
@ -2224,7 +2201,6 @@ fn commit_msg_hook_rejection() -> Result<()> {
&branch1_id,
"test commit",
None,
Some(suite.keys.get_or_create()?).as_ref(),
None,
true,
);

View File

@ -29,6 +29,7 @@ test-askpass-path = []
thiserror.workspace = true
serde = { workspace = true, optional = true }
tokio = { workspace = true, optional = true, features = ["process", "time", "io-util", "net", "fs"] }
uuid.workspace = true
rand = "0.8.5"
futures = "0.3.30"
sysinfo = "0.30.11"

View File

@ -24,5 +24,5 @@ pub use self::executor::tokio;
pub use self::{
error::Error,
refspec::{Error as RefSpecError, RefSpec},
repository::{fetch, push},
repository::{fetch, push, sign_commit},
};

View File

@ -59,7 +59,7 @@ pub type Error<E> = RepositoryError<
#[cold]
async fn execute_with_auth_harness<P, F, Fut, E, Extra>(
repo_path: P,
executor: E,
executor: &E,
args: &[&str],
envs: Option<HashMap<String, String>>,
mut on_prompt: F,
@ -155,7 +155,7 @@ where
.or_else(|| std::env::var("GIT_SSH").ok())
{
Some(v) => v,
None => get_core_sshcommand(&executor, &repo_path)
None => get_core_sshcommand(executor, &repo_path)
.await
.unwrap_or_else(|| "ssh".into()),
};
@ -300,7 +300,7 @@ where
args.push(&refspec);
let (status, stdout, stderr) =
execute_with_auth_harness(repo_path, executor, &args, None, on_prompt, extra).await?;
execute_with_auth_harness(repo_path, &executor, &args, None, on_prompt, extra).await?;
if status == 0 {
Ok(())
@ -362,7 +362,7 @@ where
}
let (status, stdout, stderr) =
execute_with_auth_harness(repo_path, executor, &args, None, on_prompt, extra).await?;
execute_with_auth_harness(repo_path, &executor, &args, None, on_prompt, extra).await?;
if status == 0 {
Ok(())
@ -392,6 +392,118 @@ where
}
}
/// Signs the given commit-ish in the repository at the given path.
/// Returns the newly signed commit SHA.
///
/// Any prompts for the user are passed to the asynchronous callback `on_prompt`,
/// which should return the user's response or `None` if the operation should be
/// aborted, in which case an `Err` value is returned from this function.
pub async fn sign_commit<P, E, F, Extra, Fut>(
repo_path: P,
executor: E,
base_commitish: String,
on_prompt: F,
extra: Extra,
) -> Result<String, crate::Error<Error<E>>>
where
P: AsRef<Path>,
E: GitExecutor,
F: FnMut(String, Extra) -> Fut,
Fut: std::future::Future<Output = Option<String>>,
Extra: Send + Clone,
{
let repo_path = repo_path.as_ref();
// First, create a worktree to perform the commit.
let worktree_path = repo_path
.join(".git")
.join("gitbutler")
.join(".wt")
.join(uuid::Uuid::new_v4().to_string());
let args = [
"worktree",
"add",
"--detach",
"--no-checkout",
worktree_path.to_str().unwrap(),
base_commitish.as_str(),
];
let (status, stdout, stderr) = executor
.execute(&args, repo_path, None)
.await
.map_err(Error::<E>::Exec)?;
if status != 0 {
return Err(Error::<E>::Failed {
status,
args: args.into_iter().map(Into::into).collect(),
stdout,
stderr,
})?;
}
// Now, perform the commit.
let args = [
"commit",
"--amend",
"-S",
"-o",
"--no-edit",
"--no-verify",
"--no-post-rewrite",
"--allow-empty",
"--allow-empty-message",
];
let (status, stdout, stderr) =
execute_with_auth_harness(&worktree_path, &executor, &args, None, on_prompt, extra).await?;
if status != 0 {
return Err(Error::<E>::Failed {
status,
args: args.into_iter().map(Into::into).collect(),
stdout,
stderr,
})?;
}
// Get the commit hash that was generated
let args = ["rev-parse", "--verify", "HEAD"];
let (status, stdout, stderr) = executor
.execute(&args, &worktree_path, None)
.await
.map_err(Error::<E>::Exec)?;
if status != 0 {
return Err(Error::<E>::Failed {
status,
args: args.into_iter().map(Into::into).collect(),
stdout,
stderr,
})?;
}
let commit_hash = stdout.trim().to_string();
// Finally, remove the worktree
let args = [
"worktree",
"remove",
"--force",
worktree_path.to_str().unwrap(),
];
let (status, stdout, stderr) = executor
.execute(&args, repo_path, None)
.await
.map_err(Error::<E>::Exec)?;
if status != 0 {
return Err(Error::<E>::Failed {
status,
args: args.into_iter().map(Into::into).collect(),
stdout,
stderr,
})?;
}
Ok(commit_hash)
}
async fn get_core_sshcommand<E: GitExecutor, P: AsRef<Path>>(
executor: &E,
cwd: P,

View File

@ -140,7 +140,6 @@ fn main() {
app_handle.manage(gitbutler_core::virtual_branches::controller::Controller::new(
projects_controller.clone(),
users_controller.clone(),
keys_controller.clone(),
git_credentials_controller.clone(),
));

View File

@ -37,7 +37,6 @@ mod support {
let vbranch_controller = virtual_branches::Controller::new(
inner.projects.clone(),
inner.users.clone(),
inner.keys.clone(),
git_credentials_helper,
);
let assets_proxy = assets::Proxy::new(tmp.path().to_owned());