Skip to content

Commit 2c7773a

Browse files
authored
Merge pull request #4793 from Byron/git2-to-gix
performance improvements and bug fixes
2 parents 717078d + 4d495cb commit 2c7773a

File tree

26 files changed

+268
-148
lines changed

26 files changed

+268
-148
lines changed

apps/desktop/src/lib/stores/remoteBranches.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export class RemoteBranchService {
2121
try {
2222
const remoteBranches = plainToInstance(
2323
Branch,
24-
await invoke<any[]>('list_remote_branches', { projectId: this.projectId })
24+
await invoke<any[]>('list_local_branches', { projectId: this.projectId })
2525
);
2626
this.projectMetrics?.setMetric('normal_branch_count', remoteBranches.length);
2727
this.branches.set(remoteBranches);

apps/desktop/src/lib/vbranches/types.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,13 +179,19 @@ export class DetailedCommit {
179179
conflicted!: boolean;
180180
// Set if a GitButler branch reference pointing to this commit exists. In the format of "refs/remotes/origin/my-branch"
181181
remoteRef?: string | undefined;
182+
// Identifies the remote commit id from which this local commit was copied. The backend figured this out by comparing
183+
// author, commit and message.
184+
copiedFromRemoteId?: string;
182185

183186
prev?: DetailedCommit;
184187
next?: DetailedCommit;
185188

186189
get status(): CommitStatus {
187190
if (this.isIntegrated) return 'integrated';
188-
if (this.isRemote && (!this.relatedTo || this.id === this.relatedTo.id))
191+
if (
192+
(this.isRemote && (!this.relatedTo || this.id === this.relatedTo.id)) ||
193+
(this.copiedFromRemoteId && this.relatedTo && this.copiedFromRemoteId === this.relatedTo.id)
194+
)
189195
return 'localAndRemote';
190196
return 'local';
191197
}
@@ -240,9 +246,10 @@ export class Commit {
240246

241247
export type AnyCommit = DetailedCommit | Commit;
242248

243-
export function commitCompare(left: AnyCommit, right: AnyCommit): boolean {
249+
export function commitCompare(left: AnyCommit, right: DetailedCommit): boolean {
244250
if (left.id === right.id) return true;
245251
if (left.changeId && right.changeId && left.changeId === right.changeId) return true;
252+
if (right.copiedFromRemoteId && right.copiedFromRemoteId === left.id) return true;
246253
return false;
247254
}
248255

crates/gitbutler-branch-actions/src/actions.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crate::{
88
branch::get_uncommited_files,
99
branch_manager::BranchManagerExt,
1010
file::RemoteBranchFile,
11-
remote::{get_branch_data, list_remote_branches, RemoteBranch, RemoteBranchData},
11+
remote::{get_branch_data, list_local_branches, RemoteBranch, RemoteBranchData},
1212
VirtualBranchesExt,
1313
};
1414
use anyhow::{Context, Result};
@@ -485,9 +485,9 @@ impl VirtualBranchActions {
485485
branch::push(&ctx, branch_id, with_force, &helper, askpass)
486486
}
487487

488-
pub fn list_remote_branches(project: Project) -> Result<Vec<RemoteBranch>> {
488+
pub fn list_local_branches(project: Project) -> Result<Vec<RemoteBranch>> {
489489
let ctx = CommandContext::open(&project)?;
490-
list_remote_branches(&ctx)
490+
list_local_branches(&ctx)
491491
}
492492

493493
pub fn get_remote_branch_data(
@@ -581,6 +581,7 @@ impl VirtualBranchActions {
581581
branch::move_commit(&ctx, target_branch_id, commit_oid).map_err(Into::into)
582582
}
583583

584+
#[instrument(level = tracing::Level::DEBUG, skip(self, project), err(Debug))]
584585
pub fn create_virtual_branch_from_branch(
585586
&self,
586587
project: &Project,

crates/gitbutler-branch-actions/src/base.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ pub(crate) fn set_base_branch(
181181
// if there are any commits on the head branch or uncommitted changes in the working directory, we need to
182182
// put them into a virtual branch
183183

184-
let wd_diff = gitbutler_diff::workdir(repo, &current_head_commit.id())?;
184+
let wd_diff = gitbutler_diff::workdir(repo, current_head_commit.id())?;
185185
if !wd_diff.is_empty() || current_head_commit.id() != target.sha {
186186
// assign ownership to the branch
187187
let ownership = wd_diff.iter().fold(

crates/gitbutler-branch-actions/src/branch.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::integration::get_workspace_head;
12
use crate::{RemoteBranchFile, VirtualBranchesExt};
23
use anyhow::{bail, Context, Result};
34
use bstr::{BStr, ByteSlice};
@@ -9,7 +10,7 @@ use gitbutler_command_context::CommandContext;
910
use gitbutler_diff::DiffByPathMap;
1011
use gitbutler_project::access::WorktreeReadPermission;
1112
use gitbutler_reference::normalize_branch_name;
12-
use gitbutler_repo::{GixRepositoryExt, RepositoryExt};
13+
use gitbutler_repo::GixRepositoryExt;
1314
use gitbutler_serde::BStringForFrontend;
1415
use gix::object::tree::diff::Action;
1516
use gix::prelude::ObjectIdExt;
@@ -23,14 +24,14 @@ use std::{
2324
fmt::Debug,
2425
vec,
2526
};
27+
use tracing::instrument;
2628

29+
#[instrument(level = tracing::Level::DEBUG, skip(ctx, _permission))]
2730
pub(crate) fn get_uncommited_files_raw(
28-
context: &CommandContext,
31+
ctx: &CommandContext,
2932
_permission: &WorktreeReadPermission,
3033
) -> Result<DiffByPathMap> {
31-
let repository = context.repository();
32-
let head_commit = repository.head_commit()?;
33-
gitbutler_diff::workdir(repository, &head_commit.id())
34+
gitbutler_diff::workdir(ctx.repository(), get_workspace_head(ctx)?)
3435
.context("Failed to list uncommited files")
3536
}
3637

crates/gitbutler-branch-actions/src/branch_manager/branch_creation.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use gitbutler_project::access::WorktreeWritePermission;
99
use gitbutler_reference::{Refname, RemoteRefname};
1010
use gitbutler_repo::{rebase::cherry_rebase, RepoActionsExt, RepositoryExt};
1111
use gitbutler_time::time::now_since_unix_epoch_ms;
12+
use tracing::instrument;
1213

1314
use super::BranchManager;
1415
use crate::{
@@ -20,6 +21,7 @@ use crate::{
2021
};
2122

2223
impl BranchManager<'_> {
24+
#[instrument(level = tracing::Level::DEBUG, skip(self, perm), err(Debug))]
2325
pub fn create_virtual_branch(
2426
&self,
2527
create: &BranchCreateRequest,
@@ -281,6 +283,7 @@ impl BranchManager<'_> {
281283

282284
/// Holding private methods associated to branch creation
283285
impl BranchManager<'_> {
286+
#[instrument(level = tracing::Level::DEBUG, skip(self, perm), err(Debug))]
284287
fn apply_branch(
285288
&self,
286289
branch_id: BranchId,
@@ -310,6 +313,7 @@ impl BranchManager<'_> {
310313
default_target.sha, branch.head
311314
))?;
312315
if merge_base != default_target.sha {
316+
let _span = tracing::debug_span!("merge-base isn't default-target").entered();
313317
// Branch is out of date, merge or rebase it
314318
let merge_base_tree = repo
315319
.find_commit(merge_base)
@@ -454,6 +458,8 @@ impl BranchManager<'_> {
454458
vb_state.set_branch(branch.clone())?;
455459
}
456460

461+
let _span = tracing::debug_span!("finalize").entered();
462+
457463
let wd_tree = self.ctx.repository().create_wd_tree()?;
458464

459465
let branch_tree = repo

crates/gitbutler-branch-actions/src/branch_manager/branch_removal.rs

Lines changed: 35 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use gitbutler_oplog::SnapshotExt;
88
use gitbutler_project::access::WorktreeWritePermission;
99
use gitbutler_reference::{normalize_branch_name, ReferenceName, Refname};
1010
use gitbutler_repo::{RepoActionsExt, RepositoryExt};
11+
use tracing::instrument;
1112

1213
use super::BranchManager;
1314
use crate::{
@@ -19,6 +20,7 @@ use crate::{
1920

2021
impl BranchManager<'_> {
2122
// to unapply a branch, we need to write the current tree out, then remove those file changes from the wd
23+
#[instrument(level = tracing::Level::DEBUG, skip(self, perm), err(Debug))]
2224
pub fn convert_to_real_branch(
2325
&self,
2426
branch_id: BranchId,
@@ -52,6 +54,7 @@ impl BranchManager<'_> {
5254
real_branch.reference_name()
5355
}
5456

57+
#[instrument(level = tracing::Level::DEBUG, skip(self, perm), err(Debug))]
5558
pub(crate) fn delete_branch(
5659
&self,
5760
branch_id: BranchId,
@@ -88,30 +91,38 @@ impl BranchManager<'_> {
8891

8992
// go through the other applied branches and merge them into the final tree
9093
// then check that out into the working directory
91-
let final_tree = applied_statuses
92-
.into_iter()
93-
.filter(|(branch, _)| branch.id != branch_id)
94-
.fold(
95-
target_commit.tree().context("failed to get target tree"),
96-
|final_tree, status| {
97-
let final_tree = final_tree?;
98-
let branch = status.0;
99-
let files = status
100-
.1
101-
.into_iter()
102-
.map(|file| (file.path, file.hunks))
103-
.collect::<Vec<(PathBuf, Vec<VirtualBranchHunk>)>>();
104-
let tree_oid =
105-
gitbutler_diff::write::hunks_onto_oid(self.ctx, &branch.head, files)?;
106-
let branch_tree = repo.find_tree(tree_oid)?;
107-
let mut result =
108-
repo.merge_trees(&base_tree, &final_tree, &branch_tree, None)?;
109-
let final_tree_oid = result.write_tree_to(repo)?;
110-
repo.find_tree(final_tree_oid)
111-
.context("failed to find tree")
112-
},
113-
)?;
94+
let final_tree = {
95+
let _span = tracing::debug_span!(
96+
"new tree without deleted branch",
97+
num_branches = applied_statuses.len() - 1
98+
)
99+
.entered();
100+
applied_statuses
101+
.into_iter()
102+
.filter(|(branch, _)| branch.id != branch_id)
103+
.fold(
104+
target_commit.tree().context("failed to get target tree"),
105+
|final_tree, status| {
106+
let final_tree = final_tree?;
107+
let branch = status.0;
108+
let files = status
109+
.1
110+
.into_iter()
111+
.map(|file| (file.path, file.hunks))
112+
.collect::<Vec<(PathBuf, Vec<VirtualBranchHunk>)>>();
113+
let tree_oid =
114+
gitbutler_diff::write::hunks_onto_oid(self.ctx, branch.head, files)?;
115+
let branch_tree = repo.find_tree(tree_oid)?;
116+
let mut result =
117+
repo.merge_trees(&base_tree, &final_tree, &branch_tree, None)?;
118+
let final_tree_oid = result.write_tree_to(repo)?;
119+
repo.find_tree(final_tree_oid)
120+
.context("failed to find tree")
121+
},
122+
)?
123+
};
114124

125+
let _span = tracing::debug_span!("checkout final tree").entered();
115126
// checkout final_tree into the working directory
116127
repo.checkout_tree_builder(&final_tree)
117128
.force()
@@ -128,6 +139,7 @@ impl BranchManager<'_> {
128139
}
129140

130141
impl BranchManager<'_> {
142+
#[instrument(level = tracing::Level::DEBUG, skip(self, vbranch), err(Debug))]
131143
fn build_real_branch(&self, vbranch: &mut Branch) -> Result<git2::Branch<'_>> {
132144
let repo = self.ctx.repository();
133145
let target_commit = repo.find_commit(vbranch.head)?;

crates/gitbutler-branch-actions/src/commit.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ pub struct VirtualBranchCommit {
3636
pub change_id: Option<String>,
3737
pub is_signed: bool,
3838
pub conflicted: bool,
39+
/// The id of the remote commit from which this one was copied, as identified by
40+
/// having equal author, committer, and commit message.
41+
/// This is used by the frontend similar to the `change_id` to group matching commits.
42+
#[serde(with = "gitbutler_serde::oid_opt")]
43+
pub copied_from_remote_id: Option<git2::Oid>,
3944
pub remote_ref: Option<ReferenceName>,
4045
}
4146

@@ -45,6 +50,7 @@ pub(crate) fn commit_to_vbranch_commit(
4550
commit: &git2::Commit,
4651
is_integrated: bool,
4752
is_remote: bool,
53+
copied_from_remote_id: Option<git2::Oid>,
4854
) -> Result<VirtualBranchCommit> {
4955
let timestamp = u128::try_from(commit.time().seconds())?;
5056
let message = commit.message_bstr().to_owned();
@@ -81,6 +87,7 @@ pub(crate) fn commit_to_vbranch_commit(
8187
change_id: commit.change_id(),
8288
is_signed: commit.is_signed(),
8389
conflicted: commit.is_conflicted(),
90+
copied_from_remote_id,
8491
remote_ref,
8592
};
8693

crates/gitbutler-branch-actions/src/integration.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ fn write_integration_file(head: &git2::Reference, path: PathBuf) -> Result<()> {
122122
std::fs::write(path, format!(":{}", sha))?;
123123
Ok(())
124124
}
125+
#[instrument(level = tracing::Level::DEBUG, skip(vb_state, ctx), err(Debug))]
125126
pub fn update_gitbutler_integration(
126127
vb_state: &VirtualBranchesHandle,
127128
ctx: &CommandContext,

crates/gitbutler-branch-actions/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ mod file;
1818
pub use file::{Get, RemoteBranchFile};
1919

2020
mod remote;
21-
pub use remote::{list_remote_branches, RemoteBranch, RemoteBranchData, RemoteCommit};
21+
pub use remote::{list_local_branches, RemoteBranch, RemoteBranchData, RemoteCommit};
2222

2323
pub mod conflicts;
2424

0 commit comments

Comments
 (0)