Skip to content

Commit 448fa58

Browse files
committed
feat: support bare paths in gix diff file
1 parent 7255a5f commit 448fa58

File tree

1 file changed

+41
-20
lines changed
  • gitoxide-core/src/repository

1 file changed

+41
-20
lines changed

gitoxide-core/src/repository/diff.rs

Lines changed: 41 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use gix::diff::blob::UnifiedDiff;
66
use gix::objs::tree::EntryMode;
77
use gix::odb::store::RefreshMode;
88
use gix::prelude::ObjectIdExt;
9+
use gix::ObjectId;
910

1011
pub fn tree(
1112
mut repo: gix::Repository,
@@ -116,6 +117,38 @@ fn typed_location(mut location: BString, mode: EntryMode) -> BString {
116117
location
117118
}
118119

120+
fn resolve_revspec(
121+
repo: &gix::Repository,
122+
revspec: BString,
123+
) -> Result<(ObjectId, Option<std::path::PathBuf>, BString), anyhow::Error> {
124+
let result = repo.rev_parse(revspec.as_bstr());
125+
126+
match result {
127+
Err(gix::revision::spec::parse::Error::FindReference(gix::refs::file::find::existing::Error::NotFound {
128+
name,
129+
})) => {
130+
use std::os::unix::ffi::OsStrExt;
131+
132+
let root: Option<std::path::PathBuf> = repo.workdir().map(std::path::Path::to_path_buf);
133+
let name: BString = BString::new(name.as_os_str().as_bytes().to_vec());
134+
135+
Ok((ObjectId::null(gix::hash::Kind::Sha1), root, name))
136+
}
137+
Err(err) => Err(err.into()),
138+
Ok(resolved_revspec) => {
139+
let blob_id = resolved_revspec
140+
.single()
141+
.context(format!("rev-spec '{revspec}' must resolve to a single object"))?;
142+
143+
let (path, _) = resolved_revspec
144+
.path_and_mode()
145+
.context(format!("rev-spec '{revspec}' must contain a path"))?;
146+
147+
Ok((blob_id.into(), None, path.into()))
148+
}
149+
}
150+
}
151+
119152
pub fn file(
120153
mut repo: gix::Repository,
121154
out: &mut dyn std::io::Write,
@@ -125,39 +158,27 @@ pub fn file(
125158
repo.object_cache_size_if_unset(repo.compute_object_cache_size_for_tree_diffs(&**repo.index_or_empty()?));
126159
repo.objects.refresh = RefreshMode::Never;
127160

128-
let old_resolved_revspec = repo.rev_parse(old_revspec.as_bstr())?;
129-
let new_resolved_revspec = repo.rev_parse(new_revspec.as_bstr())?;
130-
131-
let old_blob_id = old_resolved_revspec
132-
.single()
133-
.context(format!("rev-spec '{old_revspec}' must resolve to a single object"))?;
134-
let new_blob_id = new_resolved_revspec
135-
.single()
136-
.context(format!("rev-spec '{new_revspec}' must resolve to a single object"))?;
161+
let (old_blob_id, old_root, old_path) = resolve_revspec(&repo, old_revspec)?;
162+
let (new_blob_id, new_root, new_path) = resolve_revspec(&repo, new_revspec)?;
137163

138-
let (old_path, _) = old_resolved_revspec
139-
.path_and_mode()
140-
.context(format!("rev-spec '{old_revspec}' must contain a path"))?;
141-
let (new_path, _) = new_resolved_revspec
142-
.path_and_mode()
143-
.context(format!("rev-spec '{new_revspec}' must contain a path"))?;
164+
let worktree_roots = gix::diff::blob::pipeline::WorktreeRoots { old_root, new_root };
144165

145166
let mut resource_cache = repo.diff_resource_cache(
146167
gix::diff::blob::pipeline::Mode::ToGitUnlessBinaryToTextIsPresent,
147-
Default::default(),
168+
worktree_roots,
148169
)?;
149170

150171
resource_cache.set_resource(
151-
old_blob_id.into(),
172+
old_blob_id,
152173
gix::object::tree::EntryKind::Blob,
153-
old_path,
174+
old_path.as_ref(),
154175
gix::diff::blob::ResourceKind::OldOrSource,
155176
&repo.objects,
156177
)?;
157178
resource_cache.set_resource(
158-
new_blob_id.into(),
179+
new_blob_id,
159180
gix::object::tree::EntryKind::Blob,
160-
new_path,
181+
new_path.as_ref(),
161182
gix::diff::blob::ResourceKind::NewOrDestination,
162183
&repo.objects,
163184
)?;

0 commit comments

Comments
 (0)