Merge pull request #3963 from gitbutlerapp/refname-mod-rs-cleanup

refname-mod-rs-cleanup
This commit is contained in:
Kiril Videlov 2024-06-03 01:17:02 +02:00 committed by GitHub
commit 8eb7d1d0f0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 351 additions and 328 deletions

View File

@ -1,12 +1,7 @@
use super::{Oid, Refname, Result, Url};
use git2::{BlameOptions, Submodule};
use git2_hooks::HookResult;
#[cfg(unix)]
use std::os::unix::fs::PermissionsExt;
#[cfg(windows)]
use std::os::windows::process::CommandExt;
use std::process::Stdio;
use std::{io::Write, path::Path, str};
use std::{path::Path, str};
// wrapper around git2::Repository to get control over how it's used.
pub struct Repository(git2::Repository);
@ -80,12 +75,6 @@ impl Repository {
.map_err(Into::into)
}
pub fn is_descendant_of(&self, a: Oid, b: Oid) -> Result<bool> {
self.0
.graph_descendant_of(a.into(), b.into())
.map_err(Into::into)
}
pub fn merge_base(&self, one: Oid, two: Oid) -> Result<Oid> {
self.0
.merge_base(one.into(), two.into())
@ -201,193 +190,6 @@ impl Repository {
self.0.blob(data).map(Into::into).map_err(Into::into)
}
#[allow(clippy::too_many_arguments)]
pub fn commit(
&self,
update_ref: Option<&Refname>,
author: &git2::Signature<'_>,
committer: &git2::Signature<'_>,
message: &str,
tree: &git2::Tree<'_>,
parents: &[&git2::Commit<'_>],
change_id: Option<&str>,
) -> Result<Oid> {
let commit_buffer = self
.0
.commit_create_buffer(author, committer, message, tree, parents)?;
let commit_buffer = Self::inject_change_id(&commit_buffer, change_id)?;
let oid = self.commit_buffer(commit_buffer)?;
// update reference
if let Some(refname) = update_ref {
self.0.reference(&refname.to_string(), oid, true, message)?;
}
Ok(oid.into())
}
/// takes raw commit data and commits it to the repository
/// - if the git config commit.gpgSign is set, it will sign the commit
/// returns an oid of the new commit object
pub fn commit_buffer(&self, buffer: String) -> Result<git2::Oid> {
// check git config for gpg.signingkey
let should_sign = self.0.config()?.get_bool("commit.gpgSign").unwrap_or(false);
if should_sign {
// TODO: support gpg.ssh.defaultKeyCommand to get the signing key if this value doesn't exist
let signing_key = self.0.config()?.get_string("user.signingkey");
if let Ok(signing_key) = signing_key {
let sign_format = self.0.config()?.get_string("gpg.format");
let is_ssh = if let Ok(sign_format) = sign_format {
sign_format == "ssh"
} else {
false
};
if is_ssh {
// write commit data to a temp file so we can sign it
let mut signature_storage = tempfile::NamedTempFile::new()?;
signature_storage.write_all(buffer.as_ref())?;
let buffer_file_to_sign_path = signature_storage.into_temp_path();
let gpg_program = self.0.config()?.get_string("gpg.ssh.program");
let mut cmd =
std::process::Command::new(gpg_program.unwrap_or("ssh-keygen".to_string()));
cmd.args(["-Y", "sign", "-n", "git", "-f"]);
#[cfg(windows)]
cmd.creation_flags(0x08000000); // CREATE_NO_WINDOW
let output;
// support literal ssh key
if let (true, signing_key) = Self::is_literal_ssh_key(&signing_key) {
// write the key to a temp file
let mut key_storage = tempfile::NamedTempFile::new()?;
key_storage.write_all(signing_key.as_bytes())?;
// if on unix
#[cfg(unix)]
{
// make sure the tempfile permissions are acceptable for a private ssh key
let mut permissions = key_storage.as_file().metadata()?.permissions();
permissions.set_mode(0o600);
key_storage.as_file().set_permissions(permissions)?;
}
let key_file_path = key_storage.into_temp_path();
cmd.arg(&key_file_path);
cmd.arg("-U");
cmd.arg(&buffer_file_to_sign_path);
cmd.stdout(Stdio::piped());
cmd.stdin(Stdio::null());
let child = cmd.spawn()?;
output = child.wait_with_output()?;
} else {
cmd.arg(signing_key);
cmd.arg(&buffer_file_to_sign_path);
cmd.stdout(Stdio::piped());
cmd.stdin(Stdio::null());
let child = cmd.spawn()?;
output = child.wait_with_output()?;
}
if output.status.success() {
// read signed_storage path plus .sig
let signature_path = buffer_file_to_sign_path.with_extension("sig");
let sig_data = std::fs::read(signature_path)?;
let signature = String::from_utf8_lossy(&sig_data);
let oid = self
.0
.commit_signed(&buffer, &signature, None)
.map(Into::into)
.map_err(Into::into);
return oid;
}
} else {
// is gpg
let gpg_program = self.0.config()?.get_string("gpg.program");
let mut cmd =
std::process::Command::new(gpg_program.unwrap_or("gpg".to_string()));
cmd.args(["--status-fd=2", "-bsau", &signing_key])
//.arg(&signed_storage)
.arg("-")
.stdout(Stdio::piped())
.stdin(Stdio::piped());
#[cfg(windows)]
cmd.creation_flags(0x08000000); // CREATE_NO_WINDOW
let mut child = cmd.spawn()?;
child
.stdin
.take()
.expect("configured")
.write_all(buffer.to_string().as_ref())?;
let output = child.wait_with_output()?;
if output.status.success() {
// read stdout
let signature = String::from_utf8_lossy(&output.stdout);
let oid = self
.0
.commit_signed(&buffer, &signature, None)
.map(Into::into)
.map_err(Into::into);
return oid;
}
}
}
}
let oid = self
.0
.odb()?
.write(git2::ObjectType::Commit, buffer.as_bytes())?;
Ok(oid)
}
fn is_literal_ssh_key(string: &str) -> (bool, &str) {
if let Some(key) = string.strip_prefix("key::") {
return (true, key);
}
if string.starts_with("ssh-") {
return (true, string);
}
(false, string)
}
// in commit_buffer, inject a line right before the first `\n\n` that we see:
// `change-id: <id>`
fn inject_change_id(commit_buffer: &[u8], change_id: Option<&str>) -> Result<String> {
// if no change id, generate one
let change_id = change_id
.map(|id| id.to_string())
.unwrap_or_else(|| format!("{}", uuid::Uuid::new_v4()));
let commit_ends_in_newline = commit_buffer.ends_with(b"\n");
let commit_buffer = str::from_utf8(commit_buffer).unwrap();
let lines = commit_buffer.lines();
let mut new_buffer = String::new();
let mut found = false;
for line in lines {
if line.is_empty() && !found {
new_buffer.push_str(&format!("change-id {}\n", change_id));
found = true;
}
new_buffer.push_str(line);
new_buffer.push('\n');
}
if !commit_ends_in_newline {
// strip last \n
new_buffer.pop();
}
Ok(new_buffer)
}
pub fn config(&self) -> Result<git2::Config> {
self.0.config().map_err(Into::into)
}

View File

@ -1,7 +1,15 @@
use anyhow::{bail, Context, Result};
use git2::{Repository, Tree};
use std::{process::Stdio, str};
use tracing::instrument;
use super::Refname;
use std::io::Write;
#[cfg(unix)]
use std::os::unix::fs::PermissionsExt;
#[cfg(windows)]
use std::os::windows::process::CommandExt;
/// Extension trait for `git2::Repository`.
///
/// For now, it collects useful methods from `gitbutler-core::git::Repository`
@ -15,6 +23,18 @@ pub trait RepositoryExt {
///
/// This is for safety to assure the repository actually is in 'gitbutler mode'.
fn integration_ref_from_head(&self) -> Result<git2::Reference<'_>>;
#[allow(clippy::too_many_arguments)]
fn commit_with_signature(
&self,
update_ref: Option<&Refname>,
author: &git2::Signature<'_>,
committer: &git2::Signature<'_>,
message: &str,
tree: &git2::Tree<'_>,
parents: &[&git2::Commit<'_>],
change_id: Option<&str>,
) -> Result<git2::Oid>;
}
impl RepositoryExt for Repository {
@ -34,4 +54,185 @@ impl RepositoryExt for Repository {
bail!("Unexpected state: cannot perform operation on non-integration branch")
}
}
#[allow(clippy::too_many_arguments)]
fn commit_with_signature(
&self,
update_ref: Option<&Refname>,
author: &git2::Signature<'_>,
committer: &git2::Signature<'_>,
message: &str,
tree: &git2::Tree<'_>,
parents: &[&git2::Commit<'_>],
change_id: Option<&str>,
) -> Result<git2::Oid> {
let commit_buffer = self.commit_create_buffer(author, committer, message, tree, parents)?;
let commit_buffer = inject_change_id(&commit_buffer, change_id)?;
let oid = do_commit_buffer(self, commit_buffer)?;
// update reference
if let Some(refname) = update_ref {
self.reference(&refname.to_string(), oid, true, message)?;
}
Ok(oid)
}
}
/// takes raw commit data and commits it to the repository
/// - if the git config commit.gpgSign is set, it will sign the commit
/// returns an oid of the new commit object
fn do_commit_buffer(repo: &git2::Repository, buffer: String) -> Result<git2::Oid> {
// check git config for gpg.signingkey
let should_sign = repo.config()?.get_bool("commit.gpgSign").unwrap_or(false);
if should_sign {
// TODO: support gpg.ssh.defaultKeyCommand to get the signing key if this value doesn't exist
let signing_key = repo.config()?.get_string("user.signingkey");
if let Ok(signing_key) = signing_key {
let sign_format = repo.config()?.get_string("gpg.format");
let is_ssh = if let Ok(sign_format) = sign_format {
sign_format == "ssh"
} else {
false
};
if is_ssh {
// write commit data to a temp file so we can sign it
let mut signature_storage = tempfile::NamedTempFile::new()?;
signature_storage.write_all(buffer.as_ref())?;
let buffer_file_to_sign_path = signature_storage.into_temp_path();
let gpg_program = repo.config()?.get_string("gpg.ssh.program");
let mut cmd =
std::process::Command::new(gpg_program.unwrap_or("ssh-keygen".to_string()));
cmd.args(["-Y", "sign", "-n", "git", "-f"]);
#[cfg(windows)]
cmd.creation_flags(0x08000000); // CREATE_NO_WINDOW
let output;
// support literal ssh key
if let (true, signing_key) = is_literal_ssh_key(&signing_key) {
// write the key to a temp file
let mut key_storage = tempfile::NamedTempFile::new()?;
key_storage.write_all(signing_key.as_bytes())?;
// if on unix
#[cfg(unix)]
{
// make sure the tempfile permissions are acceptable for a private ssh key
let mut permissions = key_storage.as_file().metadata()?.permissions();
permissions.set_mode(0o600);
key_storage.as_file().set_permissions(permissions)?;
}
let key_file_path = key_storage.into_temp_path();
cmd.arg(&key_file_path);
cmd.arg("-U");
cmd.arg(&buffer_file_to_sign_path);
cmd.stdout(Stdio::piped());
cmd.stdin(Stdio::null());
let child = cmd.spawn()?;
output = child.wait_with_output()?;
} else {
cmd.arg(signing_key);
cmd.arg(&buffer_file_to_sign_path);
cmd.stdout(Stdio::piped());
cmd.stdin(Stdio::null());
let child = cmd.spawn()?;
output = child.wait_with_output()?;
}
if output.status.success() {
// read signed_storage path plus .sig
let signature_path = buffer_file_to_sign_path.with_extension("sig");
let sig_data = std::fs::read(signature_path)?;
let signature = String::from_utf8_lossy(&sig_data);
let oid = repo
.commit_signed(&buffer, &signature, None)
.map(Into::into)
.map_err(Into::into);
return oid;
}
} else {
// is gpg
let gpg_program = repo.config()?.get_string("gpg.program");
let mut cmd = std::process::Command::new(gpg_program.unwrap_or("gpg".to_string()));
cmd.args(["--status-fd=2", "-bsau", &signing_key])
//.arg(&signed_storage)
.arg("-")
.stdout(Stdio::piped())
.stdin(Stdio::piped());
#[cfg(windows)]
cmd.creation_flags(0x08000000); // CREATE_NO_WINDOW
let mut child = cmd.spawn()?;
child
.stdin
.take()
.expect("configured")
.write_all(buffer.to_string().as_ref())?;
let output = child.wait_with_output()?;
if output.status.success() {
// read stdout
let signature = String::from_utf8_lossy(&output.stdout);
let oid = repo
.commit_signed(&buffer, &signature, None)
.map(Into::into)
.map_err(Into::into);
return oid;
}
}
}
}
let oid = repo
.odb()?
.write(git2::ObjectType::Commit, buffer.as_bytes())?;
Ok(oid)
}
fn is_literal_ssh_key(string: &str) -> (bool, &str) {
if let Some(key) = string.strip_prefix("key::") {
return (true, key);
}
if string.starts_with("ssh-") {
return (true, string);
}
(false, string)
}
// in commit_buffer, inject a line right before the first `\n\n` that we see:
// `change-id: <id>`
fn inject_change_id(commit_buffer: &[u8], change_id: Option<&str>) -> Result<String> {
// if no change id, generate one
let change_id = change_id
.map(|id| id.to_string())
.unwrap_or_else(|| format!("{}", uuid::Uuid::new_v4()));
let commit_ends_in_newline = commit_buffer.ends_with(b"\n");
let commit_buffer = str::from_utf8(commit_buffer).unwrap();
let lines = commit_buffer.lines();
let mut new_buffer = String::new();
let mut found = false;
for line in lines {
if line.is_empty() && !found {
new_buffer.push_str(&format!("change-id {}\n", change_id));
found = true;
}
new_buffer.push_str(line);
new_buffer.push('\n');
}
if !commit_ends_in_newline {
// strip last \n
new_buffer.pop();
}
Ok(new_buffer)
}

View File

@ -7,7 +7,6 @@ use std::{
use anyhow::{anyhow, Context, Result};
use super::conflicts;
use crate::virtual_branches::errors::Marker;
use crate::{
askpass,
git::{self, Url},
@ -16,6 +15,7 @@ use crate::{
virtual_branches::{Branch, BranchId},
};
use crate::{error::Code, git::Oid};
use crate::{git::RepositoryExt, virtual_branches::errors::Marker};
pub struct Repository {
pub git_repository: git::Repository,
@ -333,11 +333,11 @@ impl Repository {
tree: &git2::Tree,
parents: &[&git2::Commit],
change_id: Option<&str>,
) -> Result<git::Oid> {
) -> Result<git2::Oid> {
let (author, committer) =
super::signatures::signatures(self, user).context("failed to get signatures")?;
self.git_repository
.commit(None, &author, &committer, message, tree, parents, change_id)
self.repo()
.commit_with_signature(None, &author, &committer, message, tree, parents, change_id)
.context("failed to commit")
}

View File

@ -497,7 +497,7 @@ pub fn update_base_branch(
)
.context("failed to commit merge")?;
branch.head = new_target_head;
branch.head = new_target_head.into();
branch.tree = branch_merge_index_tree_oid.into();
vb_state.set_branch(branch.clone())?;
Ok(Some(branch))

View File

@ -329,8 +329,8 @@ impl Controller {
&self,
project_id: ProjectId,
branch_id: BranchId,
commit_oid: git::Oid,
) -> Result<Option<git::Oid>> {
commit_oid: git2::Oid,
) -> Result<Option<git2::Oid>> {
self.inner(project_id)
.await
.cherry_pick(project_id, branch_id, commit_oid)
@ -809,8 +809,8 @@ impl ControllerInner {
&self,
project_id: ProjectId,
branch_id: BranchId,
commit_oid: git::Oid,
) -> Result<Option<git::Oid>> {
commit_oid: git2::Oid,
) -> Result<Option<git2::Oid>> {
let _permit = self.semaphore.acquire().await;
self.with_verify_branch(project_id, |project_repository, _| {

View File

@ -5,6 +5,7 @@ use bstr::ByteSlice;
use lazy_static::lazy_static;
use super::VirtualBranchesHandle;
use crate::git::RepositoryExt;
use crate::virtual_branches::errors::Marker;
use crate::{
git::{self, CommitExt},
@ -389,8 +390,8 @@ impl project_repository::Repository {
.context("failed to find new branch head")?;
let rebased_commit_oid = self
.git_repository
.commit(
.repo()
.commit_with_signature(
None,
&commit.author(),
&commit.committer(),
@ -406,7 +407,7 @@ impl project_repository::Repository {
let rebased_commit = self
.git_repository
.find_commit(rebased_commit_oid)
.find_commit(rebased_commit_oid.into())
.context(format!(
"failed to find rebased commit {}",
rebased_commit_oid

View File

@ -343,7 +343,7 @@ pub fn apply_branch(
)?;
// ok, update the virtual branch
branch.head = new_branch_head;
branch.head = new_branch_head.into();
} else {
// branch was not pushed to upstream yet. attempt a rebase,
let (_, committer) =
@ -411,7 +411,7 @@ pub fn apply_branch(
)
.context("failed to commit merge")?;
branch.head = new_branch_head;
branch.head = new_branch_head.into();
}
}
@ -1214,6 +1214,7 @@ pub fn integrate_upstream_commits(
&upstream_commit,
merge_base,
)
.map(Into::into)
}
};
@ -1270,7 +1271,7 @@ pub fn integrate_with_merge(
branch: &mut Branch,
upstream_commit: &git2::Commit,
merge_base: git::Oid,
) -> Result<git::Oid> {
) -> Result<git2::Oid> {
let wd_tree = project_repository.repo().get_wd_tree()?;
let repo = &project_repository.git_repository;
let remote_tree = upstream_commit.tree().context("failed to get tree")?;
@ -2326,7 +2327,7 @@ pub fn commit(
let vb_state = project_repository.project().virtual_branches();
branch.tree = tree_oid;
branch.head = commit_oid;
branch.head = commit_oid.into();
vb_state
.set_branch(branch.clone())
.context("failed to write branch")?;
@ -2334,7 +2335,7 @@ pub fn commit(
super::integration::update_gitbutler_integration(&vb_state, project_repository)
.context("failed to update gitbutler integration")?;
Ok(commit_oid)
Ok(commit_oid.into())
}
pub fn push(
@ -2709,8 +2710,9 @@ pub fn move_commit_file(
.find_tree(new_from_tree_id)
.with_context(|| "tree {new_from_tree_oid} not found")?;
let change_id = from_commit.change_id();
let new_from_commit_oid = repo
.commit(
let new_from_commit_oid = project_repository
.repo()
.commit_with_signature(
None,
&from_commit.author(),
&from_commit.committer(),
@ -2724,7 +2726,7 @@ pub fn move_commit_file(
// rebase everything above the new "from" commit that has the moved changes removed
let new_head = match cherry_rebase(
project_repository,
new_from_commit_oid,
new_from_commit_oid.into(),
from_commit_id,
target_branch.head,
) {
@ -2785,8 +2787,8 @@ pub fn move_commit_file(
let parents: Vec<_> = amend_commit.parents().collect();
let change_id = amend_commit.change_id();
let commit_oid = project_repository
.git_repository
.commit(
.repo()
.commit_with_signature(
None,
&amend_commit.author(),
&amend_commit.committer(),
@ -2801,17 +2803,17 @@ pub fn move_commit_file(
// if there are no upstream commits (the "to" commit was the branch head), then we're done
if upstream_commits.is_empty() {
target_branch.head = commit_oid;
target_branch.head = commit_oid.into();
vb_state.set_branch(target_branch.clone())?;
super::integration::update_gitbutler_integration(&vb_state, project_repository)?;
return Ok(commit_oid);
return Ok(commit_oid.into());
}
// otherwise, rebase the upstream commits onto the new commit
let last_commit = upstream_commits.first().cloned().unwrap();
let new_head = cherry_rebase(
project_repository,
commit_oid,
commit_oid.into(),
amend_commit.id().into(),
last_commit,
)?;
@ -2821,7 +2823,7 @@ pub fn move_commit_file(
target_branch.head = new_head;
vb_state.set_branch(target_branch.clone())?;
super::integration::update_gitbutler_integration(&vb_state, project_repository)?;
Ok(commit_oid)
Ok(commit_oid.into())
} else {
Err(anyhow!("rebase failed"))
}
@ -2934,8 +2936,8 @@ pub fn amend(
let parents: Vec<_> = amend_commit.parents().collect();
let commit_oid = project_repository
.git_repository
.commit(
.repo()
.commit_with_signature(
None,
&amend_commit.author(),
&amend_commit.committer(),
@ -2953,17 +2955,17 @@ pub fn amend(
)?;
// if there are no upstream commits, we're done
if upstream_commits.is_empty() {
target_branch.head = commit_oid;
target_branch.head = commit_oid.into();
vb_state.set_branch(target_branch.clone())?;
super::integration::update_gitbutler_integration(&vb_state, project_repository)?;
return Ok(commit_oid);
return Ok(commit_oid.into());
}
let last_commit = upstream_commits.first().cloned().unwrap();
let new_head = cherry_rebase(
project_repository,
commit_oid,
commit_oid.into(),
amend_commit.id().into(),
last_commit,
)?;
@ -2972,7 +2974,7 @@ pub fn amend(
target_branch.head = new_head;
vb_state.set_branch(target_branch.clone())?;
super::integration::update_gitbutler_integration(&vb_state, project_repository)?;
Ok(commit_oid)
Ok(commit_oid.into())
} else {
Err(anyhow!("rebase failed"))
}
@ -3102,7 +3104,7 @@ pub fn insert_blank_commit(
if commit.id() == branch.head.into() && offset < 0 {
// inserting before the first commit
branch.head = blank_commit_oid;
branch.head = blank_commit_oid.into();
vb_state
.set_branch(branch.clone())
.context("failed to write branch")?;
@ -3112,7 +3114,7 @@ pub fn insert_blank_commit(
// rebase all commits above it onto the new commit
match cherry_rebase(
project_repository,
blank_commit_oid,
blank_commit_oid.into(),
commit.id().into(),
branch.head,
) {
@ -3261,8 +3263,8 @@ fn cherry_rebase_group(
let change_id = to_rebase.change_id();
let commit_oid = project_repository
.git_repository
.commit(
.repo()
.commit_with_signature(
None,
&to_rebase.author(),
&to_rebase.committer(),
@ -3275,7 +3277,7 @@ fn cherry_rebase_group(
project_repository
.git_repository
.find_commit(commit_oid)
.find_commit(commit_oid.into())
.context("failed to find commit")
},
)?
@ -3287,8 +3289,8 @@ fn cherry_rebase_group(
pub fn cherry_pick(
project_repository: &project_repository::Repository,
branch_id: BranchId,
target_commit_id: git::Oid,
) -> Result<Option<git::Oid>> {
target_commit_id: git2::Oid,
) -> Result<Option<git2::Oid>> {
project_repository.assure_unconflicted()?;
let vb_state = project_repository.project().virtual_branches();
@ -3304,7 +3306,7 @@ pub fn cherry_pick(
let target_commit = project_repository
.git_repository
.find_commit(target_commit_id)
.find_commit(target_commit_id.into())
.map_err(|error| match error {
git::Error::NotFound(_) => anyhow!("commit {target_commit_id} not found "),
err => err.into(),
@ -3351,8 +3353,8 @@ pub fn cherry_pick(
let signature = git2::Signature::now("GitButler", "gitbutler@gitbutler.com")
.context("failed to make gb signature")?;
let oid = project_repository
.git_repository
.commit(
.repo()
.commit_with_signature(
None,
&signature,
&signature,
@ -3364,7 +3366,7 @@ pub fn cherry_pick(
.context("failed to commit wip work")?;
project_repository
.git_repository
.find_commit(oid)
.find_commit(oid.into())
.context("failed to find wip commit")?
};
@ -3425,8 +3427,8 @@ pub fn cherry_pick(
let change_id = target_commit.change_id();
let commit_oid = project_repository
.git_repository
.commit(
.repo()
.commit_with_signature(
None,
&target_commit.author(),
&target_commit.committer(),
@ -3447,7 +3449,7 @@ pub fn cherry_pick(
.context("failed to checkout final tree")?;
// update branch status
branch.head = commit_oid;
branch.head = commit_oid.into();
vb_state
.set_branch(branch.clone())
.context("failed to write branch")?;
@ -3521,8 +3523,8 @@ pub fn squash(
let change_id = commit_to_squash.change_id();
let new_commit_oid = project_repository
.git_repository
.commit(
.repo()
.commit_with_signature(
None,
&commit_to_squash.author(),
&commit_to_squash.committer(),
@ -3546,7 +3548,11 @@ pub fn squash(
.with_context(|| format!("commit {commit_id} not in the branch"))?;
let mut ids_to_rebase = ids_to_rebase.to_vec();
match cherry_rebase_group(project_repository, new_commit_oid, &mut ids_to_rebase) {
match cherry_rebase_group(
project_repository,
new_commit_oid.into(),
&mut ids_to_rebase,
) {
Ok(new_head_id) => {
// save new branch head
branch.head = new_head_id;
@ -3612,8 +3618,8 @@ pub fn update_commit_message(
let change_id = target_commit.change_id();
let new_commit_oid = project_repository
.git_repository
.commit(
.repo()
.commit_with_signature(
None,
&target_commit.author(),
&target_commit.committer(),
@ -3633,8 +3639,12 @@ pub fn update_commit_message(
.with_context(|| format!("commit {commit_id} not in the branch"))?;
let mut ids_to_rebase = ids_to_rebase.to_vec();
let new_head_id = cherry_rebase_group(project_repository, new_commit_oid, &mut ids_to_rebase)
.map_err(|err| err.context("rebase error"))?;
let new_head_id = cherry_rebase_group(
project_repository,
new_commit_oid.into(),
&mut ids_to_rebase,
)
.map_err(|err| err.context("rebase error"))?;
// save new branch head
branch.head = new_head_id;
vb_state
@ -3780,7 +3790,7 @@ pub fn move_commit(
)
.context("failed to commit")?;
destination_branch.head = new_destination_head_oid;
destination_branch.head = new_destination_head_oid.into();
vb_state.set_branch(destination_branch.clone())?;
}

View File

@ -57,7 +57,7 @@ mod cleanly {
);
let cherry_picked_commit_oid = controller
.cherry_pick(*project_id, branch_id, commit_two)
.cherry_pick(*project_id, branch_id, commit_two.into())
.await
.unwrap();
assert!(cherry_picked_commit_oid.is_some());
@ -72,7 +72,10 @@ mod cleanly {
assert_eq!(branches[0].id, branch_id);
assert!(branches[0].active);
assert_eq!(branches[0].commits.len(), 2);
assert_eq!(branches[0].commits[0].id, cherry_picked_commit_oid.unwrap());
assert_eq!(
branches[0].commits[0].id,
cherry_picked_commit_oid.unwrap().into()
);
assert_eq!(branches[0].commits[1].id, commit_one);
}
@ -135,7 +138,7 @@ mod cleanly {
.unwrap();
let cherry_picked_commit_oid = controller
.cherry_pick(*project_id, branch_two_id, commit_two)
.cherry_pick(*project_id, branch_two_id, commit_two.into())
.await
.unwrap();
assert!(cherry_picked_commit_oid.is_some());
@ -156,7 +159,10 @@ mod cleanly {
assert_eq!(branches[1].id, branch_two_id);
assert!(branches[1].active);
assert_eq!(branches[1].commits.len(), 1);
assert_eq!(branches[1].commits[0].id, cherry_picked_commit_oid.unwrap());
assert_eq!(
branches[1].commits[0].id,
cherry_picked_commit_oid.unwrap().into()
);
}
#[tokio::test]
@ -214,7 +220,7 @@ mod cleanly {
assert_eq!(
controller
.cherry_pick(*project_id, branch_id, commit_three_oid)
.cherry_pick(*project_id, branch_id, commit_three_oid.into())
.await
.unwrap_err()
.to_string(),
@ -294,7 +300,7 @@ mod with_conflicts {
{
// cherry picking leads to conflict
let cherry_picked_commit_oid = controller
.cherry_pick(*project_id, branch_id, commit_three)
.cherry_pick(*project_id, branch_id, commit_three.into())
.await
.unwrap();
assert!(cherry_picked_commit_oid.is_none());
@ -376,7 +382,7 @@ mod with_conflicts {
assert_eq!(
controller
.cherry_pick(*project_id, branch_id, commit_oid)
.cherry_pick(*project_id, branch_id, commit_oid.into())
.await
.unwrap_err()
.to_string(),

View File

@ -15,7 +15,7 @@ use std::{
use anyhow::{Context, Result};
use git2::TreeEntry;
use gitbutler_core::{
git::{self, CommitExt},
git::{self, CommitExt, RepositoryExt},
virtual_branches::{
self, apply_branch,
branch::{BranchCreateRequest, BranchOwnershipClaims},
@ -715,8 +715,9 @@ fn commit_id_can_be_generated_or_specified() -> Result<()> {
let signature = git2::Signature::now("test", "test@email.com").unwrap();
let head = repository.head().expect("failed to get head");
let refname: git::Refname = head.name().unwrap().parse().unwrap();
repository
.commit(
project_repository
.repo()
.commit_with_signature(
Some(&refname),
&signature,
&signature,

View File

@ -342,10 +342,10 @@ pub mod commands {
) -> Result<Option<git::Oid>, Error> {
let oid = handle
.state::<Controller>()
.cherry_pick(project_id, branch_id, target_commit_oid)
.cherry_pick(project_id, branch_id, target_commit_oid.into())
.await?;
emit_vbranches(&handle, project_id).await;
Ok(oid)
Ok(oid.map(Into::into))
}
#[tauri::command(async)]

View File

@ -4,7 +4,7 @@ use std::{
path::{Path, PathBuf},
};
use gitbutler_core::project_repository;
use gitbutler_core::{git::RepositoryExt, project_repository};
use tempfile::{tempdir, TempDir};
use crate::{init_opts, init_opts_bare, VAR_NO_CLEANUP};
@ -169,19 +169,19 @@ pub fn test_repository() -> (gitbutler_core::git::Repository, TempDir) {
let mut index = repository.index().expect("failed to get index");
let oid = index.write_tree().expect("failed to write tree");
let signature = git2::Signature::now("test", "test@email.com").unwrap();
repository
.commit(
Some(&"refs/heads/master".parse().unwrap()),
&signature,
&signature,
"Initial commit",
&repository
.find_tree(oid.into())
.expect("failed to find tree"),
&[],
None,
)
.expect("failed to commit");
let repo: &git2::Repository = (&repository).into();
repo.commit_with_signature(
Some(&"refs/heads/master".parse().unwrap()),
&signature,
&signature,
"Initial commit",
&repository
.find_tree(oid.into())
.expect("failed to find tree"),
&[],
None,
)
.expect("failed to commit");
(repository, tmp)
}
@ -194,8 +194,9 @@ pub fn commit_all(repository: &gitbutler_core::git::Repository) -> gitbutler_cor
let oid = index.write_tree().expect("failed to write tree");
let signature = git2::Signature::now("test", "test@email.com").unwrap();
let head = repository.head().expect("failed to get head");
let commit_oid = repository
.commit(
let repo: &git2::Repository = repository.into();
let commit_oid = repo
.commit_with_signature(
Some(&head.name().map(|name| name.parse().unwrap()).unwrap()),
&signature,
&signature,
@ -213,5 +214,5 @@ pub fn commit_all(repository: &gitbutler_core::git::Repository) -> gitbutler_cor
None,
)
.expect("failed to commit");
commit_oid
commit_oid.into()
}

View File

@ -1,7 +1,7 @@
use std::path;
use std::path::PathBuf;
use gitbutler_core::git::{self};
use gitbutler_core::git::{self, RepositoryExt};
use tempfile::TempDir;
use crate::{init_opts, VAR_NO_CLEANUP};
@ -35,19 +35,19 @@ impl Default for TestProject {
let mut index = local_repository.index().expect("failed to get index");
let oid = index.write_tree().expect("failed to write tree");
let signature = git2::Signature::now("test", "test@email.com").unwrap();
local_repository
.commit(
Some(&"refs/heads/master".parse().unwrap()),
&signature,
&signature,
"Initial commit",
&local_repository
.find_tree(oid.into())
.expect("failed to find tree"),
&[],
None,
)
.expect("failed to commit");
let repo: &git2::Repository = (&local_repository).into();
repo.commit_with_signature(
Some(&"refs/heads/master".parse().unwrap()),
&signature,
&signature,
"Initial commit",
&local_repository
.find_tree(oid.into())
.expect("failed to find tree"),
&[],
None,
)
.expect("failed to commit");
let remote_tmp = temp_dir();
let remote_repository = git::Repository::init_opts(
@ -243,17 +243,17 @@ impl TestProject {
self.remote_repository.find_tree(oid.into()).unwrap()
};
self.remote_repository
.commit(
Some(&"refs/heads/master".parse().unwrap()),
&branch_commit.author(),
&branch_commit.committer(),
&format!("Merge pull request from {}", branch_name),
&merge_tree,
&[&master_branch_commit, &branch_commit],
None,
)
.unwrap();
let repo: &git2::Repository = (&self.remote_repository).into();
repo.commit_with_signature(
Some(&"refs/heads/master".parse().unwrap()),
&branch_commit.author(),
&branch_commit.committer(),
&format!("Merge pull request from {}", branch_name),
&merge_tree,
&[&master_branch_commit, &branch_commit],
None,
)
.unwrap();
}
pub fn find_commit(&self, oid: git::Oid) -> Result<git2::Commit<'_>, git::Error> {
@ -309,27 +309,28 @@ impl TestProject {
let oid = index.write_tree().expect("failed to write tree");
let signature = git2::Signature::now("test", "test@email.com").unwrap();
let refname: git::Refname = head.name().unwrap().parse().unwrap();
self.local_repository
.commit(
Some(&refname),
&signature,
&signature,
message,
&self
.local_repository
.find_tree(oid.into())
.expect("failed to find tree"),
&[&self
.local_repository
.find_commit(
self.local_repository
.refname_to_id("HEAD")
.expect("failed to get head"),
)
.expect("failed to find commit")],
None,
)
.expect("failed to commit")
let repo: &git2::Repository = (&self.local_repository).into();
repo.commit_with_signature(
Some(&refname),
&signature,
&signature,
message,
&self
.local_repository
.find_tree(oid.into())
.expect("failed to find tree"),
&[&self
.local_repository
.find_commit(
self.local_repository
.refname_to_id("HEAD")
.expect("failed to get head"),
)
.expect("failed to find commit")],
None,
)
.expect("failed to commit")
.into()
}
pub fn references(&self) -> Vec<git2::Reference<'_>> {