Skip to content

Commit 431570d

Browse files
committed
Reapply "Merge pull request #4771 from Byron/git2-to-gix"
This reverts commit e2d3718.
1 parent e2d3718 commit 431570d

File tree

33 files changed

+387
-244
lines changed

33 files changed

+387
-244
lines changed

Cargo.lock

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,8 @@ codegen-units = 1 # Compile crates one after another so the compiler can optimiz
9090
lto = true # Enables link to optimizations
9191
opt-level = "s" # Optimize for binary size
9292
debug = true # Enable debug symbols, for profiling
93+
94+
[profile.bench]
95+
codegen-units = 256
96+
lto = false
97+
opt-level = 3

DEVELOPMENT.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,29 @@ The app writes logs into:
132132
1. `stdout` in development mode
133133
2. The Tauri [logs](https://tauri.app/v1/api/js/path/#platform-specific) directory
134134

135+
One can get performance log when launching the application locally as follows:
136+
137+
```bash
138+
GITBUTLER_PERFORMANCE_LOG=1 LOG_LEVEL=debug pnpm tauri dev
139+
```
140+
141+
For more realistic performance logging, use local release builds with `--release`.
142+
143+
```bash
144+
GITBUTLER_PERFORMANCE_LOG=1 LOG_LEVEL=debug pnpm tauri dev --release
145+
```
146+
147+
Since release builds are configured for public releases, they are very slow to compile.
148+
Speed them up by sourcing the following file.
149+
150+
```bash
151+
export CARGO_PROFILE_RELEASE_DEBUG=0
152+
export CARGO_PROFILE_RELEASE_INCREMENTAL=false
153+
export CARGO_PROFILE_RELEASE_LTO=false
154+
export CARGO_PROFILE_RELEASE_CODEGEN_UNITS=256
155+
export CARGO_PROFILE_RELEASE_OPT_LEVEL=2
156+
```
157+
135158
### Tokio
136159

137160
We are also collecting tokio's runtime tracing information that could be viewed using [tokio-console](https://github.com/tokio-rs/console#tokio-console-prototypes):

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

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,22 @@
1+
use super::r#virtual as branch;
2+
use crate::branch::get_uncommited_files_raw;
3+
use crate::{
4+
base::{
5+
get_base_branch_data, set_base_branch, set_target_push_remote, update_base_branch,
6+
BaseBranch,
7+
},
8+
branch::get_uncommited_files,
9+
branch_manager::BranchManagerExt,
10+
file::RemoteBranchFile,
11+
remote::{get_branch_data, list_remote_branches, RemoteBranch, RemoteBranchData},
12+
VirtualBranchesExt,
13+
};
114
use anyhow::{Context, Result};
215
use gitbutler_branch::{
316
BranchCreateRequest, BranchId, BranchOwnershipClaims, BranchUpdateRequest, ChangeReference,
417
};
518
use gitbutler_command_context::CommandContext;
19+
use gitbutler_diff::DiffByPathMap;
620
use gitbutler_operating_modes::assure_open_workspace_mode;
721
use gitbutler_oplog::{
822
entry::{OperationKind, SnapshotDetails},
@@ -13,19 +27,6 @@ use gitbutler_reference::{ReferenceName, Refname, RemoteRefname};
1327
use gitbutler_repo::{credentials::Helper, RepoActionsExt, RepositoryExt};
1428
use tracing::instrument;
1529

16-
use super::r#virtual as branch;
17-
use crate::{
18-
base::{
19-
get_base_branch_data, set_base_branch, set_target_push_remote, update_base_branch,
20-
BaseBranch,
21-
},
22-
branch::get_uncommited_files,
23-
branch_manager::BranchManagerExt,
24-
file::RemoteBranchFile,
25-
remote::{get_branch_data, list_remote_branches, RemoteBranch, RemoteBranchData},
26-
VirtualBranchesExt,
27-
};
28-
2930
#[derive(Clone, Copy, Default)]
3031
pub struct VirtualBranchActions;
3132

@@ -81,6 +82,24 @@ impl VirtualBranchActions {
8182
.map_err(Into::into)
8283
}
8384

85+
pub fn list_virtual_branches_cached(
86+
&self,
87+
project: &Project,
88+
worktree_changes: Option<DiffByPathMap>,
89+
) -> Result<(Vec<branch::VirtualBranch>, Vec<gitbutler_diff::FileDiff>)> {
90+
let ctx = open_with_verify(project)?;
91+
92+
assure_open_workspace_mode(&ctx)
93+
.context("Listing virtual branches requires open workspace mode")?;
94+
95+
branch::list_virtual_branches_cached(
96+
&ctx,
97+
project.exclusive_worktree_access().write_permission(),
98+
worktree_changes,
99+
)
100+
.map_err(Into::into)
101+
}
102+
84103
pub fn create_virtual_branch(
85104
&self,
86105
project: &Project,
@@ -569,11 +588,17 @@ impl VirtualBranchActions {
569588

570589
pub fn get_uncommited_files(&self, project: &Project) -> Result<Vec<RemoteBranchFile>> {
571590
let context = CommandContext::open(project)?;
572-
573591
let guard = project.exclusive_worktree_access();
574-
575592
get_uncommited_files(&context, guard.read_permission())
576593
}
594+
595+
/// Like [`get_uncommited_files()`], but returns a type that can be re-used with
596+
/// [`crate::list_virtual_branches()`].
597+
pub fn get_uncommited_files_reusable(&self, project: &Project) -> Result<DiffByPathMap> {
598+
let context = CommandContext::open(project)?;
599+
let guard = project.exclusive_worktree_access();
600+
get_uncommited_files_raw(&context, guard.read_permission())
601+
}
577602
}
578603

579604
fn open_with_verify(project: &Project) -> Result<CommandContext> {

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

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ use core::fmt;
55
use gitbutler_branch::{
66
Branch as GitButlerBranch, BranchId, BranchIdentity, ReferenceExtGix, Target,
77
};
8-
use gitbutler_command_context::{CommandContext, GixRepositoryExt};
8+
use gitbutler_command_context::CommandContext;
9+
use gitbutler_diff::DiffByPathMap;
910
use gitbutler_project::access::WorktreeReadPermission;
1011
use gitbutler_reference::normalize_branch_name;
12+
use gitbutler_repo::{GixRepositoryExt, RepositoryExt};
1113
use gitbutler_serde::BStringForFrontend;
1214
use gix::object::tree::diff::Action;
1315
use gix::prelude::ObjectIdExt;
@@ -22,19 +24,21 @@ use std::{
2224
vec,
2325
};
2426

27+
pub(crate) fn get_uncommited_files_raw(
28+
context: &CommandContext,
29+
_permission: &WorktreeReadPermission,
30+
) -> Result<DiffByPathMap> {
31+
let repository = context.repository();
32+
let head_commit = repository.head_commit()?;
33+
gitbutler_diff::workdir(repository, &head_commit.id())
34+
.context("Failed to list uncommited files")
35+
}
36+
2537
pub(crate) fn get_uncommited_files(
2638
context: &CommandContext,
2739
_permission: &WorktreeReadPermission,
2840
) -> Result<Vec<RemoteBranchFile>> {
29-
let repository = context.repository();
30-
let head_commit = repository
31-
.head()
32-
.context("Failed to get head")?
33-
.peel_to_commit()
34-
.context("Failed to get head commit")?;
35-
36-
let files = gitbutler_diff::workdir(repository, &head_commit.id())
37-
.context("Failed to list uncommited files")?
41+
let files = get_uncommited_files_raw(context, _permission)?
3842
.into_iter()
3943
.map(|(path, file)| {
4044
let binary = file.hunks.iter().any(|h| h.binary);

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,7 @@ impl BranchManager<'_> {
454454
vb_state.set_branch(branch.clone())?;
455455
}
456456

457-
let wd_tree = self.ctx.repository().get_wd_tree()?;
457+
let wd_tree = self.ctx.repository().create_wd_tree()?;
458458

459459
let branch_tree = repo
460460
.find_tree(branch.tree)

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

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,22 @@ use gitbutler_commit::commit_ext::CommitExt;
1212
use gitbutler_error::error::Marker;
1313
use gitbutler_project::access::WorktreeWritePermission;
1414
use gitbutler_repo::{LogUntil, RepoActionsExt, RepositoryExt};
15+
use tracing::instrument;
1516

1617
use crate::{branch_manager::BranchManagerExt, conflicts, VirtualBranchesExt};
1718

1819
const WORKSPACE_HEAD: &str = "Workspace Head";
1920
const GITBUTLER_INTEGRATION_COMMIT_TITLE: &str = "GitButler Integration Commit";
2021

21-
// Creates and returns a merge commit of all active branch heads.
22-
//
23-
// This is the base against which we diff the working directory to understand
24-
// what files have been modified.
22+
/// Creates and returns a merge commit of all active branch heads.
23+
///
24+
/// This is the base against which we diff the working directory to understand
25+
/// what files have been modified.
26+
///
27+
/// This should be used to update the `gitbutler/workspace` ref with, which is usually
28+
/// done from [`update_gitbutler_integration()`], after any of its input changes.
29+
/// This is namely the conflicting state, or any head of the virtual branches.
30+
#[instrument(level = tracing::Level::DEBUG, skip(ctx))]
2531
pub(crate) fn get_workspace_head(ctx: &CommandContext) -> Result<git2::Oid> {
2632
let vb_state = ctx.project().virtual_branches();
2733
let target = vb_state

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

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
use std::{collections::HashMap, path::PathBuf, vec};
22

3+
use crate::integration::get_workspace_head;
4+
use crate::{
5+
conflicts::RepoConflictsExt,
6+
file::{virtual_hunks_into_virtual_files, VirtualBranchFile},
7+
hunk::{file_hunks_from_diffs, HunkLock, VirtualBranchHunk},
8+
BranchManagerExt, VirtualBranchesExt,
9+
};
310
use anyhow::{bail, Context, Result};
411
use git2::Tree;
512
use gitbutler_branch::{
@@ -10,14 +17,7 @@ use gitbutler_command_context::CommandContext;
1017
use gitbutler_diff::{diff_files_into_hunks, GitHunk, Hunk, HunkHash};
1118
use gitbutler_operating_modes::assure_open_workspace_mode;
1219
use gitbutler_project::access::WorktreeWritePermission;
13-
14-
use crate::{
15-
conflicts::RepoConflictsExt,
16-
file::{virtual_hunks_into_virtual_files, VirtualBranchFile},
17-
hunk::{file_hunks_from_diffs, HunkLock, VirtualBranchHunk},
18-
integration::get_workspace_head,
19-
BranchManagerExt, VirtualBranchesExt,
20-
};
20+
use tracing::instrument;
2121

2222
/// Represents the uncommitted status of the applied virtual branches in the workspace.
2323
pub struct VirtualBranchesStatus {
@@ -27,21 +27,38 @@ pub struct VirtualBranchesStatus {
2727
pub skipped_files: Vec<gitbutler_diff::FileDiff>,
2828
}
2929

30+
pub fn get_applied_status(
31+
ctx: &CommandContext,
32+
perm: Option<&mut WorktreeWritePermission>,
33+
) -> Result<VirtualBranchesStatus> {
34+
get_applied_status_cached(ctx, perm, None)
35+
}
36+
3037
/// Returns branches and their associated file changes, in addition to a list
3138
/// of skipped files.
39+
/// `worktree_changes` are all changed files against the current `HEAD^{tree}` and index
40+
/// against the current working tree directory, and it's used to avoid double-computing
41+
/// this expensive information.
3242
// TODO(kv): make this side effect free
33-
pub fn get_applied_status(
43+
#[instrument(level = tracing::Level::DEBUG, skip(ctx, perm, worktree_changes))]
44+
pub fn get_applied_status_cached(
3445
ctx: &CommandContext,
3546
perm: Option<&mut WorktreeWritePermission>,
47+
worktree_changes: Option<gitbutler_diff::DiffByPathMap>,
3648
) -> Result<VirtualBranchesStatus> {
3749
assure_open_workspace_mode(ctx).context("ng applied status requires open workspace mode")?;
38-
let integration_commit = get_workspace_head(ctx)?;
3950
let mut virtual_branches = ctx
4051
.project()
4152
.virtual_branches()
4253
.list_branches_in_workspace()?;
43-
let base_file_diffs = gitbutler_diff::workdir(ctx.repository(), &integration_commit.to_owned())
44-
.context("failed to diff workdir")?;
54+
let base_file_diffs = worktree_changes.map(Ok).unwrap_or_else(|| {
55+
// TODO(ST): Ideally, we can avoid calling `get_workspace_head()` as everyone who modifies
56+
// any of its inputs will update the intragration commit right away.
57+
// It's for another day though - right now the integration commit may be slightly stale.
58+
let integration_commit_id = get_workspace_head(ctx)?;
59+
gitbutler_diff::workdir(ctx.repository(), &integration_commit_id.to_owned())
60+
.context("failed to diff workdir")
61+
})?;
4562

4663
let mut skipped_files: Vec<gitbutler_diff::FileDiff> = Vec::new();
4764
for file_diff in base_file_diffs.values() {

0 commit comments

Comments
 (0)