Merge pull request #4523 from gitbutlerapp/Boosting-my-contribution-score

Boosting my contribution score
This commit is contained in:
Caleb Owens 2024-07-29 11:18:58 +02:00 committed by GitHub
commit d37dcefdf5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
29 changed files with 905 additions and 1213 deletions

View File

@ -1,6 +1,6 @@
use anyhow::Result; use anyhow::Result;
use gitbutler_branch::{BranchCreateRequest, BranchId, BranchOwnershipClaims, BranchUpdateRequest}; use gitbutler_branch::{BranchCreateRequest, BranchId, BranchOwnershipClaims, BranchUpdateRequest};
use gitbutler_command_context::ProjectRepository; use gitbutler_command_context::CommandContext;
use gitbutler_oplog::{ use gitbutler_oplog::{
entry::{OperationKind, SnapshotDetails}, entry::{OperationKind, SnapshotDetails},
OplogExt, SnapshotExt, OplogExt, SnapshotExt,
@ -34,21 +34,13 @@ impl VirtualBranchActions {
ownership: Option<&BranchOwnershipClaims>, ownership: Option<&BranchOwnershipClaims>,
run_hooks: bool, run_hooks: bool,
) -> Result<git2::Oid> { ) -> Result<git2::Oid> {
let project_repository = open_with_verify(project)?; let ctx = open_with_verify(project)?;
let mut guard = project.exclusive_worktree_access(); let mut guard = project.exclusive_worktree_access();
let snapshot_tree = project_repository let snapshot_tree = ctx.project().prepare_snapshot(guard.read_permission());
.project() let result =
.prepare_snapshot(guard.read_permission()); branch::commit(&ctx, branch_id, message, ownership, run_hooks).map_err(Into::into);
let result = branch::commit(
&project_repository,
branch_id,
message,
ownership,
run_hooks,
)
.map_err(Into::into);
let _ = snapshot_tree.and_then(|snapshot_tree| { let _ = snapshot_tree.and_then(|snapshot_tree| {
project_repository.project().snapshot_commit_creation( ctx.project().snapshot_commit_creation(
snapshot_tree, snapshot_tree,
result.as_ref().err(), result.as_ref().err(),
message.to_owned(), message.to_owned(),
@ -64,8 +56,8 @@ impl VirtualBranchActions {
project: &Project, project: &Project,
branch_name: &RemoteRefname, branch_name: &RemoteRefname,
) -> Result<bool> { ) -> Result<bool> {
let project_repository = ProjectRepository::open(project)?; let ctx = CommandContext::open(project)?;
branch::is_remote_branch_mergeable(&project_repository, branch_name).map_err(Into::into) branch::is_remote_branch_mergeable(&ctx, branch_name).map_err(Into::into)
} }
pub fn list_virtual_branches( pub fn list_virtual_branches(
@ -84,9 +76,9 @@ impl VirtualBranchActions {
project: &Project, project: &Project,
create: &BranchCreateRequest, create: &BranchCreateRequest,
) -> Result<BranchId> { ) -> Result<BranchId> {
let project_repository = open_with_verify(project)?; let ctx = open_with_verify(project)?;
let mut guard = project.exclusive_worktree_access(); let mut guard = project.exclusive_worktree_access();
let branch_manager = project_repository.branch_manager(); let branch_manager = ctx.branch_manager();
let branch_id = branch_manager let branch_id = branch_manager
.create_virtual_branch(create, guard.write_permission())? .create_virtual_branch(create, guard.write_permission())?
.id; .id;
@ -95,8 +87,8 @@ impl VirtualBranchActions {
#[instrument(skip(project), err(Debug))] #[instrument(skip(project), err(Debug))]
pub fn get_base_branch_data(project: &Project) -> Result<BaseBranch> { pub fn get_base_branch_data(project: &Project) -> Result<BaseBranch> {
let project_repository = ProjectRepository::open(project)?; let ctx = CommandContext::open(project)?;
get_base_branch_data(&project_repository) get_base_branch_data(&ctx)
} }
pub fn list_remote_commit_files( pub fn list_remote_commit_files(
@ -104,9 +96,8 @@ impl VirtualBranchActions {
project: &Project, project: &Project,
commit_oid: git2::Oid, commit_oid: git2::Oid,
) -> Result<Vec<RemoteBranchFile>> { ) -> Result<Vec<RemoteBranchFile>> {
let project_repository = ProjectRepository::open(project)?; let ctx = CommandContext::open(project)?;
crate::file::list_remote_commit_files(project_repository.repo(), commit_oid) crate::file::list_remote_commit_files(ctx.repository(), commit_oid).map_err(Into::into)
.map_err(Into::into)
} }
pub fn set_base_branch( pub fn set_base_branch(
@ -114,38 +105,38 @@ impl VirtualBranchActions {
project: &Project, project: &Project,
target_branch: &RemoteRefname, target_branch: &RemoteRefname,
) -> Result<BaseBranch> { ) -> Result<BaseBranch> {
let project_repository = ProjectRepository::open(project)?; let ctx = CommandContext::open(project)?;
let mut guard = project.exclusive_worktree_access(); let mut guard = project.exclusive_worktree_access();
let _ = project_repository.project().create_snapshot( let _ = ctx.project().create_snapshot(
SnapshotDetails::new(OperationKind::SetBaseBranch), SnapshotDetails::new(OperationKind::SetBaseBranch),
guard.write_permission(), guard.write_permission(),
); );
set_base_branch(&project_repository, target_branch) set_base_branch(&ctx, target_branch)
} }
pub fn set_target_push_remote(&self, project: &Project, push_remote: &str) -> Result<()> { pub fn set_target_push_remote(&self, project: &Project, push_remote: &str) -> Result<()> {
let project_repository = ProjectRepository::open(project)?; let ctx = CommandContext::open(project)?;
set_target_push_remote(&project_repository, push_remote) set_target_push_remote(&ctx, push_remote)
} }
pub fn integrate_upstream_commits(&self, project: &Project, branch_id: BranchId) -> Result<()> { pub fn integrate_upstream_commits(&self, project: &Project, branch_id: BranchId) -> Result<()> {
let project_repository = open_with_verify(project)?; let ctx = open_with_verify(project)?;
let mut guard = project.exclusive_worktree_access(); let mut guard = project.exclusive_worktree_access();
let _ = project_repository.project().create_snapshot( let _ = ctx.project().create_snapshot(
SnapshotDetails::new(OperationKind::MergeUpstream), SnapshotDetails::new(OperationKind::MergeUpstream),
guard.write_permission(), guard.write_permission(),
); );
branch::integrate_upstream_commits(&project_repository, branch_id).map_err(Into::into) branch::integrate_upstream_commits(&ctx, branch_id).map_err(Into::into)
} }
pub fn update_base_branch(&self, project: &Project) -> Result<Vec<ReferenceName>> { pub fn update_base_branch(&self, project: &Project) -> Result<Vec<ReferenceName>> {
let project_repository = open_with_verify(project)?; let ctx = open_with_verify(project)?;
let mut guard = project.exclusive_worktree_access(); let mut guard = project.exclusive_worktree_access();
let _ = project_repository.project().create_snapshot( let _ = ctx.project().create_snapshot(
SnapshotDetails::new(OperationKind::UpdateWorkspaceBase), SnapshotDetails::new(OperationKind::UpdateWorkspaceBase),
guard.write_permission(), guard.write_permission(),
); );
update_base_branch(&project_repository, guard.write_permission()).map_err(Into::into) update_base_branch(&ctx, guard.write_permission()).map_err(Into::into)
} }
pub fn update_virtual_branch( pub fn update_virtual_branch(
@ -153,18 +144,16 @@ impl VirtualBranchActions {
project: &Project, project: &Project,
branch_update: BranchUpdateRequest, branch_update: BranchUpdateRequest,
) -> Result<()> { ) -> Result<()> {
let project_repository = open_with_verify(project)?; let ctx = open_with_verify(project)?;
let mut guard = project.exclusive_worktree_access(); let mut guard = project.exclusive_worktree_access();
let snapshot_tree = project_repository let snapshot_tree = ctx.project().prepare_snapshot(guard.read_permission());
.project() let old_branch = ctx
.prepare_snapshot(guard.read_permission());
let old_branch = project_repository
.project() .project()
.virtual_branches() .virtual_branches()
.get_branch_in_workspace(branch_update.id)?; .get_branch_in_workspace(branch_update.id)?;
let result = branch::update_branch(&project_repository, &branch_update); let result = branch::update_branch(&ctx, &branch_update);
let _ = snapshot_tree.and_then(|snapshot_tree| { let _ = snapshot_tree.and_then(|snapshot_tree| {
project_repository.project().snapshot_branch_update( ctx.project().snapshot_branch_update(
snapshot_tree, snapshot_tree,
&old_branch, &old_branch,
&branch_update, &branch_update,
@ -181,22 +170,22 @@ impl VirtualBranchActions {
project: &Project, project: &Project,
branch_updates: Vec<BranchUpdateRequest>, branch_updates: Vec<BranchUpdateRequest>,
) -> Result<()> { ) -> Result<()> {
let project_repository = open_with_verify(project)?; let ctx = open_with_verify(project)?;
for branch_update in branch_updates { for branch_update in branch_updates {
let branch = project_repository let branch = ctx
.project() .project()
.virtual_branches() .virtual_branches()
.get_branch_in_workspace(branch_update.id)?; .get_branch_in_workspace(branch_update.id)?;
if branch_update.order != Some(branch.order) { if branch_update.order != Some(branch.order) {
branch::update_branch(&project_repository, &branch_update)?; branch::update_branch(&ctx, &branch_update)?;
} }
} }
Ok(()) Ok(())
} }
pub fn delete_virtual_branch(&self, project: &Project, branch_id: BranchId) -> Result<()> { pub fn delete_virtual_branch(&self, project: &Project, branch_id: BranchId) -> Result<()> {
let project_repository = open_with_verify(project)?; let ctx = open_with_verify(project)?;
let branch_manager = project_repository.branch_manager(); let branch_manager = ctx.branch_manager();
let mut guard = project.exclusive_worktree_access(); let mut guard = project.exclusive_worktree_access();
branch_manager.delete_branch(branch_id, guard.write_permission()) branch_manager.delete_branch(branch_id, guard.write_permission())
} }
@ -206,24 +195,23 @@ impl VirtualBranchActions {
project: &Project, project: &Project,
ownership: &BranchOwnershipClaims, ownership: &BranchOwnershipClaims,
) -> Result<()> { ) -> Result<()> {
let project_repository = open_with_verify(project)?; let ctx = open_with_verify(project)?;
let mut guard = project.exclusive_worktree_access(); let mut guard = project.exclusive_worktree_access();
let _ = project_repository.project().create_snapshot( let _ = ctx.project().create_snapshot(
SnapshotDetails::new(OperationKind::DiscardHunk), SnapshotDetails::new(OperationKind::DiscardHunk),
guard.write_permission(), guard.write_permission(),
); );
branch::unapply_ownership(&project_repository, ownership, guard.write_permission()) branch::unapply_ownership(&ctx, ownership, guard.write_permission()).map_err(Into::into)
.map_err(Into::into)
} }
pub fn reset_files(&self, project: &Project, files: &Vec<String>) -> Result<()> { pub fn reset_files(&self, project: &Project, files: &Vec<String>) -> Result<()> {
let project_repository = open_with_verify(project)?; let ctx = open_with_verify(project)?;
let mut guard = project.exclusive_worktree_access(); let mut guard = project.exclusive_worktree_access();
let _ = project_repository.project().create_snapshot( let _ = ctx.project().create_snapshot(
SnapshotDetails::new(OperationKind::DiscardFile), SnapshotDetails::new(OperationKind::DiscardFile),
guard.write_permission(), guard.write_permission(),
); );
branch::reset_files(&project_repository, files).map_err(Into::into) branch::reset_files(&ctx, files).map_err(Into::into)
} }
pub fn amend( pub fn amend(
@ -233,13 +221,13 @@ impl VirtualBranchActions {
commit_oid: git2::Oid, commit_oid: git2::Oid,
ownership: &BranchOwnershipClaims, ownership: &BranchOwnershipClaims,
) -> Result<git2::Oid> { ) -> Result<git2::Oid> {
let project_repository = open_with_verify(project)?; let ctx = open_with_verify(project)?;
let mut guard = project.exclusive_worktree_access(); let mut guard = project.exclusive_worktree_access();
let _ = project_repository.project().create_snapshot( let _ = ctx.project().create_snapshot(
SnapshotDetails::new(OperationKind::AmendCommit), SnapshotDetails::new(OperationKind::AmendCommit),
guard.write_permission(), guard.write_permission(),
); );
branch::amend(&project_repository, branch_id, commit_oid, ownership) branch::amend(&ctx, branch_id, commit_oid, ownership)
} }
pub fn move_commit_file( pub fn move_commit_file(
@ -250,19 +238,13 @@ impl VirtualBranchActions {
to_commit_oid: git2::Oid, to_commit_oid: git2::Oid,
ownership: &BranchOwnershipClaims, ownership: &BranchOwnershipClaims,
) -> Result<git2::Oid> { ) -> Result<git2::Oid> {
let project_repository = open_with_verify(project)?; let ctx = open_with_verify(project)?;
let mut guard = project.exclusive_worktree_access(); let mut guard = project.exclusive_worktree_access();
let _ = project_repository.project().create_snapshot( let _ = ctx.project().create_snapshot(
SnapshotDetails::new(OperationKind::MoveCommitFile), SnapshotDetails::new(OperationKind::MoveCommitFile),
guard.write_permission(), guard.write_permission(),
); );
branch::move_commit_file( branch::move_commit_file(&ctx, branch_id, from_commit_oid, to_commit_oid, ownership)
&project_repository,
branch_id,
from_commit_oid,
to_commit_oid,
ownership,
)
.map_err(Into::into) .map_err(Into::into)
} }
@ -272,15 +254,13 @@ impl VirtualBranchActions {
branch_id: BranchId, branch_id: BranchId,
commit_oid: git2::Oid, commit_oid: git2::Oid,
) -> Result<()> { ) -> Result<()> {
let project_repository = open_with_verify(project)?; let ctx = open_with_verify(project)?;
let mut guard = project.exclusive_worktree_access(); let mut guard = project.exclusive_worktree_access();
let snapshot_tree = project_repository let snapshot_tree = ctx.project().prepare_snapshot(guard.read_permission());
.project()
.prepare_snapshot(guard.read_permission());
let result: Result<()> = let result: Result<()> =
branch::undo_commit(&project_repository, branch_id, commit_oid).map_err(Into::into); branch::undo_commit(&ctx, branch_id, commit_oid).map_err(Into::into);
let _ = snapshot_tree.and_then(|snapshot_tree| { let _ = snapshot_tree.and_then(|snapshot_tree| {
project_repository.project().snapshot_commit_undo( ctx.project().snapshot_commit_undo(
snapshot_tree, snapshot_tree,
result.as_ref(), result.as_ref(),
commit_oid, commit_oid,
@ -297,14 +277,13 @@ impl VirtualBranchActions {
commit_oid: git2::Oid, commit_oid: git2::Oid,
offset: i32, offset: i32,
) -> Result<()> { ) -> Result<()> {
let project_repository = open_with_verify(project)?; let ctx = open_with_verify(project)?;
let mut guard = project.exclusive_worktree_access(); let mut guard = project.exclusive_worktree_access();
let _ = project_repository.project().create_snapshot( let _ = ctx.project().create_snapshot(
SnapshotDetails::new(OperationKind::InsertBlankCommit), SnapshotDetails::new(OperationKind::InsertBlankCommit),
guard.write_permission(), guard.write_permission(),
); );
branch::insert_blank_commit(&project_repository, branch_id, commit_oid, offset) branch::insert_blank_commit(&ctx, branch_id, commit_oid, offset).map_err(Into::into)
.map_err(Into::into)
} }
pub fn reorder_commit( pub fn reorder_commit(
@ -314,14 +293,13 @@ impl VirtualBranchActions {
commit_oid: git2::Oid, commit_oid: git2::Oid,
offset: i32, offset: i32,
) -> Result<()> { ) -> Result<()> {
let project_repository = open_with_verify(project)?; let ctx = open_with_verify(project)?;
let mut guard = project.exclusive_worktree_access(); let mut guard = project.exclusive_worktree_access();
let _ = project_repository.project().create_snapshot( let _ = ctx.project().create_snapshot(
SnapshotDetails::new(OperationKind::ReorderCommit), SnapshotDetails::new(OperationKind::ReorderCommit),
guard.write_permission(), guard.write_permission(),
); );
branch::reorder_commit(&project_repository, branch_id, commit_oid, offset) branch::reorder_commit(&ctx, branch_id, commit_oid, offset).map_err(Into::into)
.map_err(Into::into)
} }
pub fn reset_virtual_branch( pub fn reset_virtual_branch(
@ -330,13 +308,13 @@ impl VirtualBranchActions {
branch_id: BranchId, branch_id: BranchId,
target_commit_oid: git2::Oid, target_commit_oid: git2::Oid,
) -> Result<()> { ) -> Result<()> {
let project_repository = open_with_verify(project)?; let ctx = open_with_verify(project)?;
let mut guard = project.exclusive_worktree_access(); let mut guard = project.exclusive_worktree_access();
let _ = project_repository.project().create_snapshot( let _ = ctx.project().create_snapshot(
SnapshotDetails::new(OperationKind::UndoCommit), SnapshotDetails::new(OperationKind::UndoCommit),
guard.write_permission(), guard.write_permission(),
); );
branch::reset_branch(&project_repository, branch_id, target_commit_oid).map_err(Into::into) branch::reset_branch(&ctx, branch_id, target_commit_oid).map_err(Into::into)
} }
pub fn convert_to_real_branch( pub fn convert_to_real_branch(
@ -344,16 +322,14 @@ impl VirtualBranchActions {
project: &Project, project: &Project,
branch_id: BranchId, branch_id: BranchId,
) -> Result<ReferenceName> { ) -> Result<ReferenceName> {
let project_repository = open_with_verify(project)?; let ctx = open_with_verify(project)?;
let mut guard = project.exclusive_worktree_access(); let mut guard = project.exclusive_worktree_access();
let snapshot_tree = project_repository let snapshot_tree = ctx.project().prepare_snapshot(guard.read_permission());
.project() let branch_manager = ctx.branch_manager();
.prepare_snapshot(guard.read_permission());
let branch_manager = project_repository.branch_manager();
let result = branch_manager.convert_to_real_branch(branch_id, guard.write_permission()); let result = branch_manager.convert_to_real_branch(branch_id, guard.write_permission());
let _ = snapshot_tree.and_then(|snapshot_tree| { let _ = snapshot_tree.and_then(|snapshot_tree| {
project_repository.project().snapshot_branch_unapplied( ctx.project().snapshot_branch_unapplied(
snapshot_tree, snapshot_tree,
result.as_ref(), result.as_ref(),
guard.write_permission(), guard.write_permission(),
@ -371,13 +347,13 @@ impl VirtualBranchActions {
askpass: Option<Option<BranchId>>, askpass: Option<Option<BranchId>>,
) -> Result<()> { ) -> Result<()> {
let helper = Helper::default(); let helper = Helper::default();
let project_repository = open_with_verify(project)?; let ctx = open_with_verify(project)?;
branch::push(&project_repository, branch_id, with_force, &helper, askpass) branch::push(&ctx, branch_id, with_force, &helper, askpass)
} }
pub fn list_remote_branches(project: Project) -> Result<Vec<RemoteBranch>> { pub fn list_remote_branches(project: Project) -> Result<Vec<RemoteBranch>> {
let project_repository = ProjectRepository::open(&project)?; let ctx = CommandContext::open(&project)?;
list_remote_branches(&project_repository) list_remote_branches(&ctx)
} }
pub fn get_remote_branch_data( pub fn get_remote_branch_data(
@ -385,8 +361,8 @@ impl VirtualBranchActions {
project: &Project, project: &Project,
refname: &Refname, refname: &Refname,
) -> Result<RemoteBranchData> { ) -> Result<RemoteBranchData> {
let project_repository = ProjectRepository::open(project)?; let ctx = CommandContext::open(project)?;
get_branch_data(&project_repository, refname) get_branch_data(&ctx, refname)
} }
pub fn squash( pub fn squash(
@ -395,13 +371,13 @@ impl VirtualBranchActions {
branch_id: BranchId, branch_id: BranchId,
commit_oid: git2::Oid, commit_oid: git2::Oid,
) -> Result<()> { ) -> Result<()> {
let project_repository = open_with_verify(project)?; let ctx = open_with_verify(project)?;
let mut guard = project.exclusive_worktree_access(); let mut guard = project.exclusive_worktree_access();
let _ = project_repository.project().create_snapshot( let _ = ctx.project().create_snapshot(
SnapshotDetails::new(OperationKind::SquashCommit), SnapshotDetails::new(OperationKind::SquashCommit),
guard.write_permission(), guard.write_permission(),
); );
branch::squash(&project_repository, branch_id, commit_oid).map_err(Into::into) branch::squash(&ctx, branch_id, commit_oid).map_err(Into::into)
} }
pub fn update_commit_message( pub fn update_commit_message(
@ -411,14 +387,13 @@ impl VirtualBranchActions {
commit_oid: git2::Oid, commit_oid: git2::Oid,
message: &str, message: &str,
) -> Result<()> { ) -> Result<()> {
let project_repository = open_with_verify(project)?; let ctx = open_with_verify(project)?;
let mut guard = project.exclusive_worktree_access(); let mut guard = project.exclusive_worktree_access();
let _ = project_repository.project().create_snapshot( let _ = ctx.project().create_snapshot(
SnapshotDetails::new(OperationKind::UpdateCommitMessage), SnapshotDetails::new(OperationKind::UpdateCommitMessage),
guard.write_permission(), guard.write_permission(),
); );
branch::update_commit_message(&project_repository, branch_id, commit_oid, message) branch::update_commit_message(&ctx, branch_id, commit_oid, message).map_err(Into::into)
.map_err(Into::into)
} }
pub fn fetch_from_remotes( pub fn fetch_from_remotes(
@ -426,15 +401,14 @@ impl VirtualBranchActions {
project: &Project, project: &Project,
askpass: Option<String>, askpass: Option<String>,
) -> Result<FetchResult> { ) -> Result<FetchResult> {
let project_repository = ProjectRepository::open(project)?; let ctx = CommandContext::open(project)?;
let helper = Helper::default(); let helper = Helper::default();
let remotes = project_repository.repo().remotes_as_string()?; let remotes = ctx.repository().remotes_as_string()?;
let fetch_errors: Vec<_> = remotes let fetch_errors: Vec<_> = remotes
.iter() .iter()
.filter_map(|remote| { .filter_map(|remote| {
project_repository ctx.fetch(remote, &helper, askpass.clone())
.fetch(remote, &helper, askpass.clone())
.err() .err()
.map(|err| err.to_string()) .map(|err| err.to_string())
}) })
@ -459,13 +433,13 @@ impl VirtualBranchActions {
target_branch_id: BranchId, target_branch_id: BranchId,
commit_oid: git2::Oid, commit_oid: git2::Oid,
) -> Result<()> { ) -> Result<()> {
let project_repository = open_with_verify(project)?; let ctx = open_with_verify(project)?;
let mut guard = project.exclusive_worktree_access(); let mut guard = project.exclusive_worktree_access();
let _ = project_repository.project().create_snapshot( let _ = ctx.project().create_snapshot(
SnapshotDetails::new(OperationKind::MoveCommit), SnapshotDetails::new(OperationKind::MoveCommit),
guard.write_permission(), guard.write_permission(),
); );
branch::move_commit(&project_repository, target_branch_id, commit_oid).map_err(Into::into) branch::move_commit(&ctx, target_branch_id, commit_oid).map_err(Into::into)
} }
pub fn create_virtual_branch_from_branch( pub fn create_virtual_branch_from_branch(
@ -474,8 +448,8 @@ impl VirtualBranchActions {
branch: &Refname, branch: &Refname,
remote: Option<RemoteRefname>, remote: Option<RemoteRefname>,
) -> Result<BranchId> { ) -> Result<BranchId> {
let project_repository = open_with_verify(project)?; let ctx = open_with_verify(project)?;
let branch_manager = project_repository.branch_manager(); let branch_manager = ctx.branch_manager();
let mut guard = project.exclusive_worktree_access(); let mut guard = project.exclusive_worktree_access();
branch_manager branch_manager
.create_virtual_branch_from_branch(branch, remote, guard.write_permission()) .create_virtual_branch_from_branch(branch, remote, guard.write_permission())
@ -483,9 +457,9 @@ impl VirtualBranchActions {
} }
} }
fn open_with_verify(project: &Project) -> Result<ProjectRepository> { fn open_with_verify(project: &Project) -> Result<CommandContext> {
let project_repository = ProjectRepository::open(project)?; let ctx = CommandContext::open(project)?;
let mut guard = project.exclusive_worktree_access(); let mut guard = project.exclusive_worktree_access();
crate::integration::verify_branch(&project_repository, guard.write_permission())?; crate::integration::verify_branch(&ctx, guard.write_permission())?;
Ok(project_repository) Ok(ctx)
} }

View File

@ -6,7 +6,7 @@ use gitbutler_branch::{
self, Branch, BranchId, BranchOwnershipClaims, Target, VirtualBranchesHandle, self, Branch, BranchId, BranchOwnershipClaims, Target, VirtualBranchesHandle,
GITBUTLER_INTEGRATION_REFERENCE, GITBUTLER_INTEGRATION_REFERENCE,
}; };
use gitbutler_command_context::ProjectRepository; use gitbutler_command_context::CommandContext;
use gitbutler_error::error::Marker; use gitbutler_error::error::Marker;
use gitbutler_project::{access::WorktreeWritePermission, FetchResult}; use gitbutler_project::{access::WorktreeWritePermission, FetchResult};
use gitbutler_reference::{ReferenceName, Refname, RemoteRefname}; use gitbutler_reference::{ReferenceName, Refname, RemoteRefname};
@ -41,18 +41,15 @@ pub struct BaseBranch {
pub last_fetched_ms: Option<u128>, pub last_fetched_ms: Option<u128>,
} }
pub(crate) fn get_base_branch_data(project_repository: &ProjectRepository) -> Result<BaseBranch> { pub(crate) fn get_base_branch_data(ctx: &CommandContext) -> Result<BaseBranch> {
let target = default_target(&project_repository.project().gb_dir())?; let target = default_target(&ctx.project().gb_dir())?;
let base = target_to_base_branch(project_repository, &target)?; let base = target_to_base_branch(ctx, &target)?;
Ok(base) Ok(base)
} }
fn go_back_to_integration( fn go_back_to_integration(ctx: &CommandContext, default_target: &Target) -> Result<BaseBranch> {
project_repository: &ProjectRepository, let statuses = ctx
default_target: &Target, .repository()
) -> Result<BaseBranch> {
let statuses = project_repository
.repo()
.statuses(Some( .statuses(Some(
git2::StatusOptions::new() git2::StatusOptions::new()
.show(git2::StatusShow::IndexAndWorkdir) .show(git2::StatusShow::IndexAndWorkdir)
@ -63,13 +60,13 @@ fn go_back_to_integration(
return Err(anyhow!("current HEAD is dirty")).context(Marker::ProjectConflict); return Err(anyhow!("current HEAD is dirty")).context(Marker::ProjectConflict);
} }
let vb_state = project_repository.project().virtual_branches(); let vb_state = ctx.project().virtual_branches();
let virtual_branches = vb_state let virtual_branches = vb_state
.list_branches_in_workspace() .list_branches_in_workspace()
.context("failed to read virtual branches")?; .context("failed to read virtual branches")?;
let target_commit = project_repository let target_commit = ctx
.repo() .repository()
.find_commit(default_target.sha) .find_commit(default_target.sha)
.context("failed to find target commit")?; .context("failed to find target commit")?;
@ -81,48 +78,47 @@ fn go_back_to_integration(
.context("failed to get base tree from commit")?; .context("failed to get base tree from commit")?;
for branch in &virtual_branches { for branch in &virtual_branches {
// merge this branches tree with our tree // merge this branches tree with our tree
let branch_head = project_repository let branch_head = ctx
.repo() .repository()
.find_commit(branch.head) .find_commit(branch.head)
.context("failed to find branch head")?; .context("failed to find branch head")?;
let branch_tree = branch_head let branch_tree = branch_head
.tree() .tree()
.context("failed to get branch head tree")?; .context("failed to get branch head tree")?;
let mut result = project_repository let mut result = ctx
.repo() .repository()
.merge_trees(&base_tree, &final_tree, &branch_tree, None) .merge_trees(&base_tree, &final_tree, &branch_tree, None)
.context("failed to merge")?; .context("failed to merge")?;
let final_tree_oid = result let final_tree_oid = result
.write_tree_to(project_repository.repo()) .write_tree_to(ctx.repository())
.context("failed to write tree")?; .context("failed to write tree")?;
final_tree = project_repository final_tree = ctx
.repo() .repository()
.find_tree(final_tree_oid) .find_tree(final_tree_oid)
.context("failed to find written tree")?; .context("failed to find written tree")?;
} }
project_repository ctx.repository()
.repo()
.checkout_tree_builder(&final_tree) .checkout_tree_builder(&final_tree)
.force() .force()
.checkout() .checkout()
.context("failed to checkout tree")?; .context("failed to checkout tree")?;
let base = target_to_base_branch(project_repository, default_target)?; let base = target_to_base_branch(ctx, default_target)?;
update_gitbutler_integration(&vb_state, project_repository)?; update_gitbutler_integration(&vb_state, ctx)?;
Ok(base) Ok(base)
} }
pub(crate) fn set_base_branch( pub(crate) fn set_base_branch(
project_repository: &ProjectRepository, ctx: &CommandContext,
target_branch_ref: &RemoteRefname, target_branch_ref: &RemoteRefname,
) -> Result<BaseBranch> { ) -> Result<BaseBranch> {
let repo = project_repository.repo(); let repo = ctx.repository();
// if target exists, and it is the same as the requested branch, we should go back // if target exists, and it is the same as the requested branch, we should go back
if let Ok(target) = default_target(&project_repository.project().gb_dir()) { if let Ok(target) = default_target(&ctx.project().gb_dir()) {
if target.branch.eq(target_branch_ref) { if target.branch.eq(target_branch_ref) {
return go_back_to_integration(project_repository, &target); return go_back_to_integration(ctx, &target);
} }
} }
@ -154,7 +150,7 @@ pub(crate) fn set_base_branch(
.peel_to_commit() .peel_to_commit()
.context("Failed to peel HEAD reference to commit")?; .context("Failed to peel HEAD reference to commit")?;
// calculate the commit as the merge-base between HEAD in project_repository and this target commit // calculate the commit as the merge-base between HEAD in ctx and this target commit
let target_commit_oid = repo let target_commit_oid = repo
.merge_base(current_head_commit.id(), target_branch_head.id()) .merge_base(current_head_commit.id(), target_branch_head.id())
.context(format!( .context(format!(
@ -170,7 +166,7 @@ pub(crate) fn set_base_branch(
push_remote_name: None, push_remote_name: None,
}; };
let vb_state = project_repository.project().virtual_branches(); let vb_state = ctx.project().virtual_branches();
vb_state.set_default_target(target.clone())?; vb_state.set_default_target(target.clone())?;
// TODO: make sure this is a real branch // TODO: make sure this is a real branch
@ -244,14 +240,14 @@ pub(crate) fn set_base_branch(
updated_timestamp_ms: now_ms, updated_timestamp_ms: now_ms,
head: current_head_commit.id(), head: current_head_commit.id(),
tree: gitbutler_diff::write::hunks_onto_commit( tree: gitbutler_diff::write::hunks_onto_commit(
project_repository, ctx,
current_head_commit.id(), current_head_commit.id(),
gitbutler_diff::diff_files_into_hunks(wd_diff), gitbutler_diff::diff_files_into_hunks(wd_diff),
)?, )?,
ownership, ownership,
order: 0, order: 0,
selected_for_changes: None, selected_for_changes: None,
allow_rebasing: project_repository.project().ok_with_force_push.into(), allow_rebasing: ctx.project().ok_with_force_push.into(),
applied: true, applied: true,
in_workspace: true, in_workspace: true,
not_in_workspace_wip_change_id: None, not_in_workspace_wip_change_id: None,
@ -261,38 +257,35 @@ pub(crate) fn set_base_branch(
} }
} }
set_exclude_decoration(project_repository)?; set_exclude_decoration(ctx)?;
update_gitbutler_integration(&vb_state, project_repository)?; update_gitbutler_integration(&vb_state, ctx)?;
let base = target_to_base_branch(project_repository, &target)?; let base = target_to_base_branch(ctx, &target)?;
Ok(base) Ok(base)
} }
pub(crate) fn set_target_push_remote( pub(crate) fn set_target_push_remote(ctx: &CommandContext, push_remote_name: &str) -> Result<()> {
project_repository: &ProjectRepository, let remote = ctx
push_remote_name: &str, .repository()
) -> Result<()> {
let remote = project_repository
.repo()
.find_remote(push_remote_name) .find_remote(push_remote_name)
.context(format!("failed to find remote {}", push_remote_name))?; .context(format!("failed to find remote {}", push_remote_name))?;
// if target exists, and it is the same as the requested branch, we should go back // if target exists, and it is the same as the requested branch, we should go back
let mut target = default_target(&project_repository.project().gb_dir())?; let mut target = default_target(&ctx.project().gb_dir())?;
target.push_remote_name = remote target.push_remote_name = remote
.name() .name()
.context("failed to get remote name")? .context("failed to get remote name")?
.to_string() .to_string()
.into(); .into();
let vb_state = project_repository.project().virtual_branches(); let vb_state = ctx.project().virtual_branches();
vb_state.set_default_target(target)?; vb_state.set_default_target(target)?;
Ok(()) Ok(())
} }
fn set_exclude_decoration(project_repository: &ProjectRepository) -> Result<()> { fn set_exclude_decoration(ctx: &CommandContext) -> Result<()> {
let repo = project_repository.repo(); let repo = ctx.repository();
let mut config = repo.config()?; let mut config = repo.config()?;
config config
.set_multivar("log.excludeDecoration", "refs/gitbutler", "refs/gitbutler") .set_multivar("log.excludeDecoration", "refs/gitbutler", "refs/gitbutler")
@ -327,14 +320,14 @@ fn _print_tree(repo: &git2::Repository, tree: &git2::Tree) -> Result<()> {
// merge the target branch into our current working directory // merge the target branch into our current working directory
// update the target sha // update the target sha
pub(crate) fn update_base_branch( pub(crate) fn update_base_branch(
project_repository: &ProjectRepository, ctx: &CommandContext,
perm: &mut WorktreeWritePermission, perm: &mut WorktreeWritePermission,
) -> anyhow::Result<Vec<ReferenceName>> { ) -> anyhow::Result<Vec<ReferenceName>> {
project_repository.assure_resolved()?; ctx.assure_resolved()?;
// look up the target and see if there is a new oid // look up the target and see if there is a new oid
let target = default_target(&project_repository.project().gb_dir())?; let target = default_target(&ctx.project().gb_dir())?;
let repo = project_repository.repo(); let repo = ctx.repository();
let target_branch = repo let target_branch = repo
.find_branch_by_refname(&target.branch.clone().into()) .find_branch_by_refname(&target.branch.clone().into())
.context(format!("failed to find branch {}", target.branch))?; .context(format!("failed to find branch {}", target.branch))?;
@ -360,10 +353,10 @@ pub(crate) fn update_base_branch(
target.sha target.sha
))?; ))?;
let vb_state = project_repository.project().virtual_branches(); let vb_state = ctx.project().virtual_branches();
// try to update every branch // try to update every branch
let updated_vbranches = get_applied_status(project_repository, None)? let updated_vbranches = get_applied_status(ctx, None)?
.branches .branches
.into_iter() .into_iter()
.map(|(branch, _)| branch) .map(|(branch, _)| branch)
@ -390,16 +383,13 @@ pub(crate) fn update_base_branch(
branch.upstream = None; branch.upstream = None;
branch.upstream_head = None; branch.upstream_head = None;
let non_commited_files = gitbutler_diff::trees( let non_commited_files =
project_repository.repo(), gitbutler_diff::trees(ctx.repository(), &branch_head_tree, &branch_tree)?;
&branch_head_tree,
&branch_tree,
)?;
if non_commited_files.is_empty() { if non_commited_files.is_empty() {
// if there are no commited files, then the branch is fully merged // if there are no commited files, then the branch is fully merged
// and we can delete it. // and we can delete it.
vb_state.mark_as_not_in_workspace(branch.id)?; vb_state.mark_as_not_in_workspace(branch.id)?;
project_repository.delete_branch_reference(&branch)?; ctx.delete_branch_reference(&branch)?;
Ok(None) Ok(None)
} else { } else {
vb_state.set_branch(branch.clone())?; vb_state.set_branch(branch.clone())?;
@ -418,7 +408,7 @@ pub(crate) fn update_base_branch(
if branch_tree_merge_index.has_conflicts() { if branch_tree_merge_index.has_conflicts() {
// branch tree conflicts with new target, unapply branch for now. we'll handle it later, when user applies it back. // branch tree conflicts with new target, unapply branch for now. we'll handle it later, when user applies it back.
let branch_manager = project_repository.branch_manager(); let branch_manager = ctx.branch_manager();
let unapplied_real_branch = let unapplied_real_branch =
branch_manager.convert_to_real_branch(branch.id, perm)?; branch_manager.convert_to_real_branch(branch.id, perm)?;
@ -428,7 +418,7 @@ pub(crate) fn update_base_branch(
} }
let branch_merge_index_tree_oid = let branch_merge_index_tree_oid =
branch_tree_merge_index.write_tree_to(project_repository.repo())?; branch_tree_merge_index.write_tree_to(ctx.repository())?;
if branch_merge_index_tree_oid == new_target_tree.id() { if branch_merge_index_tree_oid == new_target_tree.id() {
return result_integrated_detected(branch); return result_integrated_detected(branch);
@ -452,7 +442,7 @@ pub(crate) fn update_base_branch(
if branch_head_merge_index.has_conflicts() { if branch_head_merge_index.has_conflicts() {
// branch commits conflict with new target, make sure the branch is // branch commits conflict with new target, make sure the branch is
// unapplied. conflicts witll be dealt with when applying it back. // unapplied. conflicts witll be dealt with when applying it back.
let branch_manager = project_repository.branch_manager(); let branch_manager = ctx.branch_manager();
let unapplied_real_branch = let unapplied_real_branch =
branch_manager.convert_to_real_branch(branch.id, perm)?; branch_manager.convert_to_real_branch(branch.id, perm)?;
unapplied_branch_names.push(unapplied_real_branch); unapplied_branch_names.push(unapplied_real_branch);
@ -462,7 +452,7 @@ pub(crate) fn update_base_branch(
// branch commits do not conflict with new target, so lets merge them // branch commits do not conflict with new target, so lets merge them
let branch_head_merge_tree_oid = branch_head_merge_index let branch_head_merge_tree_oid = branch_head_merge_index
.write_tree_to(project_repository.repo()) .write_tree_to(ctx.repository())
.context(format!( .context(format!(
"failed to write head merge index for {}", "failed to write head merge index for {}",
branch.id branch.id
@ -477,7 +467,7 @@ pub(crate) fn update_base_branch(
.find_tree(branch_head_merge_tree_oid) .find_tree(branch_head_merge_tree_oid)
.context("failed to find tree")?; .context("failed to find tree")?;
let new_target_head = project_repository let new_target_head = ctx
.commit( .commit(
format!( format!(
"Merged {}/{} into {}", "Merged {}/{} into {}",
@ -504,7 +494,7 @@ pub(crate) fn update_base_branch(
// branch was not pushed to upstream yet. attempt a rebase, // branch was not pushed to upstream yet. attempt a rebase,
let rebased_head_oid = cherry_rebase( let rebased_head_oid = cherry_rebase(
project_repository, ctx,
new_target_commit.id(), new_target_commit.id(),
new_target_commit.id(), new_target_commit.id(),
branch.head, branch.head,
@ -558,15 +548,12 @@ pub(crate) fn update_base_branch(
})?; })?;
// Rewriting the integration commit is necessary after changing target sha. // Rewriting the integration commit is necessary after changing target sha.
crate::integration::update_gitbutler_integration(&vb_state, project_repository)?; crate::integration::update_gitbutler_integration(&vb_state, ctx)?;
Ok(unapplied_branch_names) Ok(unapplied_branch_names)
} }
pub(crate) fn target_to_base_branch( pub(crate) fn target_to_base_branch(ctx: &CommandContext, target: &Target) -> Result<BaseBranch> {
project_repository: &ProjectRepository, let repo = ctx.repository();
target: &Target,
) -> Result<BaseBranch> {
let repo = project_repository.repo();
let branch = repo let branch = repo
.find_branch_by_refname(&target.branch.clone().into())? .find_branch_by_refname(&target.branch.clone().into())?
.ok_or(anyhow!("failed to get branch"))?; .ok_or(anyhow!("failed to get branch"))?;
@ -574,7 +561,7 @@ pub(crate) fn target_to_base_branch(
let oid = commit.id(); let oid = commit.id();
// gather a list of commits between oid and target.sha // gather a list of commits between oid and target.sha
let upstream_commits = project_repository let upstream_commits = ctx
.log(oid, LogUntil::Commit(target.sha)) .log(oid, LogUntil::Commit(target.sha))
.context("failed to get upstream commits")? .context("failed to get upstream commits")?
.iter() .iter()
@ -582,7 +569,7 @@ pub(crate) fn target_to_base_branch(
.collect::<Vec<_>>(); .collect::<Vec<_>>();
// get some recent commits // get some recent commits
let recent_commits = project_repository let recent_commits = ctx
.log(target.sha, LogUntil::Take(20)) .log(target.sha, LogUntil::Take(20))
.context("failed to get recent commits")? .context("failed to get recent commits")?
.iter() .iter()
@ -612,7 +599,7 @@ pub(crate) fn target_to_base_branch(
behind: upstream_commits.len(), behind: upstream_commits.len(),
upstream_commits, upstream_commits,
recent_commits, recent_commits,
last_fetched_ms: project_repository last_fetched_ms: ctx
.project() .project()
.project_data_last_fetch .project_data_last_fetch
.as_ref() .as_ref()

View File

@ -9,7 +9,7 @@ use bstr::{BString, ByteSlice};
use gitbutler_branch::{ use gitbutler_branch::{
Branch as GitButlerBranch, BranchId, ReferenceExt, Target, VirtualBranchesHandle, Branch as GitButlerBranch, BranchId, ReferenceExt, Target, VirtualBranchesHandle,
}; };
use gitbutler_command_context::ProjectRepository; use gitbutler_command_context::CommandContext;
use gitbutler_reference::normalize_branch_name; use gitbutler_reference::normalize_branch_name;
use gitbutler_repo::RepoActionsExt; use gitbutler_repo::RepoActionsExt;
use itertools::Itertools; use itertools::Itertools;
@ -19,7 +19,7 @@ use crate::VirtualBranchesExt;
/// Returns a list of branches associated with this project. /// Returns a list of branches associated with this project.
pub fn list_branches( pub fn list_branches(
ctx: &ProjectRepository, ctx: &CommandContext,
filter: Option<BranchListingFilter>, filter: Option<BranchListingFilter>,
) -> Result<Vec<BranchListing>> { ) -> Result<Vec<BranchListing>> {
let vb_handle = ctx.project().virtual_branches(); let vb_handle = ctx.project().virtual_branches();
@ -33,7 +33,7 @@ pub fn list_branches(
_ => None, _ => None,
}); });
let mut git_branches: Vec<GroupBranch> = vec![]; let mut git_branches: Vec<GroupBranch> = vec![];
for result in ctx.repo().branches(branch_filter)? { for result in ctx.repository().branches(branch_filter)? {
match result { match result {
Ok((branch, branch_type)) => match branch_type { Ok((branch, branch_type)) => match branch_type {
git2::BranchType::Local => { git2::BranchType::Local => {
@ -98,10 +98,10 @@ fn matches_all(branch: &BranchListing, filter: &Option<BranchListingFilter>) ->
fn combine_branches( fn combine_branches(
mut group_branches: Vec<GroupBranch>, mut group_branches: Vec<GroupBranch>,
virtual_branches: impl Iterator<Item = GitButlerBranch>, virtual_branches: impl Iterator<Item = GitButlerBranch>,
ctx: &ProjectRepository, ctx: &CommandContext,
vb_handle: &VirtualBranchesHandle, vb_handle: &VirtualBranchesHandle,
) -> Result<Vec<BranchListing>> { ) -> Result<Vec<BranchListing>> {
let repo = ctx.repo(); let repo = ctx.repository();
for branch in virtual_branches { for branch in virtual_branches {
group_branches.push(GroupBranch::Virtual(branch)); group_branches.push(GroupBranch::Virtual(branch));
} }
@ -393,10 +393,10 @@ pub struct VirtualBranchReference {
/// Takes a list of branch names (the given name, as returned by `BranchListing`) and returns /// Takes a list of branch names (the given name, as returned by `BranchListing`) and returns
/// a list of enriched branch data in the form of `BranchData`. /// a list of enriched branch data in the form of `BranchData`.
pub fn get_branch_listing_details( pub fn get_branch_listing_details(
ctx: &ProjectRepository, ctx: &CommandContext,
branch_names: Vec<String>, branch_names: Vec<String>,
) -> Result<Vec<BranchListingDetails>> { ) -> Result<Vec<BranchListingDetails>> {
let repo = ctx.repo(); let repo = ctx.repository();
// Can we do this in a more efficient way? // Can we do this in a more efficient way?
let branches = list_branches(ctx, None)? let branches = list_branches(ctx, None)?
.into_iter() .into_iter()

View File

@ -25,12 +25,12 @@ impl BranchManager<'_> {
create: &BranchCreateRequest, create: &BranchCreateRequest,
perm: &mut WorktreeWritePermission, perm: &mut WorktreeWritePermission,
) -> Result<Branch> { ) -> Result<Branch> {
let vb_state = self.project_repository.project().virtual_branches(); let vb_state = self.ctx.project().virtual_branches();
let default_target = vb_state.get_default_target()?; let default_target = vb_state.get_default_target()?;
let commit = self let commit = self
.project_repository .ctx
.repo() .repository()
.find_commit(default_target.sha) .find_commit(default_target.sha)
.context("failed to find default target commit")?; .context("failed to find default target commit")?;
@ -54,7 +54,7 @@ impl BranchManager<'_> {
); );
_ = self _ = self
.project_repository .ctx
.project() .project()
.snapshot_branch_creation(name.clone(), perm); .snapshot_branch_creation(name.clone(), perm);
@ -107,7 +107,7 @@ impl BranchManager<'_> {
ownership: BranchOwnershipClaims::default(), ownership: BranchOwnershipClaims::default(),
order, order,
selected_for_changes, selected_for_changes,
allow_rebasing: self.project_repository.project().ok_with_force_push.into(), allow_rebasing: self.ctx.project().ok_with_force_push.into(),
applied: true, applied: true,
in_workspace: true, in_workspace: true,
not_in_workspace_wip_change_id: None, not_in_workspace_wip_change_id: None,
@ -119,7 +119,7 @@ impl BranchManager<'_> {
} }
vb_state.set_branch(branch.clone())?; vb_state.set_branch(branch.clone())?;
self.project_repository.add_branch_reference(&branch)?; self.ctx.add_branch_reference(&branch)?;
Ok(branch) Ok(branch)
} }
@ -151,11 +151,11 @@ impl BranchManager<'_> {
.to_string(); .to_string();
let _ = self let _ = self
.project_repository .ctx
.project() .project()
.snapshot_branch_creation(branch_name.clone(), perm); .snapshot_branch_creation(branch_name.clone(), perm);
let vb_state = self.project_repository.project().virtual_branches(); let vb_state = self.ctx.project().virtual_branches();
let default_target = vb_state.get_default_target()?; let default_target = vb_state.get_default_target()?;
@ -165,7 +165,7 @@ impl BranchManager<'_> {
} }
} }
let repo = self.project_repository.repo(); let repo = self.ctx.repository();
let head_reference = repo let head_reference = repo
.find_reference(&target.to_string()) .find_reference(&target.to_string())
.map_err(|err| match err { .map_err(|err| match err {
@ -200,11 +200,8 @@ impl BranchManager<'_> {
let merge_base_tree = repo.find_commit(merge_base_oid)?.tree()?; let merge_base_tree = repo.find_commit(merge_base_oid)?.tree()?;
// do a diff between the head of this branch and the target base // do a diff between the head of this branch and the target base
let diff = gitbutler_diff::trees( let diff =
self.project_repository.repo(), gitbutler_diff::trees(self.ctx.repository(), &merge_base_tree, &head_commit_tree)?;
&merge_base_tree,
&head_commit_tree,
)?;
// assign ownership to the branch // assign ownership to the branch
let ownership = diff.iter().fold( let ownership = diff.iter().fold(
@ -235,7 +232,7 @@ impl BranchManager<'_> {
branch.ownership = ownership; branch.ownership = ownership;
branch.order = order; branch.order = order;
branch.selected_for_changes = selected_for_changes; branch.selected_for_changes = selected_for_changes;
branch.allow_rebasing = self.project_repository.project().ok_with_force_push.into(); branch.allow_rebasing = self.ctx.project().ok_with_force_push.into();
branch.applied = true; branch.applied = true;
branch.in_workspace = true; branch.in_workspace = true;
@ -255,7 +252,7 @@ impl BranchManager<'_> {
ownership, ownership,
order, order,
selected_for_changes, selected_for_changes,
allow_rebasing: self.project_repository.project().ok_with_force_push.into(), allow_rebasing: self.ctx.project().ok_with_force_push.into(),
applied: true, applied: true,
in_workspace: true, in_workspace: true,
not_in_workspace_wip_change_id: None, not_in_workspace_wip_change_id: None,
@ -263,7 +260,7 @@ impl BranchManager<'_> {
}; };
vb_state.set_branch(branch.clone())?; vb_state.set_branch(branch.clone())?;
self.project_repository.add_branch_reference(&branch)?; self.ctx.add_branch_reference(&branch)?;
match self.apply_branch(branch.id, perm) { match self.apply_branch(branch.id, perm) {
Ok(_) => Ok(branch.id), Ok(_) => Ok(branch.id),
@ -287,11 +284,11 @@ impl BranchManager<'_> {
branch_id: BranchId, branch_id: BranchId,
perm: &mut WorktreeWritePermission, perm: &mut WorktreeWritePermission,
) -> Result<String> { ) -> Result<String> {
self.project_repository.assure_resolved()?; self.ctx.assure_resolved()?;
self.project_repository.assure_unconflicted()?; self.ctx.assure_unconflicted()?;
let repo = self.project_repository.repo(); let repo = self.ctx.repository();
let vb_state = self.project_repository.project().virtual_branches(); let vb_state = self.ctx.project().virtual_branches();
let default_target = vb_state.get_default_target()?; let default_target = vb_state.get_default_target()?;
let mut branch = vb_state.get_branch_in_workspace(branch_id)?; let mut branch = vb_state.get_branch_in_workspace(branch_id)?;
@ -358,11 +355,7 @@ impl BranchManager<'_> {
merge_conflicts.push(path); merge_conflicts.push(path);
} }
} }
conflicts::mark( conflicts::mark(self.ctx, &merge_conflicts, Some(default_target.sha))?;
self.project_repository,
&merge_conflicts,
Some(default_target.sha),
)?;
return Ok(branch.name); return Ok(branch.name);
} }
@ -372,7 +365,7 @@ impl BranchManager<'_> {
.context("failed to find head commit")?; .context("failed to find head commit")?;
let merged_branch_tree_oid = merge_index let merged_branch_tree_oid = merge_index
.write_tree_to(self.project_repository.repo()) .write_tree_to(self.ctx.repository())
.context("failed to write tree")?; .context("failed to write tree")?;
let merged_branch_tree = repo let merged_branch_tree = repo
@ -384,7 +377,7 @@ impl BranchManager<'_> {
// branch was pushed to upstream, and user doesn't like force pushing. // branch was pushed to upstream, and user doesn't like force pushing.
// create a merge commit to avoid the need of force pushing then. // create a merge commit to avoid the need of force pushing then.
let new_branch_head = self.project_repository.commit( let new_branch_head = self.ctx.commit(
format!( format!(
"Merged {}/{} into {}", "Merged {}/{} into {}",
default_target.branch.remote(), default_target.branch.remote(),
@ -401,7 +394,7 @@ impl BranchManager<'_> {
branch.head = new_branch_head; branch.head = new_branch_head;
} else { } else {
let rebase = cherry_rebase( let rebase = cherry_rebase(
self.project_repository, self.ctx,
target_commit.id(), target_commit.id(),
target_commit.id(), target_commit.id(),
branch.head, branch.head,
@ -432,7 +425,7 @@ impl BranchManager<'_> {
// commit the merge tree oid // commit the merge tree oid
let new_branch_head = self let new_branch_head = self
.project_repository .ctx
.commit( .commit(
format!( format!(
"Merged {}/{} into {}", "Merged {}/{} into {}",
@ -459,7 +452,7 @@ impl BranchManager<'_> {
vb_state.set_branch(branch.clone())?; vb_state.set_branch(branch.clone())?;
} }
let wd_tree = self.project_repository.repo().get_wd_tree()?; let wd_tree = self.ctx.repository().get_wd_tree()?;
let branch_tree = repo let branch_tree = repo
.find_tree(branch.tree) .find_tree(branch.tree)
@ -482,11 +475,7 @@ impl BranchManager<'_> {
merge_conflicts.push(path); merge_conflicts.push(path);
} }
} }
conflicts::mark( conflicts::mark(self.ctx, &merge_conflicts, Some(default_target.sha))?;
self.project_repository,
&merge_conflicts,
Some(default_target.sha),
)?;
} }
// apply the branch // apply the branch
@ -508,7 +497,7 @@ impl BranchManager<'_> {
if let Some(headers) = potential_wip_commit.gitbutler_headers() { if let Some(headers) = potential_wip_commit.gitbutler_headers() {
if headers.change_id == wip_commit_to_unapply { if headers.change_id == wip_commit_to_unapply {
undo_commit(self.project_repository, branch.id, branch.head)?; undo_commit(self.ctx, branch.id, branch.head)?;
} }
} }
@ -517,7 +506,7 @@ impl BranchManager<'_> {
} }
} }
update_gitbutler_integration(&vb_state, self.project_repository)?; update_gitbutler_integration(&vb_state, self.ctx)?;
Ok(branch.name) Ok(branch.name)
} }

View File

@ -24,7 +24,7 @@ impl BranchManager<'_> {
branch_id: BranchId, branch_id: BranchId,
perm: &mut WorktreeWritePermission, perm: &mut WorktreeWritePermission,
) -> Result<ReferenceName> { ) -> Result<ReferenceName> {
let vb_state = self.project_repository.project().virtual_branches(); let vb_state = self.ctx.project().virtual_branches();
let mut target_branch = vb_state.get_branch(branch_id)?; let mut target_branch = vb_state.get_branch(branch_id)?;
@ -34,8 +34,8 @@ impl BranchManager<'_> {
self.delete_branch(branch_id, perm)?; self.delete_branch(branch_id, perm)?;
// If we were conflicting, it means that it was the only branch applied. Since we've now unapplied it we can clear all conflicts // If we were conflicting, it means that it was the only branch applied. Since we've now unapplied it we can clear all conflicts
if conflicts::is_conflicting(self.project_repository, None)? { if conflicts::is_conflicting(self.ctx, None)? {
conflicts::clear(self.project_repository)?; conflicts::clear(self.ctx)?;
} }
vb_state.update_ordering()?; vb_state.update_ordering()?;
@ -43,7 +43,7 @@ impl BranchManager<'_> {
// Ensure we still have a default target // Ensure we still have a default target
ensure_selected_for_changes(&vb_state).context("failed to ensure selected for changes")?; ensure_selected_for_changes(&vb_state).context("failed to ensure selected for changes")?;
crate::integration::update_gitbutler_integration(&vb_state, self.project_repository)?; crate::integration::update_gitbutler_integration(&vb_state, self.ctx)?;
real_branch.reference_name() real_branch.reference_name()
} }
@ -53,7 +53,7 @@ impl BranchManager<'_> {
branch_id: BranchId, branch_id: BranchId,
perm: &mut WorktreeWritePermission, perm: &mut WorktreeWritePermission,
) -> Result<()> { ) -> Result<()> {
let vb_state = self.project_repository.project().virtual_branches(); let vb_state = self.ctx.project().virtual_branches();
let Some(branch) = vb_state.try_branch(branch_id)? else { let Some(branch) = vb_state.try_branch(branch_id)? else {
return Ok(()); return Ok(());
}; };
@ -64,16 +64,16 @@ impl BranchManager<'_> {
} }
_ = self _ = self
.project_repository .ctx
.project() .project()
.snapshot_branch_deletion(branch.name.clone(), perm); .snapshot_branch_deletion(branch.name.clone(), perm);
let repo = self.project_repository.repo(); let repo = self.ctx.repository();
let target_commit = repo.target_commit()?; let target_commit = repo.target_commit()?;
let base_tree = target_commit.tree().context("failed to get target tree")?; let base_tree = target_commit.tree().context("failed to get target tree")?;
let applied_statuses = get_applied_status(self.project_repository, None) let applied_statuses = get_applied_status(self.ctx, None)
.context("failed to get status by branch")? .context("failed to get status by branch")?
.branches; .branches;
@ -97,11 +97,8 @@ impl BranchManager<'_> {
.into_iter() .into_iter()
.map(|file| (file.path, file.hunks)) .map(|file| (file.path, file.hunks))
.collect::<Vec<(PathBuf, Vec<VirtualBranchHunk>)>>(); .collect::<Vec<(PathBuf, Vec<VirtualBranchHunk>)>>();
let tree_oid = gitbutler_diff::write::hunks_onto_oid( let tree_oid =
self.project_repository, gitbutler_diff::write::hunks_onto_oid(self.ctx, &branch.head, files)?;
&branch.head,
files,
)?;
let branch_tree = repo.find_tree(tree_oid)?; let branch_tree = repo.find_tree(tree_oid)?;
let mut result = let mut result =
repo.merge_trees(&base_tree, &final_tree, &branch_tree, None)?; repo.merge_trees(&base_tree, &final_tree, &branch_tree, None)?;
@ -118,7 +115,7 @@ impl BranchManager<'_> {
.checkout() .checkout()
.context("failed to checkout tree")?; .context("failed to checkout tree")?;
self.project_repository.delete_branch_reference(&branch)?; self.ctx.delete_branch_reference(&branch)?;
ensure_selected_for_changes(&vb_state).context("failed to ensure selected for changes")?; ensure_selected_for_changes(&vb_state).context("failed to ensure selected for changes")?;
@ -128,12 +125,12 @@ impl BranchManager<'_> {
impl BranchManager<'_> { impl BranchManager<'_> {
fn build_real_branch(&self, vbranch: &mut Branch) -> Result<git2::Branch<'_>> { fn build_real_branch(&self, vbranch: &mut Branch) -> Result<git2::Branch<'_>> {
let repo = self.project_repository.repo(); let repo = self.ctx.repository();
let target_commit = repo.find_commit(vbranch.head)?; let target_commit = repo.find_commit(vbranch.head)?;
let branch_name = vbranch.name.clone(); let branch_name = vbranch.name.clone();
let branch_name = normalize_branch_name(&branch_name); let branch_name = normalize_branch_name(&branch_name);
let vb_state = self.project_repository.project().virtual_branches(); let vb_state = self.ctx.project().virtual_branches();
let branch = repo.branch(&branch_name, &target_commit, true)?; let branch = repo.branch(&branch_name, &target_commit, true)?;
vbranch.source_refname = Some(Refname::try_from(&branch)?); vbranch.source_refname = Some(Refname::try_from(&branch)?);
vb_state.set_branch(vbranch.clone())?; vb_state.set_branch(vbranch.clone())?;
@ -148,7 +145,7 @@ impl BranchManager<'_> {
vbranch: &mut Branch, vbranch: &mut Branch,
branch: &git2::Branch<'_>, branch: &git2::Branch<'_>,
) -> Result<Option<git2::Oid>> { ) -> Result<Option<git2::Oid>> {
let repo = self.project_repository.repo(); let repo = self.ctx.repository();
// Build wip tree as either any uncommitted changes or an empty tree // Build wip tree as either any uncommitted changes or an empty tree
let vbranch_wip_tree = repo.find_tree(vbranch.tree)?; let vbranch_wip_tree = repo.find_tree(vbranch.tree)?;
@ -181,7 +178,7 @@ impl BranchManager<'_> {
Some(commit_headers.clone()), Some(commit_headers.clone()),
)?; )?;
let vb_state = self.project_repository.project().virtual_branches(); let vb_state = self.ctx.project().virtual_branches();
// vbranch.head = commit_oid; // vbranch.head = commit_oid;
vbranch.not_in_workspace_wip_change_id = Some(commit_headers.change_id); vbranch.not_in_workspace_wip_change_id = Some(commit_headers.change_id);
vb_state.set_branch(vbranch.clone())?; vb_state.set_branch(vbranch.clone())?;

View File

@ -1,20 +1,18 @@
use gitbutler_command_context::ProjectRepository; use gitbutler_command_context::CommandContext;
mod branch_creation; mod branch_creation;
mod branch_removal; mod branch_removal;
pub struct BranchManager<'l> { pub struct BranchManager<'l> {
project_repository: &'l ProjectRepository, ctx: &'l CommandContext,
} }
pub trait BranchManagerExt { pub trait BranchManagerExt {
fn branch_manager(&self) -> BranchManager; fn branch_manager(&self) -> BranchManager;
} }
impl BranchManagerExt for ProjectRepository { impl BranchManagerExt for CommandContext {
fn branch_manager(&self) -> BranchManager { fn branch_manager(&self) -> BranchManager {
BranchManager { BranchManager { ctx: self }
project_repository: self,
}
} }
} }

View File

@ -1,7 +1,7 @@
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use bstr::BString; use bstr::BString;
use gitbutler_branch::{Branch, BranchId}; use gitbutler_branch::{Branch, BranchId};
use gitbutler_command_context::ProjectRepository; use gitbutler_command_context::CommandContext;
use gitbutler_commit::commit_ext::CommitExt; use gitbutler_commit::commit_ext::CommitExt;
use serde::Serialize; use serde::Serialize;
@ -38,7 +38,7 @@ pub struct VirtualBranchCommit {
} }
pub(crate) fn commit_to_vbranch_commit( pub(crate) fn commit_to_vbranch_commit(
repository: &ProjectRepository, repository: &CommandContext,
branch: &Branch, branch: &Branch,
commit: &git2::Commit, commit: &git2::Commit,
is_integrated: bool, is_integrated: bool,

View File

@ -12,11 +12,11 @@ use std::{
use anyhow::{anyhow, bail, Context, Result}; use anyhow::{anyhow, bail, Context, Result};
use bstr::ByteSlice; use bstr::ByteSlice;
use gitbutler_command_context::ProjectRepository; use gitbutler_command_context::CommandContext;
use gitbutler_error::error::Marker; use gitbutler_error::error::Marker;
pub(crate) fn mark<P: AsRef<Path>, A: AsRef<[P]>>( pub(crate) fn mark<P: AsRef<Path>, A: AsRef<[P]>>(
ctx: &ProjectRepository, ctx: &CommandContext,
paths: A, paths: A,
parent: Option<git2::Oid>, parent: Option<git2::Oid>,
) -> Result<()> { ) -> Result<()> {
@ -45,15 +45,15 @@ pub(crate) fn mark<P: AsRef<Path>, A: AsRef<[P]>>(
Ok(()) Ok(())
} }
fn conflicts_path(ctx: &ProjectRepository) -> PathBuf { fn conflicts_path(ctx: &CommandContext) -> PathBuf {
ctx.repo().path().join("conflicts") ctx.repository().path().join("conflicts")
} }
fn merge_parent_path(ctx: &ProjectRepository) -> PathBuf { fn merge_parent_path(ctx: &CommandContext) -> PathBuf {
ctx.repo().path().join("base_merge_parent") ctx.repository().path().join("base_merge_parent")
} }
pub(crate) fn merge_parent(ctx: &ProjectRepository) -> Result<Option<git2::Oid>> { pub(crate) fn merge_parent(ctx: &CommandContext) -> Result<Option<git2::Oid>> {
use std::io::BufRead; use std::io::BufRead;
let merge_path = merge_parent_path(ctx); let merge_path = merge_parent_path(ctx);
@ -73,7 +73,7 @@ pub(crate) fn merge_parent(ctx: &ProjectRepository) -> Result<Option<git2::Oid>>
} }
} }
pub fn resolve<P: AsRef<Path>>(ctx: &ProjectRepository, path_to_resolve: P) -> Result<()> { pub fn resolve<P: AsRef<Path>>(ctx: &CommandContext, path_to_resolve: P) -> Result<()> {
let path_to_resolve = path_to_resolve.as_ref(); let path_to_resolve = path_to_resolve.as_ref();
let path_to_resolve = path_to_resolve.as_os_str().as_encoded_bytes(); let path_to_resolve = path_to_resolve.as_os_str().as_encoded_bytes();
let conflicts_path = conflicts_path(ctx); let conflicts_path = conflicts_path(ctx);
@ -93,7 +93,7 @@ pub fn resolve<P: AsRef<Path>>(ctx: &ProjectRepository, path_to_resolve: P) -> R
Ok(()) Ok(())
} }
pub(crate) fn conflicting_files(ctx: &ProjectRepository) -> Result<Vec<PathBuf>> { pub(crate) fn conflicting_files(ctx: &CommandContext) -> Result<Vec<PathBuf>> {
let conflicts_path = conflicts_path(ctx); let conflicts_path = conflicts_path(ctx);
if !conflicts_path.exists() { if !conflicts_path.exists() {
return Ok(vec![]); return Ok(vec![]);
@ -108,7 +108,7 @@ pub(crate) fn conflicting_files(ctx: &ProjectRepository) -> Result<Vec<PathBuf>>
/// Check if `path` is conflicting in `repository`, or if `None`, check if there is any conflict. /// Check if `path` is conflicting in `repository`, or if `None`, check if there is any conflict.
// TODO(ST): Should this not rather check the conflicting state in the index? // TODO(ST): Should this not rather check the conflicting state in the index?
pub(crate) fn is_conflicting(repository: &ProjectRepository, path: Option<&Path>) -> Result<bool> { pub(crate) fn is_conflicting(repository: &CommandContext, path: Option<&Path>) -> Result<bool> {
let conflicts_path = conflicts_path(repository); let conflicts_path = conflicts_path(repository);
if !conflicts_path.exists() { if !conflicts_path.exists() {
return Ok(false); return Ok(false);
@ -128,11 +128,11 @@ pub(crate) fn is_conflicting(repository: &ProjectRepository, path: Option<&Path>
// is this project still in a resolving conflict state? // is this project still in a resolving conflict state?
// - could be that there are no more conflicts, but the state is not committed // - could be that there are no more conflicts, but the state is not committed
pub(crate) fn is_resolving(ctx: &ProjectRepository) -> bool { pub(crate) fn is_resolving(ctx: &CommandContext) -> bool {
merge_parent_path(ctx).exists() merge_parent_path(ctx).exists()
} }
pub(crate) fn clear(ctx: &ProjectRepository) -> Result<()> { pub(crate) fn clear(ctx: &CommandContext) -> Result<()> {
remove_file_ignore_missing(merge_parent_path(ctx))?; remove_file_ignore_missing(merge_parent_path(ctx))?;
remove_file_ignore_missing(conflicts_path(ctx))?; remove_file_ignore_missing(conflicts_path(ctx))?;
Ok(()) Ok(())
@ -154,7 +154,7 @@ pub(crate) trait RepoConflictsExt {
fn is_resolving(&self) -> bool; fn is_resolving(&self) -> bool;
} }
impl RepoConflictsExt for ProjectRepository { impl RepoConflictsExt for CommandContext {
fn is_resolving(&self) -> bool { fn is_resolving(&self) -> bool {
is_resolving(self) is_resolving(self)
} }

View File

@ -4,7 +4,7 @@ use std::{
}; };
use anyhow::{anyhow, Context, Result}; use anyhow::{anyhow, Context, Result};
use gitbutler_command_context::ProjectRepository; use gitbutler_command_context::CommandContext;
use gitbutler_diff::FileDiff; use gitbutler_diff::FileDiff;
use serde::Serialize; use serde::Serialize;
@ -86,7 +86,7 @@ impl Get<VirtualBranchFile> for Vec<VirtualBranchFile> {
} }
pub(crate) fn list_virtual_commit_files( pub(crate) fn list_virtual_commit_files(
project_repository: &ProjectRepository, ctx: &CommandContext,
commit: &git2::Commit, commit: &git2::Commit,
) -> Result<Vec<VirtualBranchFile>> { ) -> Result<Vec<VirtualBranchFile>> {
if commit.parent_count() == 0 { if commit.parent_count() == 0 {
@ -95,12 +95,9 @@ pub(crate) fn list_virtual_commit_files(
let parent = commit.parent(0).context("failed to get parent commit")?; let parent = commit.parent(0).context("failed to get parent commit")?;
let commit_tree = commit.tree().context("failed to get commit tree")?; let commit_tree = commit.tree().context("failed to get commit tree")?;
let parent_tree = parent.tree().context("failed to get parent tree")?; let parent_tree = parent.tree().context("failed to get parent tree")?;
let diff = gitbutler_diff::trees(project_repository.repo(), &parent_tree, &commit_tree)?; let diff = gitbutler_diff::trees(ctx.repository(), &parent_tree, &commit_tree)?;
let hunks_by_filepath = virtual_hunks_by_file_diffs(&project_repository.project().path, diff); let hunks_by_filepath = virtual_hunks_by_file_diffs(&ctx.project().path, diff);
Ok(virtual_hunks_into_virtual_files( Ok(virtual_hunks_into_virtual_files(ctx, hunks_by_filepath))
project_repository,
hunks_by_filepath,
))
} }
fn virtual_hunks_by_file_diffs<'a>( fn virtual_hunks_by_file_diffs<'a>(
@ -117,15 +114,14 @@ fn virtual_hunks_by_file_diffs<'a>(
/// NOTE: There is no use returning an iterator here as this acts like the final product. /// NOTE: There is no use returning an iterator here as this acts like the final product.
pub(crate) fn virtual_hunks_into_virtual_files( pub(crate) fn virtual_hunks_into_virtual_files(
project_repository: &ProjectRepository, ctx: &CommandContext,
hunks: impl IntoIterator<Item = (PathBuf, Vec<VirtualBranchHunk>)>, hunks: impl IntoIterator<Item = (PathBuf, Vec<VirtualBranchHunk>)>,
) -> Vec<VirtualBranchFile> { ) -> Vec<VirtualBranchFile> {
hunks hunks
.into_iter() .into_iter()
.map(|(path, hunks)| { .map(|(path, hunks)| {
let id = path.display().to_string(); let id = path.display().to_string();
let conflicted = let conflicted = conflicts::is_conflicting(ctx, Some(&path)).unwrap_or(false);
conflicts::is_conflicting(project_repository, Some(&path)).unwrap_or(false);
let binary = hunks.iter().any(|h| h.binary); let binary = hunks.iter().any(|h| h.binary);
let modified_at = hunks.iter().map(|h| h.modified_at).max().unwrap_or(0); let modified_at = hunks.iter().map(|h| h.modified_at).max().unwrap_or(0);
debug_assert!(hunks.iter().all(|hunk| hunk.file_path == path)); debug_assert!(hunks.iter().all(|hunk| hunk.file_path == path));

View File

@ -7,7 +7,7 @@ use gitbutler_branch::{
GITBUTLER_INTEGRATION_COMMIT_AUTHOR_EMAIL, GITBUTLER_INTEGRATION_COMMIT_AUTHOR_NAME, GITBUTLER_INTEGRATION_COMMIT_AUTHOR_EMAIL, GITBUTLER_INTEGRATION_COMMIT_AUTHOR_NAME,
GITBUTLER_INTEGRATION_REFERENCE, GITBUTLER_INTEGRATION_REFERENCE,
}; };
use gitbutler_command_context::ProjectRepository; use gitbutler_command_context::CommandContext;
use gitbutler_commit::commit_ext::CommitExt; use gitbutler_commit::commit_ext::CommitExt;
use gitbutler_error::error::Marker; use gitbutler_error::error::Marker;
use gitbutler_project::access::WorktreeWritePermission; use gitbutler_project::access::WorktreeWritePermission;
@ -28,12 +28,12 @@ pub(crate) fn get_integration_commiter<'a>() -> Result<git2::Signature<'a>> {
// //
// This is the base against which we diff the working directory to understand // This is the base against which we diff the working directory to understand
// what files have been modified. // what files have been modified.
pub(crate) fn get_workspace_head(project_repo: &ProjectRepository) -> Result<git2::Oid> { pub(crate) fn get_workspace_head(ctx: &CommandContext) -> Result<git2::Oid> {
let vb_state = project_repo.project().virtual_branches(); let vb_state = ctx.project().virtual_branches();
let target = vb_state let target = vb_state
.get_default_target() .get_default_target()
.context("failed to get target")?; .context("failed to get target")?;
let repo: &git2::Repository = project_repo.repo(); let repo: &git2::Repository = ctx.repository();
let mut virtual_branches: Vec<Branch> = vb_state.list_branches_in_workspace()?; let mut virtual_branches: Vec<Branch> = vb_state.list_branches_in_workspace()?;
@ -51,9 +51,8 @@ pub(crate) fn get_workspace_head(project_repo: &ProjectRepository) -> Result<git
return Ok(target_commit.id()); return Ok(target_commit.id());
} }
if conflicts::is_conflicting(project_repo, None)? { if conflicts::is_conflicting(ctx, None)? {
let merge_parent = let merge_parent = conflicts::merge_parent(ctx)?.ok_or(anyhow!("No merge parent"))?;
conflicts::merge_parent(project_repo)?.ok_or(anyhow!("No merge parent"))?;
let first_branch = virtual_branches.first().ok_or(anyhow!("No branches"))?; let first_branch = virtual_branches.first().ok_or(anyhow!("No branches"))?;
let merge_base = repo.merge_base(first_branch.head, merge_parent)?; let merge_base = repo.merge_base(first_branch.head, merge_parent)?;
@ -135,13 +134,13 @@ fn write_integration_file(head: &git2::Reference, path: PathBuf) -> Result<()> {
} }
pub fn update_gitbutler_integration( pub fn update_gitbutler_integration(
vb_state: &VirtualBranchesHandle, vb_state: &VirtualBranchesHandle,
project_repository: &ProjectRepository, ctx: &CommandContext,
) -> Result<git2::Oid> { ) -> Result<git2::Oid> {
let target = vb_state let target = vb_state
.get_default_target() .get_default_target()
.context("failed to get target")?; .context("failed to get target")?;
let repo: &git2::Repository = project_repository.repo(); let repo: &git2::Repository = ctx.repository();
// get commit object from target.sha // get commit object from target.sha
let target_commit = repo.find_commit(target.sha)?; let target_commit = repo.find_commit(target.sha)?;
@ -162,14 +161,14 @@ pub fn update_gitbutler_integration(
} }
} }
let vb_state = project_repository.project().virtual_branches(); let vb_state = ctx.project().virtual_branches();
// get all virtual branches, we need to try to update them all // get all virtual branches, we need to try to update them all
let virtual_branches: Vec<Branch> = vb_state let virtual_branches: Vec<Branch> = vb_state
.list_branches_in_workspace() .list_branches_in_workspace()
.context("failed to list virtual branches")?; .context("failed to list virtual branches")?;
let integration_commit = repo.find_commit(get_workspace_head(project_repository)?)?; let integration_commit = repo.find_commit(get_workspace_head(ctx)?)?;
let integration_tree = integration_commit.tree()?; let integration_tree = integration_commit.tree()?;
// message that says how to get back to where they were // message that says how to get back to where they were
@ -279,7 +278,7 @@ pub fn update_gitbutler_integration(
Ok(final_commit) Ok(final_commit)
} }
pub fn verify_branch(ctx: &ProjectRepository, perm: &mut WorktreeWritePermission) -> Result<()> { pub fn verify_branch(ctx: &CommandContext, perm: &mut WorktreeWritePermission) -> Result<()> {
verify_current_branch_name(ctx) verify_current_branch_name(ctx)
.and_then(verify_head_is_set) .and_then(verify_head_is_set)
.and_then(|()| verify_head_is_clean(ctx, perm)) .and_then(|()| verify_head_is_clean(ctx, perm))
@ -287,8 +286,13 @@ pub fn verify_branch(ctx: &ProjectRepository, perm: &mut WorktreeWritePermission
Ok(()) Ok(())
} }
fn verify_head_is_set(ctx: &ProjectRepository) -> Result<()> { fn verify_head_is_set(ctx: &CommandContext) -> Result<()> {
match ctx.repo().head().context("failed to get head")?.name() { match ctx
.repository()
.head()
.context("failed to get head")?
.name()
{
Some(refname) if *refname == GITBUTLER_INTEGRATION_REFERENCE.to_string() => Ok(()), Some(refname) if *refname == GITBUTLER_INTEGRATION_REFERENCE.to_string() => Ok(()),
Some(head_name) => Err(invalid_head_err(head_name)), Some(head_name) => Err(invalid_head_err(head_name)),
None => Err(anyhow!( None => Err(anyhow!(
@ -299,8 +303,8 @@ fn verify_head_is_set(ctx: &ProjectRepository) -> Result<()> {
} }
// Returns an error if repo head is not pointing to the integration branch. // Returns an error if repo head is not pointing to the integration branch.
fn verify_current_branch_name(ctx: &ProjectRepository) -> Result<&ProjectRepository> { fn verify_current_branch_name(ctx: &CommandContext) -> Result<&CommandContext> {
match ctx.repo().head()?.name() { match ctx.repository().head()?.name() {
Some(head) => { Some(head) => {
let head_name = head.to_string(); let head_name = head.to_string();
if head_name != GITBUTLER_INTEGRATION_REFERENCE.to_string() { if head_name != GITBUTLER_INTEGRATION_REFERENCE.to_string() {
@ -313,9 +317,9 @@ fn verify_current_branch_name(ctx: &ProjectRepository) -> Result<&ProjectReposit
} }
// TODO(ST): Probably there should not be an implicit vbranch creation here. // TODO(ST): Probably there should not be an implicit vbranch creation here.
fn verify_head_is_clean(ctx: &ProjectRepository, perm: &mut WorktreeWritePermission) -> Result<()> { fn verify_head_is_clean(ctx: &CommandContext, perm: &mut WorktreeWritePermission) -> Result<()> {
let head_commit = ctx let head_commit = ctx
.repo() .repository()
.head() .head()
.context("failed to get head")? .context("failed to get head")?
.peel_to_commit() .peel_to_commit()
@ -342,7 +346,7 @@ fn verify_head_is_clean(ctx: &ProjectRepository, perm: &mut WorktreeWritePermiss
return Ok(()); return Ok(());
} }
ctx.repo() ctx.repository()
.reset( .reset(
integration_commit.as_ref().unwrap().as_object(), integration_commit.as_ref().unwrap().as_object(),
git2::ResetType::Soft, git2::ResetType::Soft,
@ -369,12 +373,12 @@ fn verify_head_is_clean(ctx: &ProjectRepository, perm: &mut WorktreeWritePermiss
let mut head = new_branch.head; let mut head = new_branch.head;
for commit in extra_commits { for commit in extra_commits {
let new_branch_head = ctx let new_branch_head = ctx
.repo() .repository()
.find_commit(head) .find_commit(head)
.context("failed to find new branch head")?; .context("failed to find new branch head")?;
let rebased_commit_oid = ctx let rebased_commit_oid = ctx
.repo() .repository()
.commit_with_signature( .commit_with_signature(
None, None,
&commit.author(), &commit.author(),
@ -389,7 +393,10 @@ fn verify_head_is_clean(ctx: &ProjectRepository, perm: &mut WorktreeWritePermiss
commit.id() commit.id()
))?; ))?;
let rebased_commit = ctx.repo().find_commit(rebased_commit_oid).context(format!( let rebased_commit = ctx
.repository()
.find_commit(rebased_commit_oid)
.context(format!(
"failed to find rebased commit {}", "failed to find rebased commit {}",
rebased_commit_oid rebased_commit_oid
))?; ))?;

View File

@ -3,7 +3,7 @@ use std::path::Path;
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use bstr::BString; use bstr::BString;
use gitbutler_branch::{ReferenceExt, Target, VirtualBranchesHandle}; use gitbutler_branch::{ReferenceExt, Target, VirtualBranchesHandle};
use gitbutler_command_context::ProjectRepository; use gitbutler_command_context::CommandContext;
use gitbutler_commit::commit_ext::CommitExt; use gitbutler_commit::commit_ext::CommitExt;
use gitbutler_reference::{Refname, RemoteRefname}; use gitbutler_reference::{Refname, RemoteRefname};
use gitbutler_repo::{LogUntil, RepoActionsExt, RepositoryExt}; use gitbutler_repo::{LogUntil, RepoActionsExt, RepositoryExt};
@ -61,17 +61,17 @@ pub struct RemoteCommit {
// for legacy purposes, this is still named "remote" branches, but it's actually // for legacy purposes, this is still named "remote" branches, but it's actually
// a list of all the normal (non-gitbutler) git branches. // a list of all the normal (non-gitbutler) git branches.
pub fn list_remote_branches(project_repository: &ProjectRepository) -> Result<Vec<RemoteBranch>> { pub fn list_remote_branches(ctx: &CommandContext) -> Result<Vec<RemoteBranch>> {
let default_target = default_target(&project_repository.project().gb_dir())?; let default_target = default_target(&ctx.project().gb_dir())?;
let mut remote_branches = vec![]; let mut remote_branches = vec![];
for (branch, _) in project_repository for (branch, _) in ctx
.repo() .repository()
.branches(None) .branches(None)
.context("failed to list remote branches")? .context("failed to list remote branches")?
.flatten() .flatten()
{ {
let branch = branch_to_remote_branch(project_repository, &branch); let branch = branch_to_remote_branch(ctx, &branch);
if let Some(branch) = branch { if let Some(branch) = branch {
let branch_is_trunk = branch.name.branch() == Some(default_target.branch.branch()) let branch_is_trunk = branch.name.branch() == Some(default_target.branch.branch())
@ -88,14 +88,11 @@ pub fn list_remote_branches(project_repository: &ProjectRepository) -> Result<Ve
Ok(remote_branches) Ok(remote_branches)
} }
pub(crate) fn get_branch_data( pub(crate) fn get_branch_data(ctx: &CommandContext, refname: &Refname) -> Result<RemoteBranchData> {
ctx: &ProjectRepository,
refname: &Refname,
) -> Result<RemoteBranchData> {
let default_target = default_target(&ctx.project().gb_dir())?; let default_target = default_target(&ctx.project().gb_dir())?;
let branch = ctx let branch = ctx
.repo() .repository()
.find_branch_by_refname(refname)? .find_branch_by_refname(refname)?
.ok_or(anyhow::anyhow!("failed to find branch {}", refname))?; .ok_or(anyhow::anyhow!("failed to find branch {}", refname))?;
@ -104,7 +101,7 @@ pub(crate) fn get_branch_data(
} }
pub(crate) fn branch_to_remote_branch( pub(crate) fn branch_to_remote_branch(
ctx: &ProjectRepository, ctx: &CommandContext,
branch: &git2::Branch, branch: &git2::Branch,
) -> Option<RemoteBranch> { ) -> Option<RemoteBranch> {
let commit = match branch.get().peel_to_commit() { let commit = match branch.get().peel_to_commit() {
@ -122,7 +119,10 @@ pub(crate) fn branch_to_remote_branch(
.context("could not get branch name") .context("could not get branch name")
.ok()?; .ok()?;
let given_name = branch.get().given_name(&ctx.repo().remotes().ok()?).ok()?; let given_name = branch
.get()
.given_name(&ctx.repository().remotes().ok()?)
.ok()?;
branch.get().target().map(|sha| RemoteBranch { branch.get().target().map(|sha| RemoteBranch {
sha, sha,
@ -145,7 +145,7 @@ pub(crate) fn branch_to_remote_branch(
} }
pub(crate) fn branch_to_remote_branch_data( pub(crate) fn branch_to_remote_branch_data(
project_repository: &ProjectRepository, ctx: &CommandContext,
branch: &git2::Branch, branch: &git2::Branch,
base: git2::Oid, base: git2::Oid,
) -> Result<Option<RemoteBranchData>> { ) -> Result<Option<RemoteBranchData>> {
@ -153,13 +153,13 @@ pub(crate) fn branch_to_remote_branch_data(
.get() .get()
.target() .target()
.map(|sha| { .map(|sha| {
let ahead = project_repository let ahead = ctx
.log(sha, LogUntil::Commit(base)) .log(sha, LogUntil::Commit(base))
.context("failed to get ahead commits")?; .context("failed to get ahead commits")?;
let name = Refname::try_from(branch).context("could not get branch name")?; let name = Refname::try_from(branch).context("could not get branch name")?;
let count_behind = project_repository let count_behind = ctx
.distance(base, sha) .distance(base, sha)
.context("failed to get behind count")?; .context("failed to get behind count")?;

View File

@ -4,7 +4,7 @@ use anyhow::{bail, Context, Result};
use gitbutler_branch::{ use gitbutler_branch::{
Branch, BranchCreateRequest, BranchId, BranchOwnershipClaims, OwnershipClaim, Branch, BranchCreateRequest, BranchId, BranchOwnershipClaims, OwnershipClaim,
}; };
use gitbutler_command_context::ProjectRepository; use gitbutler_command_context::CommandContext;
use gitbutler_diff::{diff_files_into_hunks, GitHunk, Hunk, HunkHash}; use gitbutler_diff::{diff_files_into_hunks, GitHunk, Hunk, HunkHash};
use gitbutler_project::access::WorktreeWritePermission; use gitbutler_project::access::WorktreeWritePermission;
use gitbutler_repo::RepositoryExt; use gitbutler_repo::RepositoryExt;
@ -29,16 +29,15 @@ pub struct VirtualBranchesStatus {
/// of skipped files. /// of skipped files.
// TODO(kv): make this side effect free // TODO(kv): make this side effect free
pub fn get_applied_status( pub fn get_applied_status(
project_repository: &ProjectRepository, ctx: &CommandContext,
perm: Option<&mut WorktreeWritePermission>, perm: Option<&mut WorktreeWritePermission>,
) -> Result<VirtualBranchesStatus> { ) -> Result<VirtualBranchesStatus> {
let integration_commit = get_workspace_head(project_repository)?; let integration_commit = get_workspace_head(ctx)?;
let mut virtual_branches = project_repository let mut virtual_branches = ctx
.project() .project()
.virtual_branches() .virtual_branches()
.list_branches_in_workspace()?; .list_branches_in_workspace()?;
let base_file_diffs = let base_file_diffs = gitbutler_diff::workdir(ctx.repository(), &integration_commit.to_owned())
gitbutler_diff::workdir(project_repository.repo(), &integration_commit.to_owned())
.context("failed to diff workdir")?; .context("failed to diff workdir")?;
let mut skipped_files: Vec<gitbutler_diff::FileDiff> = Vec::new(); let mut skipped_files: Vec<gitbutler_diff::FileDiff> = Vec::new();
@ -52,7 +51,7 @@ pub fn get_applied_status(
// sort by order, so that the default branch is first (left in the ui) // sort by order, so that the default branch is first (left in the ui)
virtual_branches.sort_by(|a, b| a.order.cmp(&b.order)); virtual_branches.sort_by(|a, b| a.order.cmp(&b.order));
let branch_manager = project_repository.branch_manager(); let branch_manager = ctx.branch_manager();
if virtual_branches.is_empty() && !base_diffs.is_empty() { if virtual_branches.is_empty() && !base_diffs.is_empty() {
if let Some(perm) = perm { if let Some(perm) = perm {
@ -70,7 +69,7 @@ pub fn get_applied_status(
.map(|branch| (branch.id, HashMap::new())) .map(|branch| (branch.id, HashMap::new()))
.collect(); .collect();
let locks = compute_locks(project_repository.repo(), &base_diffs, &virtual_branches)?; let locks = compute_locks(ctx.repository(), &base_diffs, &virtual_branches)?;
for branch in &mut virtual_branches { for branch in &mut virtual_branches {
let old_claims = branch.ownership.claims.clone(); let old_claims = branch.ownership.claims.clone();
@ -187,11 +186,10 @@ pub fn get_applied_status(
.collect::<Vec<_>>(); .collect::<Vec<_>>();
// write updated state if not resolving // write updated state if not resolving
if !project_repository.is_resolving() { if !ctx.is_resolving() {
let vb_state = project_repository.project().virtual_branches(); let vb_state = ctx.project().virtual_branches();
for (vbranch, files) in &mut hunks_by_branch { for (vbranch, files) in &mut hunks_by_branch {
vbranch.tree = vbranch.tree = gitbutler_diff::write::hunks_onto_oid(ctx, &vbranch.head, files)?;
gitbutler_diff::write::hunks_onto_oid(project_repository, &vbranch.head, files)?;
vb_state vb_state
.set_branch(vbranch.clone()) .set_branch(vbranch.clone())
.context(format!("failed to write virtual branch {}", vbranch.name))?; .context(format!("failed to write virtual branch {}", vbranch.name))?;
@ -200,11 +198,7 @@ pub fn get_applied_status(
let hunks_by_branch: Vec<(Branch, HashMap<PathBuf, Vec<VirtualBranchHunk>>)> = hunks_by_branch let hunks_by_branch: Vec<(Branch, HashMap<PathBuf, Vec<VirtualBranchHunk>>)> = hunks_by_branch
.iter() .iter()
.map(|(branch, hunks)| { .map(|(branch, hunks)| {
let hunks = file_hunks_from_diffs( let hunks = file_hunks_from_diffs(&ctx.project().path, hunks.clone(), Some(&locks));
&project_repository.project().path,
hunks.clone(),
Some(&locks),
);
(branch.clone(), hunks) (branch.clone(), hunks)
}) })
.collect(); .collect();
@ -212,7 +206,7 @@ pub fn get_applied_status(
let files_by_branch: Vec<(Branch, Vec<VirtualBranchFile>)> = hunks_by_branch let files_by_branch: Vec<(Branch, Vec<VirtualBranchFile>)> = hunks_by_branch
.iter() .iter()
.map(|(branch, hunks)| { .map(|(branch, hunks)| {
let files = virtual_hunks_into_virtual_files(project_repository, hunks.clone()); let files = virtual_hunks_into_virtual_files(ctx, hunks.clone());
(branch.clone(), files) (branch.clone(), files)
}) })
.collect(); .collect();

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
use anyhow::Result; use anyhow::Result;
use gitbutler_branch_actions::{list_branches, Author}; use gitbutler_branch_actions::{list_branches, Author};
use gitbutler_command_context::ProjectRepository; use gitbutler_command_context::CommandContext;
#[test] #[test]
fn on_main_single_branch_no_vbranch() -> Result<()> { fn on_main_single_branch_no_vbranch() -> Result<()> {
@ -128,6 +128,6 @@ fn default_author() -> Author {
} }
} }
fn project_ctx(name: &str) -> anyhow::Result<ProjectRepository> { fn project_ctx(name: &str) -> anyhow::Result<CommandContext> {
gitbutler_testsupport::read_only::fixture("for-listing.sh", name) gitbutler_testsupport::read_only::fixture("for-listing.sh", name)
} }

View File

@ -1,2 +1,2 @@
mod repository; mod repository;
pub use repository::ProjectRepository; pub use repository::CommandContext;

View File

@ -1,12 +1,12 @@
use anyhow::Result; use anyhow::Result;
use gitbutler_project::Project; use gitbutler_project::Project;
pub struct ProjectRepository { pub struct CommandContext {
git_repository: git2::Repository, git_repository: git2::Repository,
project: Project, project: Project,
} }
impl ProjectRepository { impl CommandContext {
pub fn open(project: &Project) -> Result<Self> { pub fn open(project: &Project) -> Result<Self> {
let repo = git2::Repository::open(&project.path)?; let repo = git2::Repository::open(&project.path)?;
@ -67,7 +67,7 @@ impl ProjectRepository {
&self.project &self.project
} }
pub fn repo(&self) -> &git2::Repository { pub fn repository(&self) -> &git2::Repository {
&self.git_repository &self.git_repository
} }
} }

View File

@ -5,7 +5,7 @@ use std::{borrow::Borrow, path::PathBuf};
use anyhow::{anyhow, Context, Result}; use anyhow::{anyhow, Context, Result};
use bstr::{BString, ByteSlice, ByteVec}; use bstr::{BString, ByteSlice, ByteVec};
use diffy::{apply_bytes as diffy_apply, Line, Patch}; use diffy::{apply_bytes as diffy_apply, Line, Patch};
use gitbutler_command_context::ProjectRepository; use gitbutler_command_context::CommandContext;
use hex::ToHex; use hex::ToHex;
use crate::GitHunk; use crate::GitHunk;
@ -14,18 +14,18 @@ use crate::GitHunk;
// constructs a tree from those changes on top of the target // constructs a tree from those changes on top of the target
// and writes it as a new tree for storage // and writes it as a new tree for storage
pub fn hunks_onto_oid<T>( pub fn hunks_onto_oid<T>(
project_repository: &ProjectRepository, ctx: &CommandContext,
target: &git2::Oid, target: &git2::Oid,
files: impl IntoIterator<Item = (impl Borrow<PathBuf>, impl Borrow<Vec<T>>)>, files: impl IntoIterator<Item = (impl Borrow<PathBuf>, impl Borrow<Vec<T>>)>,
) -> Result<git2::Oid> ) -> Result<git2::Oid>
where where
T: Into<GitHunk> + Clone, T: Into<GitHunk> + Clone,
{ {
hunks_onto_commit(project_repository, *target, files) hunks_onto_commit(ctx, *target, files)
} }
pub fn hunks_onto_commit<T>( pub fn hunks_onto_commit<T>(
project_repository: &ProjectRepository, ctx: &CommandContext,
commit_oid: git2::Oid, commit_oid: git2::Oid,
files: impl IntoIterator<Item = (impl Borrow<PathBuf>, impl Borrow<Vec<T>>)>, files: impl IntoIterator<Item = (impl Borrow<PathBuf>, impl Borrow<Vec<T>>)>,
) -> Result<git2::Oid> ) -> Result<git2::Oid>
@ -33,29 +33,29 @@ where
T: Into<GitHunk> + Clone, T: Into<GitHunk> + Clone,
{ {
// read the base sha into an index // read the base sha into an index
let git_repository: &git2::Repository = project_repository.repo(); let git_repository: &git2::Repository = ctx.repository();
let head_commit = git_repository.find_commit(commit_oid)?; let head_commit = git_repository.find_commit(commit_oid)?;
let base_tree = head_commit.tree()?; let base_tree = head_commit.tree()?;
hunks_onto_tree(project_repository, &base_tree, files) hunks_onto_tree(ctx, &base_tree, files)
} }
pub fn hunks_onto_tree<T>( pub fn hunks_onto_tree<T>(
project_repository: &ProjectRepository, ctx: &CommandContext,
base_tree: &git2::Tree, base_tree: &git2::Tree,
files: impl IntoIterator<Item = (impl Borrow<PathBuf>, impl Borrow<Vec<T>>)>, files: impl IntoIterator<Item = (impl Borrow<PathBuf>, impl Borrow<Vec<T>>)>,
) -> Result<git2::Oid> ) -> Result<git2::Oid>
where where
T: Into<GitHunk> + Clone, T: Into<GitHunk> + Clone,
{ {
let git_repository = project_repository.repo(); let git_repository = ctx.repository();
let mut builder = git2::build::TreeUpdateBuilder::new(); let mut builder = git2::build::TreeUpdateBuilder::new();
// now update the index with content in the working directory for each file // now update the index with content in the working directory for each file
for (rel_path, hunks) in files { for (rel_path, hunks) in files {
let rel_path = rel_path.borrow(); let rel_path = rel_path.borrow();
let hunks: Vec<GitHunk> = hunks.borrow().iter().map(|h| h.clone().into()).collect(); let hunks: Vec<GitHunk> = hunks.borrow().iter().map(|h| h.clone().into()).collect();
let full_path = project_repository.project().worktree_path().join(rel_path); let full_path = ctx.project().worktree_path().join(rel_path);
let is_submodule = full_path.is_dir() let is_submodule = full_path.is_dir()
&& hunks.len() == 1 && hunks.len() == 1
@ -102,7 +102,7 @@ where
// if the link target is inside the project repository, make it relative // if the link target is inside the project repository, make it relative
let link_target = link_target let link_target = link_target
.strip_prefix(project_repository.project().worktree_path()) .strip_prefix(ctx.project().worktree_path())
.unwrap_or(&link_target); .unwrap_or(&link_target);
let blob_oid = git_repository.blob( let blob_oid = git_repository.blob(
@ -193,7 +193,7 @@ where
// now write out the tree // now write out the tree
let tree_oid = builder let tree_oid = builder
.create_updated(project_repository.repo(), base_tree) .create_updated(ctx.repository(), base_tree)
.context("failed to write updated tree")?; .context("failed to write updated tree")?;
Ok(tree_oid) Ok(tree_oid)

View File

@ -1,6 +1,6 @@
use anyhow::Result; use anyhow::Result;
use bstr::BString; use bstr::BString;
use gitbutler_command_context::ProjectRepository; use gitbutler_command_context::CommandContext;
use gitbutler_project::Project; use gitbutler_project::Project;
use crate::{Config, RepositoryExt}; use crate::{Config, RepositoryExt};
@ -15,20 +15,22 @@ pub trait RepoCommands {
impl RepoCommands for Project { impl RepoCommands for Project {
fn get_local_config(&self, key: &str) -> Result<Option<String>> { fn get_local_config(&self, key: &str) -> Result<Option<String>> {
let project_repo = ProjectRepository::open(self)?; let ctx = CommandContext::open(self)?;
let config: Config = project_repo.repo().into(); let config: Config = ctx.repository().into();
config.get_local(key) config.get_local(key)
} }
fn set_local_config(&self, key: &str, value: &str) -> Result<()> { fn set_local_config(&self, key: &str, value: &str) -> Result<()> {
let project_repo = ProjectRepository::open(self)?; let ctx = CommandContext::open(self)?;
let config: Config = project_repo.repo().into(); let config: Config = ctx.repository().into();
config.set_local(key, value) config.set_local(key, value)
} }
fn check_signing_settings(&self) -> Result<bool> { fn check_signing_settings(&self) -> Result<bool> {
let repo = ProjectRepository::open(self)?; let repo = CommandContext::open(self)?;
let signed = repo.repo().sign_buffer(&BString::new("test".into()).into()); let signed = repo
.repository()
.sign_buffer(&BString::new("test".into()).into());
match signed { match signed {
Ok(_) => Ok(true), Ok(_) => Ok(true),
Err(e) => Err(e), Err(e) => Err(e),
@ -36,13 +38,13 @@ impl RepoCommands for Project {
} }
fn remotes(&self) -> Result<Vec<String>> { fn remotes(&self) -> Result<Vec<String>> {
let project_repository = ProjectRepository::open(self)?; let ctx = CommandContext::open(self)?;
project_repository.repo().remotes_as_string() ctx.repository().remotes_as_string()
} }
fn add_remote(&self, name: &str, url: &str) -> Result<()> { fn add_remote(&self, name: &str, url: &str) -> Result<()> {
let project_repository = ProjectRepository::open(self)?; let ctx = CommandContext::open(self)?;
project_repository.repo().remote(name, url)?; ctx.repository().remote(name, url)?;
Ok(()) Ok(())
} }
} }

View File

@ -1,7 +1,7 @@
use std::{path::PathBuf, str::FromStr, vec}; use std::{path::PathBuf, str::FromStr, vec};
use anyhow::Context; use anyhow::Context;
use gitbutler_command_context::ProjectRepository; use gitbutler_command_context::CommandContext;
use gitbutler_project::AuthKey; use gitbutler_project::AuthKey;
use gitbutler_url::{ConvertError, Scheme, Url}; use gitbutler_url::{ConvertError, Scheme, Url};
@ -81,10 +81,10 @@ pub enum HelpError {
impl Helper { impl Helper {
pub fn help<'a>( pub fn help<'a>(
&'a self, &'a self,
project_repository: &'a ProjectRepository, ctx: &'a CommandContext,
remote_name: &str, remote_name: &str,
) -> Result<Vec<(git2::Remote, Vec<Credential>)>, HelpError> { ) -> Result<Vec<(git2::Remote, Vec<Credential>)>, HelpError> {
let remote = project_repository.repo().find_remote(remote_name)?; let remote = ctx.repository().find_remote(remote_name)?;
let remote_url = Url::from_str(remote.url().ok_or(HelpError::NoUrlSet)?) let remote_url = Url::from_str(remote.url().ok_or(HelpError::NoUrlSet)?)
.context("failed to parse remote url")?; .context("failed to parse remote url")?;
@ -93,15 +93,13 @@ impl Helper {
return Ok(vec![(remote, vec![Credential::Noop])]); return Ok(vec![(remote, vec![Credential::Noop])]);
} }
match &project_repository.project().preferred_key { match &ctx.project().preferred_key {
AuthKey::Local { private_key_path } => { AuthKey::Local { private_key_path } => {
let ssh_remote = if remote_url.scheme == Scheme::Ssh { let ssh_remote = if remote_url.scheme == Scheme::Ssh {
Ok(remote) Ok(remote)
} else { } else {
let ssh_url = remote_url.as_ssh()?; let ssh_url = remote_url.as_ssh()?;
project_repository ctx.repository().remote_anonymous(&ssh_url.to_string())
.repo()
.remote_anonymous(&ssh_url.to_string())
}?; }?;
Ok(vec![( Ok(vec![(
@ -117,9 +115,9 @@ impl Helper {
Ok(remote) Ok(remote)
} else { } else {
let url = remote_url.as_https()?; let url = remote_url.as_https()?;
project_repository.repo().remote_anonymous(&url.to_string()) ctx.repository().remote_anonymous(&url.to_string())
}?; }?;
let flow = Self::https_flow(project_repository, &remote_url)? let flow = Self::https_flow(ctx, &remote_url)?
.into_iter() .into_iter()
.map(Credential::Https) .map(Credential::Https)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -133,13 +131,13 @@ impl Helper {
} }
fn https_flow( fn https_flow(
project_repository: &ProjectRepository, ctx: &CommandContext,
remote_url: &Url, remote_url: &Url,
) -> Result<Vec<HttpsCredential>, HelpError> { ) -> Result<Vec<HttpsCredential>, HelpError> {
let mut flow = vec![]; let mut flow = vec![];
let mut helper = git2::CredentialHelper::new(&remote_url.to_string()); let mut helper = git2::CredentialHelper::new(&remote_url.to_string());
let config = project_repository.repo().config()?; let config = ctx.repository().config()?;
helper.config(&config); helper.config(&config);
if let Some((username, password)) = helper.execute() { if let Some((username, password)) = helper.execute() {
flow.push(HttpsCredential::CredentialHelper { username, password }); flow.push(HttpsCredential::CredentialHelper { username, password });

View File

@ -1,6 +1,6 @@
use anyhow::{anyhow, Context, Result}; use anyhow::{anyhow, Context, Result};
use bstr::ByteSlice; use bstr::ByteSlice;
use gitbutler_command_context::ProjectRepository; use gitbutler_command_context::CommandContext;
use gitbutler_commit::{commit_ext::CommitExt, commit_headers::HasCommitHeaders}; use gitbutler_commit::{commit_ext::CommitExt, commit_headers::HasCommitHeaders};
use gitbutler_error::error::Marker; use gitbutler_error::error::Marker;
@ -10,21 +10,19 @@ use crate::{LogUntil, RepoActionsExt, RepositoryExt};
/// this function takes a commit range and generates a Vector of commit oids /// this function takes a commit range and generates a Vector of commit oids
/// and then passes them to `cherry_rebase_group` to rebase them onto the target commit /// and then passes them to `cherry_rebase_group` to rebase them onto the target commit
pub fn cherry_rebase( pub fn cherry_rebase(
project_repository: &ProjectRepository, ctx: &CommandContext,
target_commit_oid: git2::Oid, target_commit_oid: git2::Oid,
start_commit_oid: git2::Oid, start_commit_oid: git2::Oid,
end_commit_oid: git2::Oid, end_commit_oid: git2::Oid,
) -> Result<Option<git2::Oid>> { ) -> Result<Option<git2::Oid>> {
// get a list of the commits to rebase // get a list of the commits to rebase
let mut ids_to_rebase = let mut ids_to_rebase = ctx.l(end_commit_oid, LogUntil::Commit(start_commit_oid))?;
project_repository.l(end_commit_oid, LogUntil::Commit(start_commit_oid))?;
if ids_to_rebase.is_empty() { if ids_to_rebase.is_empty() {
return Ok(None); return Ok(None);
} }
let new_head_id = let new_head_id = cherry_rebase_group(ctx, target_commit_oid, &mut ids_to_rebase)?;
cherry_rebase_group(project_repository, target_commit_oid, &mut ids_to_rebase)?;
Ok(Some(new_head_id)) Ok(Some(new_head_id))
} }
@ -34,7 +32,7 @@ pub fn cherry_rebase(
/// the difference between this and a libgit2 based rebase is that this will successfully /// the difference between this and a libgit2 based rebase is that this will successfully
/// rebase empty commits (two commits with identical trees) /// rebase empty commits (two commits with identical trees)
pub fn cherry_rebase_group( pub fn cherry_rebase_group(
project_repository: &ProjectRepository, ctx: &CommandContext,
target_commit_oid: git2::Oid, target_commit_oid: git2::Oid,
ids_to_rebase: &mut [git2::Oid], ids_to_rebase: &mut [git2::Oid],
) -> Result<git2::Oid> { ) -> Result<git2::Oid> {
@ -42,22 +40,21 @@ pub fn cherry_rebase_group(
// now, rebase unchanged commits onto the new commit // now, rebase unchanged commits onto the new commit
let commits_to_rebase = ids_to_rebase let commits_to_rebase = ids_to_rebase
.iter() .iter()
.map(|oid| project_repository.repo().find_commit(oid.to_owned())) .map(|oid| ctx.repository().find_commit(oid.to_owned()))
.collect::<Result<Vec<_>, _>>() .collect::<Result<Vec<_>, _>>()
.context("failed to read commits to rebase")?; .context("failed to read commits to rebase")?;
let new_head_id = commits_to_rebase let new_head_id = commits_to_rebase
.into_iter() .into_iter()
.fold( .fold(
project_repository ctx.repository()
.repo()
.find_commit(target_commit_oid) .find_commit(target_commit_oid)
.context("failed to find new commit"), .context("failed to find new commit"),
|head, to_rebase| { |head, to_rebase| {
let head = head?; let head = head?;
let mut cherrypick_index = project_repository let mut cherrypick_index = ctx
.repo() .repository()
.cherrypick_commit(&to_rebase, &head, 0, None) .cherrypick_commit(&to_rebase, &head, 0, None)
.context("failed to cherry pick")?; .context("failed to cherry pick")?;
@ -66,18 +63,18 @@ pub fn cherry_rebase_group(
} }
let merge_tree_oid = cherrypick_index let merge_tree_oid = cherrypick_index
.write_tree_to(project_repository.repo()) .write_tree_to(ctx.repository())
.context("failed to write merge tree")?; .context("failed to write merge tree")?;
let merge_tree = project_repository let merge_tree = ctx
.repo() .repository()
.find_tree(merge_tree_oid) .find_tree(merge_tree_oid)
.context("failed to find merge tree")?; .context("failed to find merge tree")?;
let commit_headers = to_rebase.gitbutler_headers(); let commit_headers = to_rebase.gitbutler_headers();
let commit_oid = project_repository let commit_oid = ctx
.repo() .repository()
.commit_with_signature( .commit_with_signature(
None, None,
&to_rebase.author(), &to_rebase.author(),
@ -89,8 +86,7 @@ pub fn cherry_rebase_group(
) )
.context("failed to create commit")?; .context("failed to create commit")?;
project_repository ctx.repository()
.repo()
.find_commit(commit_oid) .find_commit(commit_oid)
.context("failed to find commit") .context("failed to find commit")
}, },

View File

@ -6,7 +6,7 @@ use gitbutler_branch::{
Branch, BranchId, GITBUTLER_INTEGRATION_COMMIT_AUTHOR_EMAIL, Branch, BranchId, GITBUTLER_INTEGRATION_COMMIT_AUTHOR_EMAIL,
GITBUTLER_INTEGRATION_COMMIT_AUTHOR_NAME, GITBUTLER_INTEGRATION_COMMIT_AUTHOR_NAME,
}; };
use gitbutler_command_context::ProjectRepository; use gitbutler_command_context::CommandContext;
use gitbutler_commit::commit_headers::CommitHeadersV2; use gitbutler_commit::commit_headers::CommitHeadersV2;
use gitbutler_error::error::Code; use gitbutler_error::error::Code;
use gitbutler_project::AuthKey; use gitbutler_project::AuthKey;
@ -49,7 +49,7 @@ pub trait RepoActionsExt {
fn signatures(&self) -> Result<(git2::Signature, git2::Signature)>; fn signatures(&self) -> Result<(git2::Signature, git2::Signature)>;
} }
impl RepoActionsExt for ProjectRepository { impl RepoActionsExt for CommandContext {
fn git_test_push( fn git_test_push(
&self, &self,
credentials: &Helper, credentials: &Helper,
@ -60,7 +60,7 @@ impl RepoActionsExt for ProjectRepository {
let target_branch_refname = let target_branch_refname =
Refname::from_str(&format!("refs/remotes/{}/{}", remote_name, branch_name))?; Refname::from_str(&format!("refs/remotes/{}/{}", remote_name, branch_name))?;
let branch = self let branch = self
.repo() .repository()
.find_branch_by_refname(&target_branch_refname)? .find_branch_by_refname(&target_branch_refname)?
.ok_or(anyhow!("failed to find branch {}", target_branch_refname))?; .ok_or(anyhow!("failed to find branch {}", target_branch_refname))?;
@ -94,8 +94,10 @@ impl RepoActionsExt for ProjectRepository {
} }
fn add_branch_reference(&self, branch: &Branch) -> Result<()> { fn add_branch_reference(&self, branch: &Branch) -> Result<()> {
let (should_write, with_force) = let (should_write, with_force) = match self
match self.repo().find_reference(&branch.refname().to_string()) { .repository()
.find_reference(&branch.refname().to_string())
{
Ok(reference) => match reference.target() { Ok(reference) => match reference.target() {
Some(head_oid) => Ok((head_oid != branch.head, true)), Some(head_oid) => Ok((head_oid != branch.head, true)),
None => Ok((true, true)), None => Ok((true, true)),
@ -108,7 +110,7 @@ impl RepoActionsExt for ProjectRepository {
.context("failed to lookup reference")?; .context("failed to lookup reference")?;
if should_write { if should_write {
self.repo() self.repository()
.reference( .reference(
&branch.refname().to_string(), &branch.refname().to_string(),
branch.head, branch.head,
@ -122,7 +124,10 @@ impl RepoActionsExt for ProjectRepository {
} }
fn delete_branch_reference(&self, branch: &Branch) -> Result<()> { fn delete_branch_reference(&self, branch: &Branch) -> Result<()> {
match self.repo().find_reference(&branch.refname().to_string()) { match self
.repository()
.find_reference(&branch.refname().to_string())
{
Ok(mut reference) => { Ok(mut reference) => {
reference reference
.delete() .delete()
@ -141,7 +146,10 @@ impl RepoActionsExt for ProjectRepository {
fn l(&self, from: git2::Oid, to: LogUntil) -> Result<Vec<git2::Oid>> { fn l(&self, from: git2::Oid, to: LogUntil) -> Result<Vec<git2::Oid>> {
match to { match to {
LogUntil::Commit(oid) => { LogUntil::Commit(oid) => {
let mut revwalk = self.repo().revwalk().context("failed to create revwalk")?; let mut revwalk = self
.repository()
.revwalk()
.context("failed to create revwalk")?;
revwalk revwalk
.push(from) .push(from)
.context(format!("failed to push {}", from))?; .context(format!("failed to push {}", from))?;
@ -153,7 +161,10 @@ impl RepoActionsExt for ProjectRepository {
.collect::<Result<Vec<_>, _>>() .collect::<Result<Vec<_>, _>>()
} }
LogUntil::Take(n) => { LogUntil::Take(n) => {
let mut revwalk = self.repo().revwalk().context("failed to create revwalk")?; let mut revwalk = self
.repository()
.revwalk()
.context("failed to create revwalk")?;
revwalk revwalk
.push(from) .push(from)
.context(format!("failed to push {}", from))?; .context(format!("failed to push {}", from))?;
@ -163,7 +174,10 @@ impl RepoActionsExt for ProjectRepository {
.collect::<Result<Vec<_>, _>>() .collect::<Result<Vec<_>, _>>()
} }
LogUntil::When(cond) => { LogUntil::When(cond) => {
let mut revwalk = self.repo().revwalk().context("failed to create revwalk")?; let mut revwalk = self
.repository()
.revwalk()
.context("failed to create revwalk")?;
revwalk revwalk
.push(from) .push(from)
.context(format!("failed to push {}", from))?; .context(format!("failed to push {}", from))?;
@ -173,7 +187,7 @@ impl RepoActionsExt for ProjectRepository {
oids.push(oid); oids.push(oid);
let commit = self let commit = self
.repo() .repository()
.find_commit(oid) .find_commit(oid)
.context("failed to find commit")?; .context("failed to find commit")?;
@ -184,7 +198,10 @@ impl RepoActionsExt for ProjectRepository {
Ok(oids) Ok(oids)
} }
LogUntil::End => { LogUntil::End => {
let mut revwalk = self.repo().revwalk().context("failed to create revwalk")?; let mut revwalk = self
.repository()
.revwalk()
.context("failed to create revwalk")?;
revwalk revwalk
.push(from) .push(from)
.context(format!("failed to push {}", from))?; .context(format!("failed to push {}", from))?;
@ -205,7 +222,7 @@ impl RepoActionsExt for ProjectRepository {
Ok(self Ok(self
.list(from, to)? .list(from, to)?
.into_iter() .into_iter()
.map(|oid| self.repo().find_commit(oid)) .map(|oid| self.repository().find_commit(oid))
.collect::<Result<Vec<_>, _>>()?) .collect::<Result<Vec<_>, _>>()?)
} }
@ -213,7 +230,7 @@ impl RepoActionsExt for ProjectRepository {
fn log(&self, from: git2::Oid, to: LogUntil) -> Result<Vec<git2::Commit>> { fn log(&self, from: git2::Oid, to: LogUntil) -> Result<Vec<git2::Commit>> {
self.l(from, to)? self.l(from, to)?
.into_iter() .into_iter()
.map(|oid| self.repo().find_commit(oid)) .map(|oid| self.repository().find_commit(oid))
.collect::<Result<Vec<_>, _>>() .collect::<Result<Vec<_>, _>>()
.context("failed to collect commits") .context("failed to collect commits")
} }
@ -232,7 +249,7 @@ impl RepoActionsExt for ProjectRepository {
commit_headers: Option<CommitHeadersV2>, commit_headers: Option<CommitHeadersV2>,
) -> Result<git2::Oid> { ) -> Result<git2::Oid> {
let (author, committer) = self.signatures().context("failed to get signatures")?; let (author, committer) = self.signatures().context("failed to get signatures")?;
self.repo() self.repository()
.commit_with_signature( .commit_with_signature(
None, None,
&author, &author,
@ -428,7 +445,7 @@ impl RepoActionsExt for ProjectRepository {
} }
fn signatures(&self) -> Result<(git2::Signature, git2::Signature)> { fn signatures(&self) -> Result<(git2::Signature, git2::Signature)> {
let repo = gix::open(self.repo().path())?; let repo = gix::open(self.repository().path())?;
let default_actor = gix::actor::SignatureRef { let default_actor = gix::actor::SignatureRef {
name: GITBUTLER_INTEGRATION_COMMIT_AUTHOR_NAME.into(), name: GITBUTLER_INTEGRATION_COMMIT_AUTHOR_NAME.into(),
@ -436,7 +453,7 @@ impl RepoActionsExt for ProjectRepository {
time: Default::default(), time: Default::default(),
}; };
let author = repo.author().transpose()?.unwrap_or(default_actor); let author = repo.author().transpose()?.unwrap_or(default_actor);
let config: Config = self.repo().into(); let config: Config = self.repository().into();
let committer = if config.user_real_comitter()? { let committer = if config.user_real_comitter()? {
repo.committer().transpose()?.unwrap_or(default_actor) repo.committer().transpose()?.unwrap_or(default_actor)
} else { } else {

View File

@ -1,6 +1,6 @@
use std::{path::PathBuf, str}; use std::{path::PathBuf, str};
use gitbutler_command_context::ProjectRepository; use gitbutler_command_context::CommandContext;
use gitbutler_project as projects; use gitbutler_project as projects;
use gitbutler_repo::credentials::{Credential, Helper, SshCredential}; use gitbutler_repo::credentials::{Credential, Helper, SshCredential};
use gitbutler_testsupport::{temp_dir, test_repository}; use gitbutler_testsupport::{temp_dir, test_repository};
@ -36,9 +36,9 @@ impl TestCase<'_> {
preferred_key: self.preferred_key.clone(), preferred_key: self.preferred_key.clone(),
..Default::default() ..Default::default()
}; };
let project_repository = ProjectRepository::open(&project).unwrap(); let ctx = CommandContext::open(&project).unwrap();
let flow = helper.help(&project_repository, "origin").unwrap(); let flow = helper.help(&ctx, "origin").unwrap();
flow.into_iter() flow.into_iter()
.map(|(remote, credentials)| (remote.url().as_ref().unwrap().to_string(), credentials)) .map(|(remote, credentials)| (remote.url().as_ref().unwrap().to_string(), credentials))
.collect::<Vec<_>>() .collect::<Vec<_>>()

View File

@ -5,7 +5,7 @@ use std::{
use anyhow::{anyhow, Context, Result}; use anyhow::{anyhow, Context, Result};
use gitbutler_branch::{Target, VirtualBranchesHandle}; use gitbutler_branch::{Target, VirtualBranchesHandle};
use gitbutler_command_context::ProjectRepository; use gitbutler_command_context::CommandContext;
use gitbutler_error::error::Code; use gitbutler_error::error::Code;
use gitbutler_id::id::Id; use gitbutler_id::id::Id;
use gitbutler_oplog::OplogExt; use gitbutler_oplog::OplogExt;
@ -17,11 +17,11 @@ use gitbutler_user as users;
use itertools::Itertools; use itertools::Itertools;
pub fn sync_with_gitbutler( pub fn sync_with_gitbutler(
project_repository: &ProjectRepository, ctx: &CommandContext,
user: &users::User, user: &users::User,
projects: &projects::Controller, projects: &projects::Controller,
) -> Result<()> { ) -> Result<()> {
let project = project_repository.project(); let project = ctx.project();
let vb_state = VirtualBranchesHandle::new(project.gb_dir()); let vb_state = VirtualBranchesHandle::new(project.gb_dir());
let default_target = vb_state.get_default_target()?; let default_target = vb_state.get_default_target()?;
let gb_code_last_commit = project let gb_code_last_commit = project
@ -33,7 +33,7 @@ pub fn sync_with_gitbutler(
// Push target // Push target
push_target( push_target(
projects, projects,
project_repository, ctx,
&default_target, &default_target,
gb_code_last_commit, gb_code_last_commit,
project.id, project.id,
@ -42,16 +42,16 @@ pub fn sync_with_gitbutler(
)?; )?;
// Push all refs // Push all refs
push_all_refs(project_repository, user, project.id)?; push_all_refs(ctx, user, project.id)?;
// Push Oplog head // Push Oplog head
let oplog_refspec = project_repository let oplog_refspec = ctx
.project() .project()
.oplog_head()? .oplog_head()?
.map(|sha| format!("+{}:refs/gitbutler/oplog/oplog", sha)); .map(|sha| format!("+{}:refs/gitbutler/oplog/oplog", sha));
if let Some(oplog_refspec) = oplog_refspec { if let Some(oplog_refspec) = oplog_refspec {
let x = push_to_gitbutler_server(project_repository, Some(user), &[&oplog_refspec]); let x = push_to_gitbutler_server(ctx, Some(user), &[&oplog_refspec]);
println!("\n\n\nHERE: {:?}", x?); println!("\n\n\nHERE: {:?}", x?);
} }
@ -60,7 +60,7 @@ pub fn sync_with_gitbutler(
fn push_target( fn push_target(
projects: &projects::Controller, projects: &projects::Controller,
project_repository: &ProjectRepository, ctx: &CommandContext,
default_target: &Target, default_target: &Target,
gb_code_last_commit: Option<git2::Oid>, gb_code_last_commit: Option<git2::Oid>,
project_id: Id<Project>, project_id: Id<Project>,
@ -68,7 +68,7 @@ fn push_target(
batch_size: usize, batch_size: usize,
) -> Result<()> { ) -> Result<()> {
let ids = batch_rev_walk( let ids = batch_rev_walk(
project_repository.repo(), ctx.repository(),
batch_size, batch_size,
default_target.sha, default_target.sha,
gb_code_last_commit, gb_code_last_commit,
@ -84,7 +84,7 @@ fn push_target(
for (idx, id) in ids.iter().enumerate().rev() { for (idx, id) in ids.iter().enumerate().rev() {
let refspec = format!("+{}:refs/push-tmp/{}", id, project_id); let refspec = format!("+{}:refs/push-tmp/{}", id, project_id);
push_to_gitbutler_server(project_repository, Some(user), &[&refspec])?; push_to_gitbutler_server(ctx, Some(user), &[&refspec])?;
update_project(projects, project_id, *id)?; update_project(projects, project_id, *id)?;
tracing::info!( tracing::info!(
@ -96,7 +96,7 @@ fn push_target(
} }
push_to_gitbutler_server( push_to_gitbutler_server(
project_repository, ctx,
Some(user), Some(user),
&[&format!("+{}:refs/{}", default_target.sha, project_id)], &[&format!("+{}:refs/{}", default_target.sha, project_id)],
)?; )?;
@ -137,9 +137,9 @@ fn batch_rev_walk(
Ok(oids) Ok(oids)
} }
fn collect_refs(project_repository: &ProjectRepository) -> anyhow::Result<Vec<Refname>> { fn collect_refs(ctx: &CommandContext) -> anyhow::Result<Vec<Refname>> {
Ok(project_repository Ok(ctx
.repo() .repository()
.references_glob("refs/*")? .references_glob("refs/*")?
.flatten() .flatten()
.filter_map(|r| { .filter_map(|r| {
@ -150,11 +150,11 @@ fn collect_refs(project_repository: &ProjectRepository) -> anyhow::Result<Vec<Re
} }
fn push_all_refs( fn push_all_refs(
project_repository: &ProjectRepository, ctx: &CommandContext,
user: &users::User, user: &users::User,
project_id: Id<projects::Project>, project_id: Id<projects::Project>,
) -> Result<()> { ) -> Result<()> {
let gb_references = collect_refs(project_repository)?; let gb_references = collect_refs(ctx)?;
let all_refs: Vec<_> = gb_references let all_refs: Vec<_> = gb_references
.iter() .iter()
.filter(|r| { .filter(|r| {
@ -168,7 +168,7 @@ fn push_all_refs(
let all_refs: Vec<_> = all_refs.iter().map(String::as_str).collect(); let all_refs: Vec<_> = all_refs.iter().map(String::as_str).collect();
let anything_pushed = push_to_gitbutler_server(project_repository, Some(user), &all_refs)?; let anything_pushed = push_to_gitbutler_server(ctx, Some(user), &all_refs)?;
if anything_pushed { if anything_pushed {
tracing::info!( tracing::info!(
%project_id, %project_id,
@ -196,11 +196,11 @@ fn update_project(
} }
fn push_to_gitbutler_server( fn push_to_gitbutler_server(
project_repo: &ProjectRepository, ctx: &CommandContext,
user: Option<&users::User>, user: Option<&users::User>,
ref_specs: &[&str], ref_specs: &[&str],
) -> Result<bool> { ) -> Result<bool> {
let project = project_repo.project(); let project = ctx.project();
let url = project let url = project
.api .api
.as_ref() .as_ref()
@ -243,7 +243,7 @@ fn push_to_gitbutler_server(
let headers = &[auth_header.as_str()]; let headers = &[auth_header.as_str()];
push_options.custom_headers(headers); push_options.custom_headers(headers);
let mut remote = project_repo.repo().remote_anonymous(&url.to_string())?; let mut remote = ctx.repository().remote_anonymous(&url.to_string())?;
remote remote
.push(ref_specs, Some(&mut push_options)) .push(ref_specs, Some(&mut push_options))

View File

@ -3,7 +3,7 @@ use std::path::PathBuf;
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use gitbutler_branch::BranchId; use gitbutler_branch::BranchId;
use gitbutler_branch_actions::conflicts; use gitbutler_branch_actions::conflicts;
use gitbutler_command_context::ProjectRepository; use gitbutler_command_context::CommandContext;
use gitbutler_project as projects; use gitbutler_project as projects;
use gitbutler_project::ProjectId; use gitbutler_project::ProjectId;
use gitbutler_reference::RemoteRefname; use gitbutler_reference::RemoteRefname;
@ -28,16 +28,16 @@ impl App {
impl App { impl App {
pub fn mark_resolved(&self, project_id: ProjectId, path: &str) -> Result<()> { pub fn mark_resolved(&self, project_id: ProjectId, path: &str) -> Result<()> {
let project = self.projects().get(project_id)?; let project = self.projects().get(project_id)?;
let project_repository = ProjectRepository::open(&project)?; let ctx = CommandContext::open(&project)?;
// mark file as resolved // mark file as resolved
conflicts::resolve(&project_repository, path)?; conflicts::resolve(&ctx, path)?;
Ok(()) Ok(())
} }
pub fn git_remote_branches(&self, project_id: ProjectId) -> Result<Vec<RemoteRefname>> { pub fn git_remote_branches(&self, project_id: ProjectId) -> Result<Vec<RemoteRefname>> {
let project = self.projects().get(project_id)?; let project = self.projects().get(project_id)?;
let project_repository = ProjectRepository::open(&project)?; let ctx = CommandContext::open(&project)?;
project_repository.repo().remote_branches() ctx.repository().remote_branches()
} }
pub fn git_test_push( pub fn git_test_push(
@ -49,8 +49,8 @@ impl App {
askpass: Option<Option<BranchId>>, askpass: Option<Option<BranchId>>,
) -> Result<()> { ) -> Result<()> {
let project = self.projects().get(project_id)?; let project = self.projects().get(project_id)?;
let project_repository = ProjectRepository::open(&project)?; let ctx = CommandContext::open(&project)?;
project_repository.git_test_push(credentials, remote_name, branch_name, askpass) ctx.git_test_push(credentials, remote_name, branch_name, askpass)
} }
pub fn git_test_fetch( pub fn git_test_fetch(
@ -61,15 +61,15 @@ impl App {
askpass: Option<String>, askpass: Option<String>,
) -> Result<()> { ) -> Result<()> {
let project = self.projects().get(project_id)?; let project = self.projects().get(project_id)?;
let project_repository = ProjectRepository::open(&project)?; let ctx = CommandContext::open(&project)?;
project_repository.fetch(remote_name, credentials, askpass) ctx.fetch(remote_name, credentials, askpass)
} }
pub fn git_index_size(&self, project_id: ProjectId) -> Result<usize> { pub fn git_index_size(&self, project_id: ProjectId) -> Result<usize> {
let project = self.projects().get(project_id)?; let project = self.projects().get(project_id)?;
let project_repository = ProjectRepository::open(&project)?; let ctx = CommandContext::open(&project)?;
let size = project_repository let size = ctx
.repo() .repository()
.index() .index()
.context("failed to get index size")? .context("failed to get index size")?
.len(); .len();
@ -78,9 +78,9 @@ impl App {
pub fn git_head(&self, project_id: ProjectId) -> Result<String> { pub fn git_head(&self, project_id: ProjectId) -> Result<String> {
let project = self.projects().get(project_id)?; let project = self.projects().get(project_id)?;
let project_repository = ProjectRepository::open(&project)?; let ctx = CommandContext::open(&project)?;
let head = project_repository let head = ctx
.repo() .repository()
.head() .head()
.context("failed to get repository head")?; .context("failed to get repository head")?;
Ok(head.name().unwrap().to_string()) Ok(head.name().unwrap().to_string())

View File

@ -7,7 +7,7 @@ pub mod commands {
BaseBranch, BranchListing, BranchListingDetails, BranchListingFilter, RemoteBranch, BaseBranch, BranchListing, BranchListingDetails, BranchListingFilter, RemoteBranch,
RemoteBranchData, RemoteBranchFile, VirtualBranchActions, VirtualBranches, RemoteBranchData, RemoteBranchFile, VirtualBranchActions, VirtualBranches,
}; };
use gitbutler_command_context::ProjectRepository; use gitbutler_command_context::CommandContext;
use gitbutler_error::error::Code; use gitbutler_error::error::Code;
use gitbutler_project as projects; use gitbutler_project as projects;
use gitbutler_project::{FetchResult, ProjectId}; use gitbutler_project::{FetchResult, ProjectId};
@ -416,7 +416,7 @@ pub mod commands {
project_id: ProjectId, project_id: ProjectId,
filter: Option<BranchListingFilter>, filter: Option<BranchListingFilter>,
) -> Result<Vec<BranchListing>, Error> { ) -> Result<Vec<BranchListing>, Error> {
let ctx = ProjectRepository::open(&projects.get(project_id)?)?; let ctx = CommandContext::open(&projects.get(project_id)?)?;
let branches = gitbutler_branch_actions::list_branches(&ctx, filter)?; let branches = gitbutler_branch_actions::list_branches(&ctx, filter)?;
Ok(branches) Ok(branches)
} }
@ -428,7 +428,7 @@ pub mod commands {
project_id: ProjectId, project_id: ProjectId,
branch_names: Vec<String>, branch_names: Vec<String>,
) -> Result<Vec<BranchListingDetails>, Error> { ) -> Result<Vec<BranchListingDetails>, Error> {
let ctx = ProjectRepository::open(&projects.get(project_id)?)?; let ctx = CommandContext::open(&projects.get(project_id)?)?;
let branches = gitbutler_branch_actions::get_branch_listing_details(&ctx, branch_names)?; let branches = gitbutler_branch_actions::get_branch_listing_details(&ctx, branch_names)?;
Ok(branches) Ok(branches)
} }

View File

@ -19,15 +19,15 @@ pub mod paths {
pub mod virtual_branches { pub mod virtual_branches {
use gitbutler_branch::{Target, VirtualBranchesHandle}; use gitbutler_branch::{Target, VirtualBranchesHandle};
use gitbutler_command_context::ProjectRepository; use gitbutler_command_context::CommandContext;
use crate::empty_bare_repository; use crate::empty_bare_repository;
pub fn set_test_target(project_repository: &ProjectRepository) -> anyhow::Result<()> { pub fn set_test_target(ctx: &CommandContext) -> anyhow::Result<()> {
let vb_state = VirtualBranchesHandle::new(project_repository.project().gb_dir()); let vb_state = VirtualBranchesHandle::new(ctx.project().gb_dir());
let (remote_repo, _tmp) = empty_bare_repository(); let (remote_repo, _tmp) = empty_bare_repository();
let mut remote = project_repository let mut remote = ctx
.repo() .repository()
.remote("origin", remote_repo.path().to_str().unwrap()) .remote("origin", remote_repo.path().to_str().unwrap())
.expect("failed to add remote"); .expect("failed to add remote");
remote.push(&["refs/heads/master:refs/heads/master"], None)?; remote.push(&["refs/heads/master:refs/heads/master"], None)?;
@ -41,7 +41,7 @@ pub mod virtual_branches {
}) })
.expect("failed to write target"); .expect("failed to write target");
gitbutler_branch_actions::update_gitbutler_integration(&vb_state, project_repository) gitbutler_branch_actions::update_gitbutler_integration(&vb_state, ctx)
.expect("failed to update integration"); .expect("failed to update integration");
Ok(()) Ok(())
@ -66,7 +66,7 @@ pub mod read_only {
path::{Path, PathBuf}, path::{Path, PathBuf},
}; };
use gitbutler_command_context::ProjectRepository; use gitbutler_command_context::CommandContext;
use gitbutler_project::{Project, ProjectId}; use gitbutler_project::{Project, ProjectId};
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use parking_lot::Mutex; use parking_lot::Mutex;
@ -102,10 +102,7 @@ pub mod read_only {
/// the output of `script_name`. /// the output of `script_name`.
/// ///
/// Returns the project that is strictly for read-only use. /// Returns the project that is strictly for read-only use.
pub fn fixture( pub fn fixture(script_name: &str, project_directory: &str) -> anyhow::Result<CommandContext> {
script_name: &str,
project_directory: &str,
) -> anyhow::Result<ProjectRepository> {
static IS_VALID_PROJECT: Lazy<Mutex<BTreeSet<(String, String)>>> = static IS_VALID_PROJECT: Lazy<Mutex<BTreeSet<(String, String)>>> =
Lazy::new(|| Mutex::new(Default::default())); Lazy::new(|| Mutex::new(Default::default()));
@ -131,7 +128,7 @@ pub mod read_only {
..Default::default() ..Default::default()
} }
}; };
ProjectRepository::open(&project) CommandContext::open(&project)
} }
} }

View File

@ -4,7 +4,7 @@ use std::{
path::{Path, PathBuf}, path::{Path, PathBuf},
}; };
use gitbutler_command_context::ProjectRepository; use gitbutler_command_context::CommandContext;
use gitbutler_repo::{credentials::Helper, RepositoryExt}; use gitbutler_repo::{credentials::Helper, RepositoryExt};
use tempfile::{tempdir, TempDir}; use tempfile::{tempdir, TempDir};
@ -88,9 +88,9 @@ impl Suite {
pub struct Case { pub struct Case {
pub project: gitbutler_project::Project, pub project: gitbutler_project::Project,
pub project_repository: ProjectRepository, pub ctx: CommandContext,
pub credentials: Helper, pub credentials: Helper,
/// The directory containing the `project_repository` /// The directory containing the `ctx`
project_tmp: Option<TempDir>, project_tmp: Option<TempDir>,
} }
@ -108,12 +108,11 @@ impl Drop for Case {
impl Case { impl Case {
fn new(project: gitbutler_project::Project, project_tmp: TempDir) -> Case { fn new(project: gitbutler_project::Project, project_tmp: TempDir) -> Case {
let project_repository = let ctx = CommandContext::open(&project).expect("failed to create project repository");
ProjectRepository::open(&project).expect("failed to create project repository");
let credentials = Helper::default(); let credentials = Helper::default();
Case { Case {
project, project,
project_repository, ctx,
project_tmp: Some(project_tmp), project_tmp: Some(project_tmp),
credentials, credentials,
} }
@ -124,12 +123,11 @@ impl Case {
.projects .projects
.get(self.project.id) .get(self.project.id)
.expect("failed to get project"); .expect("failed to get project");
let project_repository = let ctx = CommandContext::open(&project).expect("failed to create project repository");
ProjectRepository::open(&project).expect("failed to create project repository");
let credentials = Helper::default(); let credentials = Helper::default();
Self { Self {
credentials, credentials,
project_repository, ctx,
project, project,
project_tmp: self.project_tmp.take(), project_tmp: self.project_tmp.take(),
} }

View File

@ -2,7 +2,7 @@ use std::{path::PathBuf, sync::Arc};
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use gitbutler_branch_actions::{VirtualBranchActions, VirtualBranches}; use gitbutler_branch_actions::{VirtualBranchActions, VirtualBranches};
use gitbutler_command_context::ProjectRepository; use gitbutler_command_context::CommandContext;
use gitbutler_error::error::Marker; use gitbutler_error::error::Marker;
use gitbutler_oplog::{ use gitbutler_oplog::{
entry::{OperationKind, SnapshotDetails}, entry::{OperationKind, SnapshotDetails},
@ -136,7 +136,7 @@ impl Handler {
.get(project_id) .get(project_id)
.context("failed to get project")?; .context("failed to get project")?;
let open_projects_repository = || { let open_projects_repository = || {
ProjectRepository::open(&project.clone()) CommandContext::open(&project.clone())
.context("failed to open project repository for project") .context("failed to open project repository for project")
}; };
@ -152,14 +152,11 @@ impl Handler {
self.emit_app_event(Change::GitActivity(project.id))?; self.emit_app_event(Change::GitActivity(project.id))?;
} }
"HEAD" => { "HEAD" => {
let project_repository = open_projects_repository()?; let ctx = open_projects_repository()?;
let head_ref = project_repository let head_ref = ctx.repository().head().context("failed to get head")?;
.repo()
.head()
.context("failed to get head")?;
let head_ref_name = head_ref.name().context("failed to get head name")?; let head_ref_name = head_ref.name().context("failed to get head name")?;
if head_ref_name != "refs/heads/gitbutler/integration" { if head_ref_name != "refs/heads/gitbutler/integration" {
let mut integration_reference = project_repository.repo().find_reference( let mut integration_reference = ctx.repository().find_reference(
&Refname::from(LocalRefname::new("gitbutler/integration", None)) &Refname::from(LocalRefname::new("gitbutler/integration", None))
.to_string(), .to_string(),
)?; )?;
@ -188,7 +185,7 @@ impl Handler {
if project.is_sync_enabled() && project.has_code_url() { if project.is_sync_enabled() && project.has_code_url() {
if let Some(user) = self.users.get_user()? { if let Some(user) = self.users.get_user()? {
let repository = ProjectRepository::open(&project) let repository = CommandContext::open(&project)
.context("failed to open project repository for project")?; .context("failed to open project repository for project")?;
return sync_with_gitbutler(&repository, &user, &self.projects); return sync_with_gitbutler(&repository, &user, &self.projects);
} }