mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2025-01-05 17:15:19 +03:00
Merge pull request #3963 from gitbutlerapp/refname-mod-rs-cleanup
refname-mod-rs-cleanup
This commit is contained in:
commit
8eb7d1d0f0
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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")
|
||||
}
|
||||
|
||||
|
@ -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))
|
||||
|
@ -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, _| {
|
||||
|
@ -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
|
||||
|
@ -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())?;
|
||||
}
|
||||
|
||||
|
@ -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(),
|
||||
|
@ -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,
|
||||
|
@ -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)]
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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<'_>> {
|
||||
|
Loading…
Reference in New Issue
Block a user