Skip to content

Commit 2e13989

Browse files
committed
Fix tree-extension loading for empty trees (#293)
This also fixes an issue with the node-id seemingly being optional, even though it is not.
1 parent 32cca7f commit 2e13989

File tree

5 files changed

+25
-18
lines changed

5 files changed

+25
-18
lines changed

git-index/src/extension/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub struct Iter<'a> {
1717
pub struct Tree {
1818
pub name: SmallVec<[u8; 23]>,
1919
/// Only set if there are any entries in the index we are associated with.
20-
pub id: Option<tree::NodeId>,
20+
pub id: tree::NodeId,
2121
pub children: Vec<Tree>,
2222
}
2323

git-index/src/extension/tree.rs

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use git_hash::ObjectId;
22

3+
use crate::util::split_at_pos;
34
use crate::{
45
extension::{Signature, Tree},
56
util::split_at_byte_exclusive,
@@ -31,19 +32,14 @@ pub fn one_recursive(data: &[u8], hash_len: usize) -> Option<(Tree, &[u8])> {
3132
let (entry_count, data) = split_at_byte_exclusive(data, b' ')?;
3233
let entry_count: u32 = atoi::atoi(entry_count)?;
3334

34-
let (subtree_count, mut data) = split_at_byte_exclusive(data, b'\n')?;
35+
let (subtree_count, data) = split_at_byte_exclusive(data, b'\n')?;
3536
let subtree_count: usize = atoi::atoi(subtree_count)?;
3637

37-
let node_id = (entry_count != 0)
38-
.then(|| {
39-
(data.len() >= hash_len).then(|| {
40-
let (hash, rest) = data.split_at(hash_len);
41-
data = rest;
42-
ObjectId::from(hash)
43-
})
44-
})
45-
.flatten()
46-
.map(|id| NodeId { id, entry_count });
38+
let (hash, mut data) = split_at_pos(data, hash_len)?;
39+
let node_id = NodeId {
40+
id: ObjectId::from(hash),
41+
entry_count,
42+
};
4743

4844
let mut subtrees = Vec::with_capacity(subtree_count);
4945
for _ in 0..subtree_count {
@@ -68,6 +64,6 @@ mod tests {
6864

6965
#[test]
7066
fn size_of_tree() {
71-
assert_eq!(std::mem::size_of::<Tree>(), 88);
67+
assert_eq!(std::mem::size_of::<Tree>(), 80);
7268
}
7369
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/bin/bash
2+
set -eu -o pipefail
3+
4+
git init -q
5+
git read-tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904

git-index/tests/index/file/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@ mod init {
3636
assert_eq!(entry.path(&file.state), "a");
3737
}
3838
}
39+
#[test]
40+
fn read_v2_empty() {
41+
let file = file("v2_empty");
42+
assert_eq!(file.version(), Version::V2);
43+
assert_eq!(file.entries().len(), 0);
44+
}
3945

4046
#[test]
4147
fn read_v2_with_multiple_entries_without_eoie_ext() {

gitoxide-core/src/index/information.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ mod serde_only {
1212
pub(crate) struct Tree {
1313
name: String,
1414
/// Only set if there are any entries in the index we are associated with.
15-
id: Option<tree::NodeId>,
15+
id: tree::NodeId,
1616
children: Vec<Tree>,
1717
}
1818

@@ -24,10 +24,10 @@ mod serde_only {
2424
fn from(t: &'a git_repository::index::extension::Tree) -> Self {
2525
super::Tree {
2626
name: t.name.as_bstr().to_string(),
27-
id: t.id.as_ref().map(|id| NodeId {
28-
entry_count: id.entry_count,
29-
id: id.id.to_hex().to_string(),
30-
}),
27+
id: NodeId {
28+
entry_count: t.id.entry_count,
29+
id: t.id.id.to_hex().to_string(),
30+
},
3131
children: t.children.iter().map(|t| t.into()).collect(),
3232
}
3333
}

0 commit comments

Comments
 (0)