Skip to content

Commit af704f5

Browse files
authored
Merge pull request #1746 from GitoxideLabs/status
status improvements
2 parents 0ab4f64 + 3b53982 commit af704f5

File tree

14 files changed

+112
-166
lines changed

14 files changed

+112
-166
lines changed

gitoxide-core/src/repository/status.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -135,11 +135,6 @@ pub fn show(
135135
)?;
136136
continue;
137137
}
138-
gix::diff::index::Change::Unmerged { .. } => {
139-
// Unmerged entries from the worktree-index are displayed as part of the index-worktree comparison.
140-
// Here we have nothing to do with them and can ignore.
141-
continue;
142-
}
143138
};
144139
writeln!(
145140
out,

gix-diff/src/index/change.rs

Lines changed: 3 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -70,19 +70,6 @@ impl ChangeRef<'_, '_> {
7070
id: Cow::Owned(id.into_owned()),
7171
copy,
7272
},
73-
ChangeRef::Unmerged {
74-
location,
75-
stage,
76-
index,
77-
entry_mode,
78-
id,
79-
} => ChangeRef::Unmerged {
80-
location: Cow::Owned(location.into_owned()),
81-
stage,
82-
index,
83-
entry_mode,
84-
id: Cow::Owned(id.into_owned()),
85-
},
8673
}
8774
}
8875
}
@@ -120,13 +107,6 @@ impl ChangeRef<'_, '_> {
120107
entry_mode,
121108
id,
122109
..
123-
}
124-
| ChangeRef::Unmerged {
125-
location,
126-
index,
127-
entry_mode,
128-
id,
129-
..
130110
} => (location.as_ref(), *index, *entry_mode, id),
131111
}
132112
}
@@ -138,7 +118,7 @@ impl rewrites::tracker::Change for ChangeRef<'_, '_> {
138118
ChangeRef::Addition { id, .. } | ChangeRef::Deletion { id, .. } | ChangeRef::Modification { id, .. } => {
139119
id.as_ref()
140120
}
141-
ChangeRef::Rewrite { .. } | ChangeRef::Unmerged { .. } => {
121+
ChangeRef::Rewrite { .. } => {
142122
unreachable!("BUG")
143123
}
144124
}
@@ -156,9 +136,6 @@ impl rewrites::tracker::Change for ChangeRef<'_, '_> {
156136
ChangeRef::Rewrite { .. } => {
157137
unreachable!("BUG: rewrites can't be determined ahead of time")
158138
}
159-
ChangeRef::Unmerged { .. } => {
160-
unreachable!("BUG: unmerged don't participate in rename tracking")
161-
}
162139
}
163140
}
164141

@@ -167,8 +144,7 @@ impl rewrites::tracker::Change for ChangeRef<'_, '_> {
167144
ChangeRef::Addition { entry_mode, .. }
168145
| ChangeRef::Deletion { entry_mode, .. }
169146
| ChangeRef::Modification { entry_mode, .. }
170-
| ChangeRef::Rewrite { entry_mode, .. }
171-
| ChangeRef::Unmerged { entry_mode, .. } => {
147+
| ChangeRef::Rewrite { entry_mode, .. } => {
172148
entry_mode
173149
.to_tree_entry_mode()
174150
// Default is for the impossible case - just don't let it participate in rename tracking.
@@ -182,8 +158,7 @@ impl rewrites::tracker::Change for ChangeRef<'_, '_> {
182158
ChangeRef::Addition { id, entry_mode, .. }
183159
| ChangeRef::Deletion { id, entry_mode, .. }
184160
| ChangeRef::Modification { id, entry_mode, .. }
185-
| ChangeRef::Rewrite { id, entry_mode, .. }
186-
| ChangeRef::Unmerged { id, entry_mode, .. } => {
161+
| ChangeRef::Rewrite { id, entry_mode, .. } => {
187162
(
188163
id,
189164
entry_mode

gix-diff/src/index/function.rs

Lines changed: 14 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use super::{Action, ChangeRef, Error, RewriteOptions};
22
use crate::rewrites;
3-
use bstr::{BStr, BString, ByteSlice};
3+
use bstr::BStr;
44
use gix_filter::attributes::glob::pattern::Case;
55
use std::borrow::Cow;
66
use std::cell::RefCell;
@@ -20,7 +20,8 @@ use std::cmp::Ordering;
2020
/// Return the outcome of the rewrite tracker if it was enabled.
2121
///
2222
/// Note that only `rhs` may contain unmerged entries, as `rhs` is expected to be the index read from `.git/index`.
23-
/// Unmerged entries are always provided as changes, one stage at a time, up to three stages for *base*, *ours* and *theirs*.
23+
/// Unmerged entries are skipped entirely.
24+
///
2425
/// Conceptually, `rhs` is *ours*, and `lhs` is *theirs*.
2526
/// The entries in `lhs` and `rhs` are both expected to be sorted like index entries are typically sorted.
2627
///
@@ -74,23 +75,6 @@ where
7475
.filter(|(_, path, e)| pattern_matches.borrow_mut()(path, e)),
7576
);
7677

77-
let mut conflicting_paths = Vec::<BString>::new();
78-
let mut cb = move |change: ChangeRef<'lhs, 'rhs>| {
79-
let (location, ..) = change.fields();
80-
if let ChangeRef::Unmerged { .. } = &change {
81-
if let Err(insert_idx) = conflicting_paths.binary_search_by(|p| p.as_bstr().cmp(location)) {
82-
conflicting_paths.insert(insert_idx, location.to_owned());
83-
}
84-
cb(change)
85-
} else if conflicting_paths
86-
.binary_search_by(|p| p.as_bstr().cmp(location))
87-
.is_err()
88-
{
89-
cb(change)
90-
} else {
91-
Ok(Action::Continue)
92-
}
93-
};
9478
let mut resource_cache_storage = None;
9579
let mut tracker = rewrite_options.map(
9680
|RewriteOptions {
@@ -107,15 +91,6 @@ where
10791
loop {
10892
match (lhs_storage, rhs_storage) {
10993
(Some(lhs), Some(rhs)) => {
110-
match emit_unmerged_ignore_intent_to_add(rhs, &mut cb)? {
111-
None => {}
112-
Some(Action::Cancel) => return Ok(None),
113-
Some(Action::Continue) => {
114-
rhs_storage = rhs_iter.next();
115-
continue;
116-
}
117-
};
118-
11994
let (lhs_idx, lhs_path, lhs_entry) = lhs;
12095
let (rhs_idx, rhs_path, rhs_entry) = rhs;
12196
match lhs_path.cmp(rhs_path) {
@@ -126,6 +101,11 @@ where
126101
Action::Cancel => return Ok(None),
127102
},
128103
Ordering::Equal => {
104+
if ignore_unmerged_and_intent_to_add(rhs) {
105+
rhs_storage = rhs_iter.next();
106+
lhs_storage = lhs_iter.next();
107+
continue;
108+
}
129109
if lhs_entry.id != rhs_entry.id || lhs_entry.mode != rhs_entry.mode {
130110
let change = ChangeRef::Modification {
131111
location: Cow::Borrowed(rhs_path),
@@ -274,8 +254,8 @@ fn emit_addition<'rhs, 'lhs: 'rhs, E>(
274254
where
275255
E: Into<Box<dyn std::error::Error + Send + Sync>>,
276256
{
277-
if let Some(action) = emit_unmerged_ignore_intent_to_add((idx, path, entry), &mut cb)? {
278-
return Ok(action);
257+
if ignore_unmerged_and_intent_to_add((idx, path, entry)) {
258+
return Ok(Action::Continue);
279259
}
280260

281261
let change = ChangeRef::Addition {
@@ -296,29 +276,9 @@ where
296276
cb(change).map_err(|err| Error::Callback(err.into()))
297277
}
298278

299-
fn emit_unmerged_ignore_intent_to_add<'rhs, 'lhs: 'rhs, E>(
300-
(idx, path, entry): (usize, &'rhs BStr, &'rhs gix_index::Entry),
301-
cb: &mut impl FnMut(ChangeRef<'lhs, 'rhs>) -> Result<Action, E>,
302-
) -> Result<Option<Action>, Error>
303-
where
304-
E: Into<Box<dyn std::error::Error + Send + Sync>>,
305-
{
306-
if entry.flags.contains(gix_index::entry::Flags::INTENT_TO_ADD) {
307-
return Ok(Some(Action::Continue));
308-
}
279+
fn ignore_unmerged_and_intent_to_add<'rhs, 'lhs: 'rhs>(
280+
(_idx, _path, entry): (usize, &'rhs BStr, &'rhs gix_index::Entry),
281+
) -> bool {
309282
let stage = entry.stage();
310-
if stage == gix_index::entry::Stage::Unconflicted {
311-
return Ok(None);
312-
}
313-
314-
Ok(Some(
315-
cb(ChangeRef::Unmerged {
316-
location: Cow::Borrowed(path),
317-
stage,
318-
index: idx,
319-
entry_mode: entry.mode,
320-
id: Cow::Borrowed(entry.id.as_ref()),
321-
})
322-
.map_err(|err| Error::Callback(err.into()))?,
323-
))
283+
entry.flags.contains(gix_index::entry::Flags::INTENT_TO_ADD) || stage != gix_index::entry::Stage::Unconflicted
324284
}

gix-diff/src/index/mod.rs

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,6 @@ where
4343
}
4444

4545
/// Identify a change that would have to be applied to `lhs` to obtain `rhs`, as provided in [`index()`](crate::index()).
46-
///
47-
/// Note that all variants are unconflicted entries, unless it's the [`Self::Unmerged`] one.
4846
#[derive(Clone, Debug, PartialEq, Eq)]
4947
pub enum ChangeRef<'lhs, 'rhs> {
5048
/// An entry was added to `rhs`.
@@ -116,22 +114,6 @@ pub enum ChangeRef<'lhs, 'rhs> {
116114
/// or similar content.
117115
copy: bool,
118116
},
119-
/// One of up to three unmerged entries that are provided in order, one for each stage, ordered
120-
/// by `location` and `stage`.
121-
///
122-
/// Unmerged entries also don't participate in rename tracking, and they are never present in `lhs`.
123-
Unmerged {
124-
/// The current location of the entry in `rhs`.
125-
location: Cow<'rhs, BStr>,
126-
/// The stage of the entry, either *base*, *ours*, or *theirs*.
127-
stage: gix_index::entry::Stage,
128-
/// The index into the entries array of `rhs` for full access.
129-
index: usize,
130-
/// The mode of the entry in `rhs`.
131-
entry_mode: gix_index::entry::Mode,
132-
/// The object id of the entry in `rhs`.
133-
id: Cow<'rhs, gix_hash::oid>,
134-
},
135117
}
136118

137119
/// The fully-owned version of [`ChangeRef`].

gix-diff/tests/diff/index.rs

Lines changed: 4 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1191,56 +1191,14 @@ fn unmerged_entries_and_intent_to_add() -> crate::Result {
11911191
}),
11921192
)?;
11931193

1194-
// each unmerged entry is emitted separately, and no entry is emitted for
1195-
// paths that are mentioned there. Intent-to-add is transparent.
1194+
// Intent-to-add is transparent. And unmerged entries aren't emitted either, along with
1195+
// their sibling paths.
11961196
// All that with rename tracking…
1197-
insta::assert_debug_snapshot!(changes.into_iter().collect::<Vec<_>>(), @r#"
1198-
[
1199-
Unmerged {
1200-
location: "src/plumbing-renamed/main.rs",
1201-
stage: Base,
1202-
index: 2,
1203-
entry_mode: Mode(
1204-
FILE,
1205-
),
1206-
id: Sha1(d00491fd7e5bb6fa28c517a0bb32b8b506539d4d),
1207-
},
1208-
Unmerged {
1209-
location: "src/plumbing-renamed/main.rs",
1210-
stage: Ours,
1211-
index: 3,
1212-
entry_mode: Mode(
1213-
FILE,
1214-
),
1215-
id: Sha1(d00491fd7e5bb6fa28c517a0bb32b8b506539d4d),
1216-
},
1217-
]
1218-
"#);
1197+
insta::assert_debug_snapshot!(changes.into_iter().collect::<Vec<_>>(), @"[]");
12191198

12201199
let changes = collect_changes_no_renames("r4-dir-rename-non-identity", ".git/index")?;
12211200
// …or without
1222-
insta::assert_debug_snapshot!(changes.into_iter().collect::<Vec<_>>(), @r#"
1223-
[
1224-
Unmerged {
1225-
location: "src/plumbing-renamed/main.rs",
1226-
stage: Base,
1227-
index: 2,
1228-
entry_mode: Mode(
1229-
FILE,
1230-
),
1231-
id: Sha1(d00491fd7e5bb6fa28c517a0bb32b8b506539d4d),
1232-
},
1233-
Unmerged {
1234-
location: "src/plumbing-renamed/main.rs",
1235-
stage: Ours,
1236-
index: 3,
1237-
entry_mode: Mode(
1238-
FILE,
1239-
),
1240-
id: Sha1(d00491fd7e5bb6fa28c517a0bb32b8b506539d4d),
1241-
},
1242-
]
1243-
"#);
1201+
insta::assert_debug_snapshot!(changes.into_iter().collect::<Vec<_>>(), @"[]");
12441202

12451203
let (index, _, _, _, _) = repo_with_indices(".git/index", ".git/index", None)?;
12461204
assert_eq!(

gix-filter/src/pipeline/convert.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,15 +76,15 @@ impl Pipeline {
7676
where
7777
R: std::io::Read,
7878
{
79-
let bstr_path = gix_path::into_bstr(rela_path);
79+
let bstr_rela_path = gix_path::to_unix_separators_on_windows(gix_path::into_bstr(rela_path));
8080
let Configuration {
8181
driver,
8282
digest,
8383
_attr_digest: _,
8484
encoding,
8585
apply_ident_filter,
8686
} = Configuration::at_path(
87-
bstr_path.as_ref(),
87+
bstr_rela_path.as_ref(),
8888
&self.options.drivers,
8989
&mut self.attrs,
9090
attributes,
@@ -109,7 +109,7 @@ impl Pipeline {
109109
driver,
110110
&mut src,
111111
driver::Operation::Clean,
112-
self.context.with_path(bstr_path.as_ref()),
112+
self.context.with_path(bstr_rela_path.as_ref()),
113113
)? {
114114
if !apply_ident_filter && encoding.is_none() && !would_convert_eol {
115115
// Note that this is not typically a benefit in terms of saving memory as most filters

gix-object/src/object/convert.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,17 @@ impl From<tree::EntryRef<'_>> for tree::Entry {
7878
}
7979
}
8080

81+
impl<'a> From<&'a tree::Entry> for tree::EntryRef<'a> {
82+
fn from(other: &'a tree::Entry) -> tree::EntryRef<'a> {
83+
let tree::Entry { mode, filename, oid } = other;
84+
tree::EntryRef {
85+
mode: *mode,
86+
filename: filename.as_ref(),
87+
oid,
88+
}
89+
}
90+
}
91+
8192
impl From<ObjectRef<'_>> for Object {
8293
fn from(v: ObjectRef<'_>) -> Self {
8394
match v {

gix-object/tests/object/tree/editor.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -619,6 +619,7 @@ fn from_existing_add() -> crate::Result {
619619
let root_tree = find_tree(&odb, root_tree_id)?;
620620
odb.access_count_and_clear();
621621
let mut edit = gix_object::tree::Editor::new(root_tree.clone(), &odb, gix_hash::Kind::Sha1);
622+
assert!(edit.get(["bin"]).is_some(), "the root is immediately available");
622623

623624
let actual = edit.write(&mut write).expect("no changes are fine");
624625
assert_eq!(actual, root_tree_id, "it rewrites the same tree");

gix/src/object/tree/editor.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,21 @@ impl<'repo> Cursor<'_, 'repo> {
177177
pub fn write(&mut self) -> Result<Id<'repo>, write::Error> {
178178
write_cursor(self)
179179
}
180+
181+
/// Obtain the entry at `rela_path` or return `None` if none was found, or the tree wasn't yet written
182+
/// to that point.
183+
/// The root tree is always available.
184+
/// Note that after [writing](Self::write) only the root path remains, all other intermediate trees are removed.
185+
/// The entry can be anything that can be stored in a tree, but may have a null-id if it's a newly
186+
/// inserted tree. Also, ids of trees might not be accurate as they may have been changed in memory.
187+
pub fn get(&self, rela_path: impl ToComponents) -> Option<crate::object::tree::EntryRef<'repo, '_>> {
188+
self.inner
189+
.get(rela_path.to_components())
190+
.map(|entry| crate::object::tree::EntryRef {
191+
inner: entry.into(),
192+
repo: self.repo,
193+
})
194+
}
180195
}
181196

182197
/// Operations
@@ -242,6 +257,21 @@ impl<'repo> super::Editor<'repo> {
242257
pub fn write(&mut self) -> Result<Id<'repo>, write::Error> {
243258
write_cursor(&mut self.to_cursor())
244259
}
260+
261+
/// Obtain the entry at `rela_path` or return `None` if none was found, or the tree wasn't yet written
262+
/// to that point.
263+
/// The root tree is always available.
264+
/// Note that after [writing](Self::write) only the root path remains, all other intermediate trees are removed.
265+
/// The entry can be anything that can be stored in a tree, but may have a null-id if it's a newly
266+
/// inserted tree. Also, ids of trees might not be accurate as they may have been changed in memory.
267+
pub fn get(&self, rela_path: impl ToComponents) -> Option<crate::object::tree::EntryRef<'repo, '_>> {
268+
self.inner
269+
.get(rela_path.to_components())
270+
.map(|entry| crate::object::tree::EntryRef {
271+
inner: entry.into(),
272+
repo: self.repo,
273+
})
274+
}
245275
}
246276

247277
fn write_cursor<'repo>(cursor: &mut Cursor<'_, 'repo>) -> Result<Id<'repo>, write::Error> {

0 commit comments

Comments
 (0)