mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-12-23 09:33:01 +03:00
Merge pull request #4523 from gitbutlerapp/Boosting-my-contribution-score
Boosting my contribution score
This commit is contained in:
commit
d37dcefdf5
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
|
@ -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()
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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())?;
|
||||||
|
@ -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,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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));
|
||||||
|
@ -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
|
||||||
))?;
|
))?;
|
||||||
|
@ -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")?;
|
||||||
|
|
||||||
|
@ -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
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
mod repository;
|
mod repository;
|
||||||
pub use repository::ProjectRepository;
|
pub use repository::CommandContext;
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 });
|
||||||
|
@ -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")
|
||||||
},
|
},
|
||||||
|
@ -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 {
|
||||||
|
@ -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<_>>()
|
||||||
|
@ -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))
|
||||||
|
@ -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())
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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(),
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user