Skip to content

Commit bf9ccb1

Browse files
committed
Use gitoxide for oplog listing
1 parent 6ef051e commit bf9ccb1

File tree

2 files changed

+53
-32
lines changed

2 files changed

+53
-32
lines changed

crates/gitbutler-oplog/src/oplog.rs

Lines changed: 49 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,18 @@ use super::{
1212
state::OplogHandle,
1313
};
1414
use anyhow::{anyhow, bail, Context, Result};
15-
use git2::{DiffOptions, FileMode};
15+
use git2::FileMode;
1616
use gitbutler_command_context::RepositoryExtLite;
1717
use gitbutler_diff::{hunks_by_filepath, FileDiff};
18-
use gitbutler_oxidize::{git2_to_gix_object_id, gix_to_git2_oid};
18+
use gitbutler_oxidize::{git2_to_gix_object_id, gix_time_to_git2, gix_to_git2_oid};
1919
use gitbutler_project::{
2020
access::{WorktreeReadPermission, WorktreeWritePermission},
2121
Project,
2222
};
2323
use gitbutler_repo::SignaturePurpose;
2424
use gitbutler_repo::{GixRepositoryExt, RepositoryExt};
2525
use gitbutler_stack::{Stack, VirtualBranchesHandle, VirtualBranchesState};
26+
use gix::bstr::ByteSlice;
2627
use gix::prelude::Write;
2728
use tracing::instrument;
2829

@@ -196,53 +197,71 @@ impl OplogExt for Project {
196197
break;
197198
}
198199
let commit_id = commit_id?;
199-
let commit = repo.find_commit(commit_id)?;
200-
201-
if commit.parent_count() > 1 {
200+
let commit = gix_repo.find_commit(git2_to_gix_object_id(commit_id))?;
201+
let mut parents = commit.parent_ids();
202+
let (first_parent, second_parent) = (parents.next(), parents.next());
203+
if second_parent.is_some() {
202204
break;
203205
}
204206

205207
let tree = commit.tree()?;
206-
if tree.get_name("virtual_branches.toml").is_none() {
208+
if tree
209+
.lookup_entry_by_path("virtual_branches.toml")?
210+
.is_none()
211+
{
207212
// We reached a tree that is not a snapshot
208213
tracing::warn!("Commit {commit_id} didn't seem to be an oplog commit - skipping");
209214
continue;
210215
}
211216

212217
// Get tree id from cache or calculate it
213-
let wd_tree = get_workdir_tree(&mut wd_trees_cache, commit_id, &repo, &gix_repo)?;
218+
let wd_tree =
219+
gix_repo.find_tree(get_workdir_tree(&mut wd_trees_cache, commit_id, &gix_repo)?)?;
214220

215221
let details = commit
216-
.message()
222+
.message_raw()?
223+
.to_str()
224+
.ok()
217225
.and_then(|msg| SnapshotDetails::from_str(msg).ok());
226+
let commit_time = gix_time_to_git2(commit.time()?);
218227

219-
if let Ok(parent) = commit.parent(0) {
228+
if let Some(parent_id) = first_parent {
220229
// Get tree id from cache or calculate it
221-
let parent_tree =
222-
get_workdir_tree(&mut wd_trees_cache, parent.id(), &repo, &gix_repo)?;
223-
224-
let mut opts = DiffOptions::new();
225-
opts.include_untracked(true);
226-
opts.ignore_submodules(true);
227-
let diff =
228-
repo.diff_tree_to_tree(Some(&parent_tree), Some(&wd_tree), Some(&mut opts))?;
230+
let parent_tree_id =
231+
get_workdir_tree(&mut wd_trees_cache, gix_to_git2_oid(parent_id), &gix_repo)?;
232+
let parent_tree = gix_repo.find_tree(parent_tree_id)?;
229233

230234
let mut files_changed = Vec::new();
231-
diff.print(git2::DiffFormat::NameOnly, |delta, _, _| {
232-
if let Some(path) = delta.new_file().path() {
233-
files_changed.push(path.to_path_buf());
234-
}
235-
true
236-
})?;
235+
let mut resource_cache = gix_repo.diff_resource_cache_for_tree_diff()?;
236+
let (mut lines_added, mut lines_removed) = (0, 0);
237+
parent_tree
238+
.changes()?
239+
.options(|opts| {
240+
opts.track_rewrites(None).track_path();
241+
})
242+
.for_each_to_obtain_tree(&wd_tree, |change| -> Result<_> {
243+
files_changed.push(gix::path::from_bstr(change.location()).into_owned());
244+
if let Some(counts) = change
245+
.diff(&mut resource_cache)
246+
.ok()
247+
.and_then(|mut platform| platform.line_counts().ok())
248+
.flatten()
249+
{
250+
lines_added += u64::from(counts.insertions);
251+
lines_removed += u64::from(counts.removals);
252+
}
253+
resource_cache.clear_resource_cache_keep_allocation();
254+
255+
Ok(gix::object::tree::diff::Action::Continue)
256+
})?;
237257

238-
let stats = diff.stats()?;
239258
snapshots.push(Snapshot {
240259
commit_id,
241260
details,
242-
lines_added: stats.insertions(),
243-
lines_removed: stats.deletions(),
261+
lines_added: lines_added as usize,
262+
lines_removed: lines_removed as usize,
244263
files_changed,
245-
created_at: commit.time(),
264+
created_at: commit_time,
246265
});
247266
} else {
248267
// this is the very first snapshot
@@ -252,7 +271,7 @@ impl OplogExt for Project {
252271
lines_added: 0,
253272
lines_removed: 0,
254273
files_changed: Vec::new(),
255-
created_at: commit.time(),
274+
created_at: commit_time,
256275
});
257276
break;
258277
}
@@ -320,9 +339,8 @@ impl OplogExt for Project {
320339
fn get_workdir_tree<'a>(
321340
wd_trees_cache: &mut HashMap<git2::Oid, git2::Oid>,
322341
commit_id: git2::Oid,
323-
repo: &'a git2::Repository,
324342
gix_repo: &gix::Repository,
325-
) -> Result<git2::Tree<'a>, anyhow::Error> {
343+
) -> Result<gix::ObjectId, anyhow::Error> {
326344
if let Entry::Vacant(e) = wd_trees_cache.entry(commit_id) {
327345
if let Ok(wd_tree_id) = tree_from_applied_vbranches(gix_repo, commit_id) {
328346
e.insert(wd_tree_id);
@@ -331,8 +349,7 @@ fn get_workdir_tree<'a>(
331349
let wd_tree_id = wd_trees_cache.get(&commit_id).ok_or(anyhow!(
332350
"Could not get a tree of all applied virtual branches merged"
333351
))?;
334-
let wd_tree = repo.find_tree(wd_tree_id.to_owned())?;
335-
Ok(wd_tree)
352+
Ok(git2_to_gix_object_id(*wd_tree_id))
336353
}
337354

338355
fn prepare_snapshot(ctx: &Project, _shared_access: &WorktreeReadPermission) -> Result<git2::Oid> {

crates/gitbutler-oxidize/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ use anyhow::Context;
44
use gix::bstr::ByteSlice;
55
use std::borrow::Borrow;
66

7+
pub fn gix_time_to_git2(time: gix::date::Time) -> git2::Time {
8+
git2::Time::new(time.seconds, time.offset)
9+
}
10+
711
pub fn git2_to_gix_object_id(id: git2::Oid) -> gix::ObjectId {
812
gix::ObjectId::try_from(id.as_bytes()).expect("git2 oid is always valid")
913
}

0 commit comments

Comments
 (0)