Merge pull request #3889 from gitbutlerapp/remove-commit-reference

remove-commit-reference
This commit is contained in:
Kiril Videlov 2024-05-29 17:48:54 +02:00 committed by GitHub
commit ea219eedf9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 246 additions and 278 deletions

View File

@ -1,4 +1,4 @@
use super::{Commit, Oid, Result};
use super::{Oid, Result};
pub struct Branch<'repo> {
branch: git2::Branch<'repo>,
@ -35,7 +35,7 @@ impl<'repo> Branch<'repo> {
self.branch.get().peel_to_tree().map_err(Into::into)
}
pub fn peel_to_commit(&self) -> Result<Commit<'repo>> {
pub fn peel_to_commit(&self) -> Result<git2::Commit<'repo>> {
self.branch
.get()
.peel_to_commit()

View File

@ -1,94 +0,0 @@
use super::{Oid, Result, Signature};
use bstr::BStr;
#[derive(Debug)]
pub struct Commit<'repo> {
pub commit: git2::Commit<'repo>,
}
impl<'repo> From<git2::Commit<'repo>> for Commit<'repo> {
fn from(commit: git2::Commit<'repo>) -> Self {
Self { commit }
}
}
impl<'repo> From<&'repo git2::Commit<'repo>> for Commit<'repo> {
fn from(commit: &'repo git2::Commit<'repo>) -> Self {
Self {
commit: commit.clone(),
}
}
}
impl<'repo> From<&'repo Commit<'repo>> for &'repo git2::Commit<'repo> {
fn from(val: &'repo Commit<'repo>) -> Self {
&val.commit
}
}
impl<'repo> Commit<'repo> {
pub fn id(&self) -> Oid {
self.commit.id().into()
}
pub fn parent_count(&self) -> usize {
self.commit.parent_count()
}
pub fn tree(&self) -> Result<git2::Tree<'repo>> {
self.commit.tree().map_err(Into::into)
}
pub fn tree_id(&self) -> Oid {
self.commit.tree_id().into()
}
pub fn parents(&self) -> Result<Vec<Commit<'repo>>> {
let mut parents = vec![];
for i in 0..self.parent_count() {
parents.push(self.parent(i)?);
}
Ok(parents)
}
pub fn parent(&self, n: usize) -> Result<Commit<'repo>> {
self.commit.parent(n).map(Into::into).map_err(Into::into)
}
pub fn time(&self) -> git2::Time {
self.commit.time()
}
pub fn author(&self) -> Signature<'_> {
self.commit.author().into()
}
/// Obtain the commit-message as bytes, but without assuming any encoding.
pub fn message(&self) -> &BStr {
self.commit.message_bytes().as_ref()
}
pub fn committer(&self) -> Signature<'_> {
self.commit.committer().into()
}
pub fn change_id(&self) -> Option<String> {
let cid = self.commit.header_field_bytes("change-id").ok()?;
if cid.is_empty() {
None
} else {
// convert the Buf to a string
let ch_id = std::str::from_utf8(&cid).ok()?.to_owned();
Some(ch_id)
}
}
pub fn is_signed(&self) -> bool {
let cid = self.commit.header_field_bytes("gpgsig").ok();
cid.is_some()
}
pub fn raw_header(&self) -> Option<&str> {
self.commit.raw_header()
}
}

View File

@ -0,0 +1,46 @@
// use anyhow::Result;
use super::Result;
use bstr::BStr;
use git2::Commit;
/// Extension trait for `git2::Commit`.
///
/// For now, it collects useful methods from `gitbutler-core::git::Commit`
pub trait CommitExt {
/// Obtain the commit-message as bytes, but without assuming any encoding.
fn message_bstr(&self) -> &BStr;
fn change_id(&self) -> Option<String>;
fn parents_gb(&self) -> Result<Vec<Commit<'_>>>;
fn is_signed(&self) -> bool;
fn tree_gb(&self) -> Result<git2::Tree<'_>>;
}
impl<'repo> CommitExt for git2::Commit<'repo> {
fn message_bstr(&self) -> &BStr {
self.message_bytes().as_ref()
}
fn change_id(&self) -> Option<String> {
let cid = self.header_field_bytes("change-id").ok()?;
if cid.is_empty() {
None
} else {
// convert the Buf to a string
let ch_id = std::str::from_utf8(&cid).ok()?.to_owned();
Some(ch_id)
}
}
fn parents_gb(&self) -> Result<Vec<Commit<'repo>>> {
let mut parents = vec![];
for i in 0..self.parent_count() {
parents.push(self.parent(i)?);
}
Ok(parents)
}
fn is_signed(&self) -> bool {
let cid = self.header_field_bytes("gpgsig").ok();
cid.is_some()
}
fn tree_gb(&self) -> Result<git2::Tree<'repo>> {
self.tree().map_err(Into::into)
}
}

View File

@ -13,9 +13,6 @@ mod repository;
pub use repository::*;
mod commit;
pub use commit::*;
mod branch;
pub use branch::*;
@ -45,3 +42,6 @@ pub use repository_ext::*;
mod tree_ext;
pub use tree_ext::*;
mod commit_ext;
pub use commit_ext::*;

View File

@ -1,7 +1,7 @@
mod refname;
pub use refname::{LocalRefname, Refname, RemoteRefname, VirtualRefname};
use super::{Commit, Oid, Result};
use super::{Oid, Result};
pub struct Reference<'repo> {
reference: git2::Reference<'repo>,
@ -28,7 +28,7 @@ impl<'repo> Reference<'repo> {
self.reference.target().map(Into::into)
}
pub fn peel_to_commit(&self) -> Result<Commit<'repo>> {
pub fn peel_to_commit(&self) -> Result<git2::Commit<'repo>> {
self.reference
.peel_to_commit()
.map(Into::into)

View File

@ -1,6 +1,6 @@
use super::{
Blob, Branch, Commit, Config, Index, Oid, Reference, Refname, Remote, Result, Signature,
TreeBuilder, Url,
Blob, Branch, Config, Index, Oid, Reference, Refname, Remote, Result, Signature, TreeBuilder,
Url,
};
use git2::{BlameOptions, Submodule};
use git2_hooks::HookResult;
@ -134,11 +134,11 @@ impl Repository {
pub fn reset(
&self,
commit: &Commit<'_>,
commit: &git2::Commit<'_>,
kind: git2::ResetType,
checkout: Option<&mut git2::build::CheckoutBuilder<'_>>,
) -> Result<()> {
let commit: &git2::Commit = commit.into();
let commit: &git2::Commit = commit;
self.0
.reset(commit.as_object(), kind, checkout)
.map_err(Into::into)
@ -159,11 +159,8 @@ impl Repository {
self.0.find_tree(id.into()).map_err(Into::into)
}
pub fn find_commit(&self, id: Oid) -> Result<Commit> {
self.0
.find_commit(id.into())
.map(Commit::from)
.map_err(Into::into)
pub fn find_commit(&self, id: Oid) -> Result<git2::Commit> {
self.0.find_commit(id.into()).map_err(Into::into)
}
pub fn find_blob(&self, id: Oid) -> Result<Blob> {
@ -212,9 +209,9 @@ impl Repository {
.map_err(Into::into)
}
pub fn cherry_pick(&self, base: &Commit, target: &Commit) -> Result<Index> {
pub fn cherry_pick(&self, base: &git2::Commit, target: &git2::Commit) -> Result<Index> {
self.0
.cherrypick_commit(target.into(), base.into(), 0, None)
.cherrypick_commit(target, base, 0, None)
.map(Into::into)
.map_err(Into::into)
}
@ -231,13 +228,10 @@ impl Repository {
committer: &Signature<'_>,
message: &str,
tree: &git2::Tree<'_>,
parents: &[&Commit<'_>],
parents: &[&git2::Commit<'_>],
change_id: Option<&str>,
) -> Result<Oid> {
let parents: Vec<&git2::Commit> = parents
.iter()
.map(|c| c.to_owned().into())
.collect::<Vec<_>>();
let parents: Vec<&git2::Commit> = parents.iter().map(|c| c.to_owned()).collect::<Vec<_>>();
let commit_buffer = self.0.commit_create_buffer(
author.into(),
@ -538,9 +532,9 @@ impl Repository {
.map_err(Into::into)
}
pub fn branch(&self, name: &Refname, target: &Commit, force: bool) -> Result<Branch> {
pub fn branch(&self, name: &Refname, target: &git2::Commit, force: bool) -> Result<Branch> {
self.0
.branch(&name.to_string(), target.into(), force)
.branch(&name.to_string(), target, force)
.map(Into::into)
.map_err(Into::into)
}

View File

@ -7,7 +7,6 @@ use std::{
use anyhow::{Context, Result};
use super::conflicts;
use crate::error::{AnyhowContextExt, Code, ErrorWithContext};
use crate::{
askpass, error,
git::{self, credentials::HelpError, Url},
@ -15,6 +14,10 @@ use crate::{
ssh, users,
virtual_branches::{Branch, BranchId},
};
use crate::{
error::{AnyhowContextExt, Code, ErrorWithContext},
git::Oid,
};
pub struct Repository {
pub git_repository: git::Repository,
@ -168,7 +171,7 @@ impl Repository {
let target_branch_refname =
git::Refname::from_str(&format!("refs/remotes/{}/{}", remote_name, branch_name))?;
let branch = self.git_repository.find_branch(&target_branch_refname)?;
let commit_id = branch.peel_to_commit()?.id();
let commit_id: Oid = branch.peel_to_commit()?.id().into();
let now = crate::time::now_ms();
let branch_name = format!("test-push-{now}");
@ -313,7 +316,7 @@ impl Repository {
self.l(from, LogUntil::Commit(to))
}
pub fn list_commits(&self, from: git::Oid, to: git::Oid) -> Result<Vec<git::Commit>> {
pub fn list_commits(&self, from: git::Oid, to: git::Oid) -> Result<Vec<git2::Commit>> {
Ok(self
.list(from, to)?
.into_iter()
@ -322,7 +325,7 @@ impl Repository {
}
// returns a list of commits from the first oid to the second oid
pub fn log(&self, from: git::Oid, to: LogUntil) -> Result<Vec<git::Commit>> {
pub fn log(&self, from: git::Oid, to: LogUntil) -> Result<Vec<git2::Commit>> {
self.l(from, to)?
.into_iter()
.map(|oid| self.git_repository.find_commit(oid))
@ -341,7 +344,7 @@ impl Repository {
user: Option<&users::User>,
message: &str,
tree: &git2::Tree,
parents: &[&git::Commit],
parents: &[&git2::Commit],
change_id: Option<&str>,
) -> Result<git::Oid> {
let (author, committer) = self.git_signatures(user)?;
@ -652,7 +655,7 @@ impl ErrorWithContext for RemoteError {
}
}
type OidFilter = dyn Fn(&git::Commit) -> Result<bool>;
type OidFilter = dyn Fn(&git2::Commit) -> Result<bool>;
pub enum LogUntil {
Commit(git::Oid),

View File

@ -1,6 +1,7 @@
use std::{path::Path, time};
use anyhow::{Context, Result};
use git2::Index;
use serde::Serialize;
use super::{
@ -15,8 +16,7 @@ use crate::{
project_repository::{self, LogUntil},
projects::FetchResult,
users,
virtual_branches::branch::BranchOwnershipClaims,
virtual_branches::cherry_rebase,
virtual_branches::{branch::BranchOwnershipClaims, cherry_rebase},
};
#[derive(Debug, Serialize, PartialEq, Clone)]
@ -162,7 +162,10 @@ pub fn set_base_branch(
// calculate the commit as the merge-base between HEAD in project_repository and this target commit
let target_commit_oid = repo
.merge_base(current_head_commit.id(), target_branch_head.id())
.merge_base(
current_head_commit.id().into(),
target_branch_head.id().into(),
)
.context(format!(
"Failed to calculate merge base between {} and {}",
current_head_commit.id(),
@ -190,8 +193,8 @@ pub fn set_base_branch(
// if there are any commits on the head branch or uncommitted changes in the working directory, we need to
// put them into a virtual branch
let wd_diff = diff::workdir(repo, &current_head_commit.id())?;
if !wd_diff.is_empty() || current_head_commit.id() != target.sha {
let wd_diff = diff::workdir(repo, &current_head_commit.id().into())?;
if !wd_diff.is_empty() || current_head_commit.id() != target.sha.into() {
// assign ownership to the branch
let ownership = wd_diff.iter().fold(
BranchOwnershipClaims::default(),
@ -244,13 +247,13 @@ pub fn set_base_branch(
notes: String::new(),
applied: true,
upstream,
upstream_head,
upstream_head: upstream_head.map(|h| h.into()),
created_timestamp_ms: now_ms,
updated_timestamp_ms: now_ms,
head: current_head_commit.id(),
head: current_head_commit.id().into(),
tree: super::write_tree_onto_commit(
project_repository,
current_head_commit.id(),
current_head_commit.id().into(),
diff::diff_files_into_hunks(wd_diff),
)?,
ownership,
@ -353,7 +356,7 @@ pub fn update_base_branch(
.peel_to_commit()
.context(format!("failed to peel branch {} to commit", target.branch))?;
if new_target_commit.id() == target.sha {
if new_target_commit.id() == target.sha.into() {
return Ok(());
}
@ -361,13 +364,10 @@ pub fn update_base_branch(
.tree()
.context("failed to get new target commit tree")?;
let old_target_tree = repo
.find_commit(target.sha)
.and_then(|commit| commit.tree())
.context(format!(
"failed to get old target commit tree {}",
target.sha
))?;
let old_target_tree = repo.find_commit(target.sha)?.tree().context(format!(
"failed to get old target commit tree {}",
target.sha
))?;
let vb_state = project_repository.project().virtual_branches();
let integration_commit = get_workspace_head(&vb_state, project_repository)?;
@ -396,7 +396,7 @@ pub fn update_base_branch(
// branch head tree is the same as the new target tree.
// meaning we can safely use the new target commit as the branch head.
branch.head = new_target_commit.id();
branch.head = new_target_commit.id().into();
// it also means that the branch is fully integrated into the target.
// disconnect it from the upstream
@ -445,7 +445,7 @@ pub fn update_base_branch(
if branch.head == target.sha {
// there are no commits on the branch, so we can just update the head to the new target and calculate the new tree
branch.head = new_target_commit.id();
branch.head = new_target_commit.id().into();
branch.tree = branch_merge_index_tree_oid;
vb_state.set_branch(branch.clone())?;
return Ok(Some(branch));
@ -513,8 +513,8 @@ pub fn update_base_branch(
// branch was not pushed to upstream yet. attempt a rebase,
let rebased_head_oid = cherry_rebase(
project_repository,
new_target_commit.id(),
new_target_commit.id(),
new_target_commit.id().into(),
new_target_commit.id().into(),
branch.head,
);
@ -546,9 +546,11 @@ pub fn update_base_branch(
.iter()
.filter(|branch| branch.applied)
.fold(new_target_commit.tree(), |final_tree, branch| {
let repo: &git2::Repository = repo.into();
let final_tree = final_tree?;
let branch_tree = repo.find_tree(branch.tree)?;
let mut merge_result = repo.merge_trees(&new_target_tree, &final_tree, &branch_tree)?;
let branch_tree = repo.find_tree(branch.tree.into())?;
let mut merge_result: Index =
repo.merge_trees(&new_target_tree, &final_tree, &branch_tree, None)?;
let final_tree_oid = merge_result.write_tree_to(repo)?;
repo.find_tree(final_tree_oid)
})
@ -561,7 +563,7 @@ pub fn update_base_branch(
// write new target oid
vb_state.set_default_target(target::Target {
sha: new_target_commit.id(),
sha: new_target_commit.id().into(),
..target
})?;
@ -581,7 +583,7 @@ pub fn target_to_base_branch(
// gather a list of commits between oid and target.sha
let upstream_commits = project_repository
.log(oid, project_repository::LogUntil::Commit(target.sha))
.log(oid.into(), project_repository::LogUntil::Commit(target.sha))
.context("failed to get upstream commits")?
.iter()
.map(super::commit_to_remote_commit)
@ -617,7 +619,7 @@ pub fn target_to_base_branch(
push_remote_name: target.push_remote_name.clone(),
push_remote_url,
base_sha: target.sha,
current_sha: oid,
current_sha: oid.into(),
behind: upstream_commits.len(),
upstream_commits,
recent_commits,

View File

@ -6,7 +6,7 @@ use lazy_static::lazy_static;
use super::{errors::VerifyError, VirtualBranchesHandle};
use crate::{
git::{self},
git::{self, CommitExt},
project_repository::{self, LogUntil},
virtual_branches::branch::BranchCreateRequest,
};
@ -299,7 +299,10 @@ fn verify_head_is_clean(
.context("failed to get default target")?;
let mut extra_commits = project_repository
.log(head_commit.id(), LogUntil::Commit(default_target.sha))
.log(
head_commit.id().into(),
LogUntil::Commit(default_target.sha),
)
.context("failed to get log")?;
let integration_commit = extra_commits.pop();
@ -328,7 +331,7 @@ fn verify_head_is_clean(
&BranchCreateRequest {
name: extra_commits
.last()
.map(|commit| commit.message().to_string()),
.map(|commit| commit.message_bstr().to_string()),
..Default::default()
},
)
@ -348,9 +351,9 @@ fn verify_head_is_clean(
.git_repository
.commit(
None,
&commit.author(),
&commit.committer(),
&commit.message().to_str_lossy(),
&commit.author().into(),
&commit.committer().into(),
&commit.message_bstr().to_str_lossy(),
&commit.tree().unwrap(),
&[&new_branch_head],
None,
@ -368,13 +371,13 @@ fn verify_head_is_clean(
rebased_commit_oid
))?;
new_branch.head = rebased_commit.id();
new_branch.tree = rebased_commit.tree_id();
new_branch.head = rebased_commit.id().into();
new_branch.tree = rebased_commit.tree_id().into();
vb_state
.set_branch(new_branch.clone())
.context("failed to write branch")?;
head = rebased_commit.id();
head = rebased_commit.id().into();
}
Ok(())
}

View File

@ -6,7 +6,7 @@ use serde::Serialize;
use super::{errors, target, Author, VirtualBranchesHandle};
use crate::{
git,
git::{self, CommitExt},
project_repository::{self, LogUntil},
};
@ -188,12 +188,13 @@ pub fn branch_to_remote_branch_data(
.transpose()
}
pub fn commit_to_remote_commit(commit: &git::Commit) -> RemoteCommit {
pub fn commit_to_remote_commit(commit: &git2::Commit) -> RemoteCommit {
let signature: git::Signature = commit.author().into();
RemoteCommit {
id: commit.id().to_string(),
description: commit.message().to_owned(),
description: commit.message_bstr().to_owned(),
created_at: commit.time().seconds().try_into().unwrap(),
author: commit.author().into(),
author: signature.into(),
change_id: commit.change_id(),
}
}

View File

@ -26,7 +26,7 @@ use super::{
};
use crate::error::{self, AnyhowContextExt, Code};
use crate::git::diff::{diff_files_into_hunks, trees, FileDiff};
use crate::git::RepositoryExt;
use crate::git::{CommitExt, RepositoryExt, Signature};
use crate::time::now_since_unix_epoch_ms;
use crate::virtual_branches::branch::HunkHash;
use crate::{
@ -34,7 +34,7 @@ use crate::{
git::{
self,
diff::{self},
Commit, Refname, RemoteRefname,
Refname, RemoteRefname,
},
project_repository::{self, conflicts, LogUntil},
reader, users,
@ -282,7 +282,7 @@ pub fn apply_branch(
if merge_index.has_conflicts() {
// currently we can only deal with the merge problem branch
for mut branch in
super::get_status_by_branch(project_repository, Some(&target_commit.id()))?
super::get_status_by_branch(project_repository, Some(&target_commit.id().into()))?
.0
.into_iter()
.map(|(branch, _)| branch)
@ -368,7 +368,7 @@ pub fn apply_branch(
let mut rebase = repo
.rebase(
Some(branch.head),
Some(target_commit.id()),
Some(target_commit.id().into()),
None,
Some(&mut rebase_options),
)
@ -428,7 +428,7 @@ pub fn apply_branch(
}
}
branch.tree = repo.find_commit(branch.head)?.tree()?.id().into();
branch.tree = repo.find_commit(branch.head)?.tree_gb()?.id().into();
vb_state.set_branch(branch.clone())?;
}
@ -738,12 +738,12 @@ pub fn unapply_branch(
fn find_base_tree<'a>(
repo: &'a git::Repository,
branch_commit: &'a git::Commit<'a>,
target_commit: &'a git::Commit<'a>,
branch_commit: &'a git2::Commit<'a>,
target_commit: &'a git2::Commit<'a>,
) -> Result<git2::Tree<'a>> {
// find merge base between target_commit and branch_commit
let merge_base = repo
.merge_base(target_commit.id(), branch_commit.id())
.merge_base(target_commit.id().into(), branch_commit.id().into())
.context("failed to find merge base")?;
// turn oid into a commit
let merge_base_commit = repo
@ -773,7 +773,7 @@ pub fn list_virtual_branches(
.unwrap();
let (statuses, skipped_files) =
get_status_by_branch(project_repository, Some(&integration_commit.id()))?;
get_status_by_branch(project_repository, Some(&integration_commit.id().into()))?;
let max_selected_for_changes = statuses
.iter()
.filter_map(|(branch, _)| branch.selected_for_changes)
@ -811,14 +811,14 @@ pub fn list_virtual_branches(
// find upstream commits if we found an upstream reference
let mut pushed_commits = HashMap::new();
if let Some(upstream) = &upstram_branch_commit {
let merge_base =
repo.merge_base(upstream.id(), default_target.sha)
.context(format!(
"failed to find merge base between {} and {}",
upstream.id(),
default_target.sha
))?;
for oid in project_repository.l(upstream.id(), LogUntil::Commit(merge_base))? {
let merge_base = repo
.merge_base(upstream.id().into(), default_target.sha)
.context(format!(
"failed to find merge base between {} and {}",
upstream.id(),
default_target.sha
))?;
for oid in project_repository.l(upstream.id().into(), LogUntil::Commit(merge_base))? {
pushed_commits.insert(oid, true);
}
}
@ -835,7 +835,7 @@ pub fn list_virtual_branches(
is_remote = if is_remote {
is_remote
} else {
pushed_commits.contains_key(&commit.id())
pushed_commits.contains_key(&commit.id().into())
};
// only check for integration if we haven't already found an integration
@ -966,14 +966,14 @@ fn is_requires_force(
let merge_base = project_repository
.git_repository
.merge_base(upstream_commit.id(), branch.head)?;
.merge_base(upstream_commit.id().into(), branch.head)?;
Ok(merge_base != upstream_commit.id())
Ok(merge_base != upstream_commit.id().into())
}
fn list_virtual_commit_files(
project_repository: &project_repository::Repository,
commit: &git::Commit,
commit: &git2::Commit,
) -> Result<Vec<VirtualBranchFile>> {
if commit.parent_count() == 0 {
return Ok(vec![]);
@ -996,21 +996,28 @@ fn list_virtual_commit_files(
fn commit_to_vbranch_commit(
repository: &project_repository::Repository,
branch: &branch::Branch,
commit: &git::Commit,
commit: &git2::Commit,
is_integrated: bool,
is_remote: bool,
) -> Result<VirtualBranchCommit> {
let timestamp = u128::try_from(commit.time().seconds())?;
let signature = commit.author();
let message = commit.message().to_owned();
let signature: Signature = commit.author().into();
let message = commit.message_bstr().to_owned();
let files =
list_virtual_commit_files(repository, commit).context("failed to list commit files")?;
let parent_ids = commit.parents()?.iter().map(Commit::id).collect::<Vec<_>>();
let parent_ids: Vec<git::Oid> = commit
.parents_gb()?
.iter()
.map(|c| {
let c: git::Oid = c.id().into();
c
})
.collect::<Vec<_>>();
let commit = VirtualBranchCommit {
id: commit.id(),
id: commit.id().into(),
created_at: timestamp * 1000,
author: Author::from(signature),
description: message,
@ -1175,12 +1182,12 @@ pub fn integrate_upstream_commits(
let upstream_oid = repo.refname_to_id(&upstream_branch.to_string())?;
let upstream_commit = repo.find_commit(upstream_oid)?;
if upstream_commit.id() == branch.head {
if upstream_commit.id() == branch.head.into() {
return Ok(());
}
let upstream_commits =
project_repository.list_commits(upstream_commit.id(), default_target.sha)?;
project_repository.list_commits(upstream_commit.id().into(), default_target.sha)?;
let branch_commits = project_repository.list_commits(branch.head, default_target.sha)?;
let branch_commit_ids = branch_commits.iter().map(|c| c.id()).collect::<Vec<_>>();
@ -1190,14 +1197,14 @@ pub fn integrate_upstream_commits(
.filter_map(|c| c.change_id())
.collect::<Vec<_>>();
let mut unknown_commits = upstream_commits
let mut unknown_commits: Vec<git::Oid> = upstream_commits
.iter()
.filter(|c| {
(!c.change_id()
.is_some_and(|cid| branch_change_ids.contains(&cid)))
&& !branch_commit_ids.contains(&c.id())
})
.map(|c| c.id())
.map(|c| c.id().into())
.collect::<Vec<_>>();
let rebased_commits = upstream_commits
@ -1304,14 +1311,16 @@ pub fn integrate_with_merge(
project_repository: &project_repository::Repository,
user: Option<&users::User>,
branch: &mut Branch,
upstream_commit: &git::Commit,
upstream_commit: &git2::Commit,
merge_base: git::Oid,
) -> Result<git::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")?;
let upstream_branch = branch.upstream.as_ref().context("upstream not found")?;
let merge_tree = repo.find_commit(merge_base).and_then(|c| c.tree())?;
// let merge_tree = repo.find_commit(merge_base).and_then(|c| c.tree())?;
let merge_tree = repo.find_commit(merge_base)?;
let merge_tree = merge_tree.tree()?;
let mut merge_index = repo.merge_trees(&merge_tree, &wd_tree, &remote_tree)?;
@ -1325,7 +1334,7 @@ pub fn integrate_with_merge(
conflicts::mark(
project_repository,
merge_conflicts,
Some(upstream_commit.id()),
Some(upstream_commit.id().into()),
)?;
repo.checkout_index(&mut merge_index)
.allow_conflicts()
@ -1762,7 +1771,7 @@ fn get_applied_status(
let commit_id = git::Oid::from(blame_hunk.orig_commit_id());
if commit_id != *target_sha && commit_id != *integration_commit {
let hash = Hunk::hash_diff(&hunk.diff_lines);
let Some(branch_id) = commit_to_branch.get(&commit_id) else {
let Some(branch_id) = commit_to_branch.get(&commit_id.into()) else {
// This is a truly absurd situation
// TODO: Test if this still happens
tracing::error!(
@ -2032,8 +2041,8 @@ pub fn reset_branch(
let repo = &project_repository.git_repository;
let diff = trees(
repo,
&repo.find_commit(updated_head)?.tree()?,
&repo.find_commit(old_head)?.tree()?,
&repo.find_commit(updated_head)?.tree_gb()?,
&repo.find_commit(old_head)?.tree_gb()?,
)?;
// Assign the new hunks to the branch we're working on.
@ -2474,18 +2483,18 @@ pub fn push(
fn is_commit_integrated(
project_repository: &project_repository::Repository,
target: &target::Target,
commit: &git::Commit,
commit: &git2::Commit,
) -> Result<bool> {
let remote_branch = project_repository
.git_repository
.find_branch(&target.branch.clone().into())?;
let remote_head = remote_branch.peel_to_commit()?;
let upstream_commits = project_repository.l(
remote_head.id(),
remote_head.id().into(),
project_repository::LogUntil::Commit(target.sha),
)?;
if target.sha.eq(&commit.id()) {
if target.sha.eq(&commit.id().into()) {
// could not be integrated if heads are the same.
return Ok(false);
}
@ -2495,14 +2504,14 @@ fn is_commit_integrated(
return Ok(false);
}
if upstream_commits.contains(&commit.id()) {
if upstream_commits.contains(&commit.id().into()) {
return Ok(true);
}
let merge_base_id = project_repository
.git_repository
.merge_base(target.sha, commit.id())?;
if merge_base_id.eq(&commit.id()) {
.merge_base(target.sha, commit.id().into())?;
if merge_base_id.eq(&commit.id().into()) {
// if merge branch is the same as branch head and there are upstream commits
// then it's integrated
return Ok(true);
@ -2514,7 +2523,7 @@ fn is_commit_integrated(
let merge_base_tree = merge_base.tree()?;
let upstream = project_repository
.git_repository
.find_commit(remote_head.id())?;
.find_commit(remote_head.id().into())?;
let upstream_tree = upstream.tree()?;
if merge_base_tree.id() == upstream_tree.id() {
@ -2685,7 +2694,7 @@ pub fn move_commit_file(
// find all the commits upstream from the target "to" commit
let mut upstream_commits = project_repository.l(
target_branch.head,
project_repository::LogUntil::Commit(amend_commit.id()),
project_repository::LogUntil::Commit(amend_commit.id().into()),
)?;
// get a list of all the diffs across all the virtual branches
@ -2787,7 +2796,7 @@ pub fn move_commit_file(
// write our new tree and commit for the new "from" commit without the moved changes
let new_from_tree_oid =
write_tree_onto_commit(project_repository, from_parent.id(), &diffs_to_keep)?;
write_tree_onto_commit(project_repository, from_parent.id().into(), &diffs_to_keep)?;
let new_from_tree = &repo
.find_tree(new_from_tree_oid)
.map_err(|_error| errors::VirtualBranchError::GitObjectNotFound(new_from_tree_oid))?;
@ -2795,9 +2804,9 @@ pub fn move_commit_file(
let new_from_commit_oid = repo
.commit(
None,
&from_commit.author(),
&from_commit.committer(),
&from_commit.message().to_str_lossy(),
&from_commit.author().into(),
&from_commit.committer().into(),
&from_commit.message_bstr().to_str_lossy(),
new_from_tree,
&[&from_parent],
change_id.as_deref(),
@ -2852,7 +2861,7 @@ pub fn move_commit_file(
// reset the concept of what the upstream commits are to be the rebased ones
upstream_commits = project_repository.l(
new_head,
project_repository::LogUntil::Commit(amend_commit.id()),
project_repository::LogUntil::Commit(amend_commit.id().into()),
)?;
}
@ -2869,16 +2878,16 @@ pub fn move_commit_file(
.find_tree(new_tree_oid)
.context("failed to find new tree")?;
let parents = amend_commit
.parents()
.parents_gb()
.context("failed to find head commit parents")?;
let change_id = amend_commit.change_id();
let commit_oid = project_repository
.git_repository
.commit(
None,
&amend_commit.author(),
&amend_commit.committer(),
&amend_commit.message().to_str_lossy(),
&amend_commit.author().into(),
&amend_commit.committer().into(),
&amend_commit.message_bstr().to_str_lossy(),
&new_tree,
&parents.iter().collect::<Vec<_>>(),
change_id.as_deref(),
@ -2900,7 +2909,7 @@ pub fn move_commit_file(
let new_head = cherry_rebase(
project_repository,
commit_oid,
amend_commit.id(),
amend_commit.id().into(),
last_commit,
)?;
@ -3049,16 +3058,16 @@ pub fn amend(
.context("failed to find new tree")?;
let parents = amend_commit
.parents()
.parents_gb()
.context("failed to find head commit parents")?;
let commit_oid = project_repository
.git_repository
.commit(
None,
&amend_commit.author(),
&amend_commit.committer(),
&amend_commit.message().to_str_lossy(),
&amend_commit.author().into(),
&amend_commit.committer().into(),
&amend_commit.message_bstr().to_str_lossy(),
&new_tree,
&parents.iter().collect::<Vec<_>>(),
None,
@ -3068,7 +3077,7 @@ pub fn amend(
// now rebase upstream commits, if needed
let upstream_commits = project_repository.l(
target_branch.head,
project_repository::LogUntil::Commit(amend_commit.id()),
project_repository::LogUntil::Commit(amend_commit.id().into()),
)?;
// if there are no upstream commits, we're done
if upstream_commits.is_empty() {
@ -3083,7 +3092,7 @@ pub fn amend(
let new_head = cherry_rebase(
project_repository,
commit_oid,
amend_commit.id(),
amend_commit.id().into(),
last_commit,
)?;
@ -3141,13 +3150,13 @@ pub fn reorder_commit(
// get a list of the commits to rebase
let mut ids_to_rebase = project_repository.l(
branch.head,
project_repository::LogUntil::Commit(commit.id()),
project_repository::LogUntil::Commit(commit.id().into()),
)?;
let last_oid = ids_to_rebase.pop().context("failed to pop last oid")?;
ids_to_rebase.push(commit_oid);
ids_to_rebase.push(last_oid);
match cherry_rebase_group(project_repository, parent_oid, &mut ids_to_rebase) {
match cherry_rebase_group(project_repository, parent_oid.into(), &mut ids_to_rebase) {
Ok(new_head) => {
branch.head = new_head;
vb_state
@ -3163,7 +3172,7 @@ pub fn reorder_commit(
}
} else {
// move commit down
if default_target.sha == parent_oid {
if default_target.sha == parent_oid.into() {
// can't move the commit down past the target
return Ok(());
}
@ -3174,12 +3183,12 @@ pub fn reorder_commit(
// get a list of the commits to rebase
let mut ids_to_rebase = project_repository.l(
branch.head,
project_repository::LogUntil::Commit(commit.id()),
project_repository::LogUntil::Commit(commit.id().into()),
)?;
ids_to_rebase.push(parent_oid);
ids_to_rebase.push(parent_oid.into());
ids_to_rebase.push(commit_oid);
match cherry_rebase_group(project_repository, target_oid, &mut ids_to_rebase) {
match cherry_rebase_group(project_repository, target_oid.into(), &mut ids_to_rebase) {
Ok(new_head) => {
branch.head = new_head;
vb_state
@ -3234,7 +3243,7 @@ pub fn insert_blank_commit(
let commit_tree = commit.tree().unwrap();
let blank_commit_oid = project_repository.commit(user, "", &commit_tree, &[&commit], None)?;
if commit.id() == branch.head && offset < 0 {
if commit.id() == branch.head.into() && offset < 0 {
// inserting before the first commit
branch.head = blank_commit_oid;
vb_state
@ -3247,7 +3256,7 @@ pub fn insert_blank_commit(
match cherry_rebase(
project_repository,
blank_commit_oid,
commit.id(),
commit.id().into(),
branch.head,
) {
Ok(Some(new_head)) => {
@ -3304,12 +3313,12 @@ pub fn undo_commit(
match cherry_rebase(
project_repository,
parent_commit_oid,
parent_commit_oid.into(),
commit_oid,
branch.head,
) {
Ok(Some(new_head)) => {
new_commit_oid = new_head;
new_commit_oid = new_head.into();
}
_ => {
return Err(errors::VirtualBranchError::RebaseFailed);
@ -3317,8 +3326,8 @@ pub fn undo_commit(
}
}
if new_commit_oid != commit_oid {
branch.head = new_commit_oid;
if new_commit_oid != commit_oid.into() {
branch.head = new_commit_oid.into();
vb_state
.set_branch(branch.clone())
.context("failed to write branch")?;
@ -3406,9 +3415,9 @@ fn cherry_rebase_group(
.git_repository
.commit(
None,
&to_rebase.author(),
&to_rebase.committer(),
&to_rebase.message().to_str_lossy(),
&to_rebase.author().into(),
&to_rebase.committer().into(),
&to_rebase.message_bstr().to_str_lossy(),
&merge_tree,
&[&head],
change_id.as_deref(),
@ -3423,7 +3432,7 @@ fn cherry_rebase_group(
)?
.id();
Ok(new_head_id)
Ok(new_head_id.into())
}
pub fn cherry_pick(
@ -3575,9 +3584,9 @@ pub fn cherry_pick(
.git_repository
.commit(
None,
&target_commit.author(),
&target_commit.committer(),
&target_commit.message().to_str_lossy(),
&target_commit.author().into(),
&target_commit.committer().into(),
&target_commit.message_bstr().to_str_lossy(),
&merge_tree,
&[&branch_head_commit],
change_id.as_deref(),
@ -3664,7 +3673,7 @@ pub fn squash(
},
)?;
if pushed_commit_oids.contains(&parent_commit.id())
if pushed_commit_oids.contains(&parent_commit.id().into())
&& !project_repository.project().ok_with_force_push
{
// squashing into a pushed commit will cause a force push that is not allowed
@ -3675,7 +3684,7 @@ pub fn squash(
));
}
if !branch_commit_oids.contains(&parent_commit.id()) {
if !branch_commit_oids.contains(&parent_commit.id().into()) {
return Err(errors::SquashError::CantSquashRootCommit);
}
@ -3684,7 +3693,7 @@ pub fn squash(
// * has the message combined of the target commit and parent commit
// * has parents of the parents commit.
let parents = parent_commit
.parents()
.parents_gb()
.context("failed to find head commit parents")?;
// use the squash commit's change id
@ -3694,12 +3703,12 @@ pub fn squash(
.git_repository
.commit(
None,
&commit_to_squash.author(),
&commit_to_squash.committer(),
&commit_to_squash.author().into(),
&commit_to_squash.committer().into(),
&format!(
"{}\n{}",
parent_commit.message(),
commit_to_squash.message(),
parent_commit.message_bstr(),
commit_to_squash.message_bstr(),
),
&commit_to_squash.tree().context("failed to find tree")?,
&parents.iter().collect::<Vec<_>>(),
@ -3801,7 +3810,7 @@ pub fn update_commit_message(
.context("failed to find commit")?;
let parents = target_commit
.parents()
.parents_gb()
.context("failed to find head commit parents")?;
let change_id = target_commit.change_id();
@ -3810,8 +3819,8 @@ pub fn update_commit_message(
.git_repository
.commit(
None,
&target_commit.author(),
&target_commit.committer(),
&target_commit.author().into(),
&target_commit.committer().into(),
message,
&target_commit.tree().context("failed to find tree")?,
&parents.iter().collect::<Vec<_>>(),
@ -3955,7 +3964,7 @@ pub fn move_commit(
// reset the source branch to the parent commit
{
source_branch.head = source_branch_head_parent.id();
source_branch.head = source_branch_head_parent.id().into();
vb_state.set_branch(source_branch.clone())?;
}
@ -3993,7 +4002,7 @@ pub fn move_commit(
let new_destination_head_oid = project_repository
.commit(
user,
&source_branch_head.message().to_str_lossy(),
&source_branch_head.message_bstr().to_str_lossy(),
&new_destination_tree,
&[&project_repository
.git_repository
@ -4092,7 +4101,7 @@ pub fn create_virtual_branch_from_branch(
.find_commit(default_target.sha)
.map_err(|error| errors::CreateVirtualBranchFromBranchError::Other(error.into()))?;
let merge_base_oid = repo
.merge_base(target_commit.id(), head_commit.id())
.merge_base(target_commit.id().into(), head_commit.id().into())
.map_err(|error| errors::CreateVirtualBranchFromBranchError::Other(error.into()))?;
let merge_base_tree = repo
.find_commit(merge_base_oid)
@ -4131,10 +4140,10 @@ pub fn create_virtual_branch_from_branch(
name: branch_name.clone(),
notes: String::new(),
applied: false,
upstream_head: upstream_branch.is_some().then_some(head_commit.id()),
upstream_head: upstream_branch.is_some().then_some(head_commit.id().into()),
upstream: upstream_branch,
tree: head_commit_tree.id().into(),
head: head_commit.id(),
head: head_commit.id().into(),
created_timestamp_ms: now,
updated_timestamp_ms: now,
ownership,

View File

@ -1,3 +1,5 @@
use git::CommitExt;
use super::*;
#[tokio::test]
@ -54,9 +56,9 @@ async fn move_file_down() {
// shas changed but change_id is the same
assert_eq!(&commit1.change_id(), &branch.commits[1].change_id);
assert_ne!(&commit1.id(), &branch.commits[1].id);
assert_ne!(&commit1.id(), &branch.commits[1].id.into());
assert_eq!(&commit2.change_id(), &branch.commits[0].change_id);
assert_ne!(&commit2.id(), &branch.commits[0].id);
assert_ne!(&commit2.id(), &branch.commits[0].id.into());
assert_eq!(branch.commits[0].files.len(), 1);
assert_eq!(branch.commits.len(), 2);

View File

@ -1,3 +1,5 @@
use git::CommitExt;
use super::*;
#[tokio::test]

View File

@ -15,7 +15,7 @@ use std::{
use anyhow::{Context, Result};
use git2::TreeEntry;
use gitbutler_core::{
git::{self},
git::{self, CommitExt},
virtual_branches::{
self, apply_branch,
branch::{BranchCreateRequest, BranchOwnershipClaims},

View File

@ -1,6 +1,6 @@
use std::path;
use gitbutler_core::git;
use gitbutler_core::git::{self, CommitExt};
use tempfile::TempDir;
use crate::{init_opts, VAR_NO_CLEANUP};
@ -155,8 +155,8 @@ impl TestProject {
let mut rebase = self
.remote_repository
.rebase(
Some(branch_commit.id()),
Some(master_branch_commit.id()),
Some(branch_commit.id().into()),
Some(master_branch_commit.id().into()),
None,
Some(&mut rebase_options),
)
@ -172,8 +172,8 @@ impl TestProject {
break;
}
if let Ok(commit_id) = rebase.commit(None, &commit.committer().into(), None) {
last_rebase_head = commit_id.into();
if let Ok(commit_id) = rebase.commit(None, &commit.committer(), None) {
last_rebase_head = commit_id;
} else {
rebase_success = false;
break;
@ -184,7 +184,7 @@ impl TestProject {
self.remote_repository
.reference(
&"refs/heads/master".parse().unwrap(),
last_rebase_head,
last_rebase_head.into(),
true,
&format!("rebase: {}", branch_name),
)
@ -215,7 +215,7 @@ impl TestProject {
let merge_base = {
let oid = self
.remote_repository
.merge_base(branch_commit.id(), master_branch_commit.id())
.merge_base(branch_commit.id().into(), master_branch_commit.id().into())
.unwrap();
self.remote_repository.find_commit(oid).unwrap()
};
@ -235,8 +235,8 @@ impl TestProject {
self.remote_repository
.commit(
Some(&"refs/heads/master".parse().unwrap()),
&branch_commit.author(),
&branch_commit.committer(),
&branch_commit.author().into(),
&branch_commit.committer().into(),
&format!("Merge pull request from {}", branch_name),
&merge_tree,
&[&master_branch_commit, &branch_commit],
@ -245,7 +245,7 @@ impl TestProject {
.unwrap();
}
pub fn find_commit(&self, oid: git::Oid) -> Result<git::Commit<'_>, git::Error> {
pub fn find_commit(&self, oid: git::Oid) -> Result<git2::Commit<'_>, git::Error> {
self.local_repository.find_commit(oid)
}
@ -263,19 +263,19 @@ impl TestProject {
pub fn checkout(&self, branch: &git::LocalRefname) {
let branch: git::Refname = branch.into();
let head_commit = self
.local_repository
.head()
.unwrap()
.peel_to_commit()
.unwrap();
let tree = match self.local_repository.find_branch(&branch) {
Ok(branch) => branch.peel_to_tree(),
Err(git::Error::NotFound(_)) => {
let head_commit = self
.local_repository
.head()
.unwrap()
.peel_to_commit()
.unwrap();
self.local_repository
.reference(&branch, head_commit.id(), false, "new branch")
.reference(&branch, head_commit.id().into(), false, "new branch")
.unwrap();
head_commit.tree()
head_commit.tree_gb()
}
Err(error) => Err(error),
}