Skip to content

Commit 40d8033

Browse files
authored
Merge pull request #1902 from cruessler/make-gix-diff-file-accept-bare-path
feat: support bare paths in `gix diff file`
2 parents 7255a5f + 46f2e14 commit 40d8033

File tree

1 file changed

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

1 file changed

+39
-20
lines changed

gitoxide-core/src/repository/diff.rs

Lines changed: 39 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,36 @@ 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+
let root = repo.workdir().map(ToOwned::to_owned);
131+
let name = gix::path::os_string_into_bstring(name.into())?;
132+
133+
Ok((ObjectId::null(gix::hash::Kind::Sha1), root, name))
134+
}
135+
Err(err) => Err(err.into()),
136+
Ok(resolved_revspec) => {
137+
let blob_id = resolved_revspec
138+
.single()
139+
.context(format!("rev-spec '{revspec}' must resolve to a single object"))?;
140+
141+
let (path, _) = resolved_revspec
142+
.path_and_mode()
143+
.context(format!("rev-spec '{revspec}' must contain a path"))?;
144+
145+
Ok((blob_id.into(), None, path.into()))
146+
}
147+
}
148+
}
149+
119150
pub fn file(
120151
mut repo: gix::Repository,
121152
out: &mut dyn std::io::Write,
@@ -125,39 +156,27 @@ pub fn file(
125156
repo.object_cache_size_if_unset(repo.compute_object_cache_size_for_tree_diffs(&**repo.index_or_empty()?));
126157
repo.objects.refresh = RefreshMode::Never;
127158

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"))?;
159+
let (old_blob_id, old_root, old_path) = resolve_revspec(&repo, old_revspec)?;
160+
let (new_blob_id, new_root, new_path) = resolve_revspec(&repo, new_revspec)?;
137161

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"))?;
162+
let worktree_roots = gix::diff::blob::pipeline::WorktreeRoots { old_root, new_root };
144163

145164
let mut resource_cache = repo.diff_resource_cache(
146165
gix::diff::blob::pipeline::Mode::ToGitUnlessBinaryToTextIsPresent,
147-
Default::default(),
166+
worktree_roots,
148167
)?;
149168

150169
resource_cache.set_resource(
151-
old_blob_id.into(),
170+
old_blob_id,
152171
gix::object::tree::EntryKind::Blob,
153-
old_path,
172+
old_path.as_ref(),
154173
gix::diff::blob::ResourceKind::OldOrSource,
155174
&repo.objects,
156175
)?;
157176
resource_cache.set_resource(
158-
new_blob_id.into(),
177+
new_blob_id,
159178
gix::object::tree::EntryKind::Blob,
160-
new_path,
179+
new_path.as_ref(),
161180
gix::diff::blob::ResourceKind::NewOrDestination,
162181
&repo.objects,
163182
)?;

0 commit comments

Comments
 (0)