Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a11f210

Browse files
committed
[tree-diff] A step closer to handling additions in a directory
1 parent f1a575c commit a11f210

6 files changed

Lines changed: 65 additions & 11 deletions

File tree

crate-status.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@
7777

7878
* **tree**
7979
* [ ] changes needed to obtain _other tree_
80-
* [ ] rename tracking
80+
* [ ] rename and copy tracking
8181
* **patches**
8282
* There are various ways to generate a patch from two blobs.
8383
* [ ] any

git-diff/src/visit/changes.rs

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,26 +52,38 @@ impl<'a> visit::Changes<'a> {
5252
use std::cmp::Ordering::*;
5353
match lhs.filename.cmp(rhs.filename) {
5454
Equal => {
55+
use tree::EntryMode::*;
5556
if lhs.oid != rhs.oid || lhs.mode != rhs.mode {
5657
delegate.update_path_component(
5758
PathComponent::new(lhs.filename, &mut path_id),
5859
PathComponentUpdateMode::Replace,
5960
);
60-
if delegate
61-
.record(Change::Modification {
61+
let record_result = if (lhs.mode.is_no_tree() && rhs.mode.is_tree())
62+
|| (rhs.mode.is_tree() && rhs.mode.is_no_tree())
63+
{
64+
delegate.record(Change::Deletion {
65+
entry_mode: lhs.mode,
66+
oid: lhs.oid.to_owned(),
67+
path_id,
68+
})
69+
} else {
70+
delegate.record(Change::Modification {
6271
previous_entry_mode: lhs.mode,
6372
previous_oid: lhs.oid.to_owned(),
6473
entry_mode: rhs.mode,
6574
oid: rhs.oid.to_owned(),
6675
path_id,
6776
})
68-
.cancelled()
69-
{
77+
};
78+
if record_result.cancelled() {
7079
break Err(Error::Cancelled);
7180
}
7281
}
73-
if lhs.mode == tree::EntryMode::Tree || rhs.mode == tree::EntryMode::Tree {
74-
todo!("handle recursion")
82+
match (lhs.mode, rhs.mode) {
83+
(Tree, Tree) => todo!("recurse tree|tree"),
84+
(lhs, Tree) if !lhs.is_tree() => todo!("recurse non-tree|tree"),
85+
(Tree, rhs) if !rhs.is_tree() => todo!("recurse tree|non-tree"),
86+
_both_are_not_trees => {}
7587
}
7688
}
7789
Less => todo!("entry compares less - catch up"),
@@ -85,8 +97,8 @@ impl<'a> visit::Changes<'a> {
8597
);
8698
if delegate
8799
.record(Change::Deletion {
88-
previous_entry_mode: lhs.mode,
89-
previous_oid: lhs.oid.to_owned(),
100+
entry_mode: lhs.mode,
101+
oid: lhs.oid.to_owned(),
90102
path_id,
91103
})
92104
.cancelled()

git-diff/src/visit/record.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use git_object::{bstr::BStr, tree};
33

44
pub type PathId = usize;
55

6+
/// `path_id`s are kept for rename or copy tracking to allow referring to a path in the tree more easily.
67
pub enum Change {
78
Addition {
89
entry_mode: tree::EntryMode,
@@ -11,8 +12,8 @@ pub enum Change {
1112
},
1213
Copy,
1314
Deletion {
14-
previous_entry_mode: tree::EntryMode,
15-
previous_oid: ObjectId,
15+
entry_mode: tree::EntryMode,
16+
oid: ObjectId,
1617
path_id: PathId,
1718
},
1819
Modification {

git-diff/src/visit/recorder.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ pub enum Change {
1313
oid: ObjectId,
1414
path: PathBuf,
1515
},
16+
Deletion {
17+
entry_mode: tree::EntryMode,
18+
oid: ObjectId,
19+
path: PathBuf,
20+
},
1621
Modification {
1722
previous_entry_mode: tree::EntryMode,
1823
previous_oid: ObjectId,
@@ -70,6 +75,15 @@ impl record::Record for Recorder {
7075
fn record(&mut self, change: record::Change) -> record::Action {
7176
use record::Change::*;
7277
self.records.push(match change {
78+
Deletion {
79+
entry_mode,
80+
oid,
81+
path_id: _,
82+
} => Change::Deletion {
83+
entry_mode,
84+
oid,
85+
path: self.path_buf(),
86+
},
7387
Addition {
7488
entry_mode,
7589
oid,

git-diff/tests/visit/mod.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ mod changes {
77

88
const FIRST_COMMIT: &str = "055df97e18cd537da3cb16bcbdf1733fdcdfb430";
99
const SECOND_COMMIT: &str = "a5ebf9ee3b1cac5daf3dc9056026ee848be52da2";
10+
const FIFTH_COMMIT: &str = "69bbebb6608472d98be684f4e6ef1faaac2a03bc";
1011

1112
fn diff_with_previous_commit_from(commit_id: &str) -> crate::Result<recorder::Changes> {
1213
let db = git_odb::linked::Db::at(
@@ -77,6 +78,20 @@ mod changes {
7778
path: "f".into()
7879
}]
7980
, ":100644 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 28ce6a8b26aa170e1de65536fe8abe1832bd3242 M f");
81+
assert_eq!(
82+
diff_with_previous_commit_from(FIFTH_COMMIT).unwrap(),
83+
vec![recorder::Change::Deletion {
84+
entry_mode: EntryMode::Blob,
85+
oid: hex_to_id("28ce6a8b26aa170e1de65536fe8abe1832bd3242"),
86+
path: "f".into()
87+
},
88+
recorder::Change::Addition {
89+
entry_mode: EntryMode::Blob,
90+
oid: hex_to_id("28ce6a8b26aa170e1de65536fe8abe1832bd3242"),
91+
path: "f/f".into()
92+
}]
93+
, ":100644 000000 28ce6a8b26aa170e1de65536fe8abe1832bd3242 0000000000000000000000000000000000000000 D f
94+
:000000 100644 0000000000000000000000000000000000000000 28ce6a8b26aa170e1de65536fe8abe1832bd3242 A f/f");
8095
}
8196
}
8297
}

git-object/src/types.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,4 +119,16 @@ pub mod tree {
119119
Link = 0o120000,
120120
Commit = 0o160000,
121121
}
122+
123+
impl EntryMode {
124+
/// Return true if this entry mode represents a Tree/directory
125+
pub fn is_tree(&self) -> bool {
126+
*self == EntryMode::Tree
127+
}
128+
129+
/// Return true if this entry mode represents anything BUT Tree/directory
130+
pub fn is_no_tree(&self) -> bool {
131+
*self != EntryMode::Tree
132+
}
133+
}
122134
}

0 commit comments

Comments
 (0)