Skip to content

Commit a363e6b

Browse files
committed
backend: add CopyId to TreeValue::File
This patch adds a `TreeValue::File::copy_id` field. The copy ids are always empty for now. I preserved the copy id where it was easy to do so, plus in a few non-trivial cases. In other places, however, I made the code use a new copy id. I added a `CopyId::placeholder()` function for creating a new copy id where we need one. We should eventually fix all callers to either preserve an existing copy or to generate a new one.
1 parent c90e139 commit a363e6b

24 files changed

+298
-67
lines changed

cli/src/commands/file/chmod.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,12 @@ pub(crate) fn cmd_file_chmod(
107107
return Err(user_error_with_path(message));
108108
}
109109
for value in tree_value.iter_mut().flatten() {
110-
if let TreeValue::File { id: _, executable } = value {
110+
if let TreeValue::File {
111+
id: _,
112+
executable,
113+
copy_id: _,
114+
} = value
115+
{
111116
*executable = executable_bit;
112117
}
113118
}

cli/src/merge_tools/builtin.rs

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use futures::stream::BoxStream;
66
use futures::StreamExt as _;
77
use itertools::Itertools as _;
88
use jj_lib::backend::BackendResult;
9+
use jj_lib::backend::CopyId;
910
use jj_lib::backend::MergedTreeId;
1011
use jj_lib::backend::TreeValue;
1112
use jj_lib::conflicts;
@@ -390,11 +391,15 @@ fn apply_diff_builtin(
390391
files,
391392
|path| left_tree.path_value(path),
392393
|path| right_tree.path_value(path),
393-
|path, contents, executable| {
394+
|path, contents, executable, copy_id| {
394395
let old_value = left_tree.path_value(path)?;
395396
let new_value = if old_value.is_resolved() {
396397
let id = store.write_file(path, &mut &contents[..]).block_on()?;
397-
Merge::normal(TreeValue::File { id, executable })
398+
Merge::normal(TreeValue::File {
399+
id,
400+
executable,
401+
copy_id,
402+
})
398403
} else if let Some(old_file_ids) = old_value.to_file_merge() {
399404
// TODO: should error out if conflicts couldn't be parsed?
400405
let new_file_ids = conflicts::update_from_content(
@@ -407,7 +412,11 @@ fn apply_diff_builtin(
407412
)
408413
.block_on()?;
409414
match new_file_ids.into_resolved() {
410-
Ok(id) => Merge::resolved(id.map(|id| TreeValue::File { id, executable })),
415+
Ok(id) => Merge::resolved(id.map(|id| TreeValue::File {
416+
id,
417+
executable,
418+
copy_id: CopyId::placeholder(),
419+
})),
411420
Err(file_ids) => old_value.with_new_file_ids(&file_ids),
412421
}
413422
} else {
@@ -425,7 +434,7 @@ fn apply_changes(
425434
files: &[scm_record::File],
426435
select_left: impl Fn(&RepoPath) -> BackendResult<MergedTreeValue>,
427436
select_right: impl Fn(&RepoPath) -> BackendResult<MergedTreeValue>,
428-
write_file: impl Fn(&RepoPath, &[u8], bool) -> BackendResult<MergedTreeValue>,
437+
write_file: impl Fn(&RepoPath, &[u8], bool, CopyId) -> BackendResult<MergedTreeValue>,
429438
) -> BackendResult<()> {
430439
assert_eq!(
431440
changed_files.len(),
@@ -487,11 +496,13 @@ fn apply_changes(
487496
new_description: None,
488497
} => {
489498
// File contents emptied out, but file mode is not absent => write empty file.
490-
let value = write_file(&path, &[], executable)?;
499+
let copy_id = CopyId::placeholder();
500+
let value = write_file(&path, &[], executable, copy_id)?;
491501
tree_builder.set_or_remove(path, value);
492502
}
493503
scm_record::SelectedContents::Text { contents } => {
494-
let value = write_file(&path, contents.as_bytes(), executable)?;
504+
let copy_id = CopyId::placeholder();
505+
let value = write_file(&path, contents.as_bytes(), executable, copy_id)?;
495506
tree_builder.set_or_remove(path, value);
496507
}
497508
}
@@ -683,9 +694,13 @@ pub fn edit_merge_builtin(
683694
// sections, but `make_merge_file` does not produce `Binary` sections for conflicted files.
684695
// This needs to be revisited when the UI becomes capable of representing binary conflicts.
685696
|path| tree.path_value(path),
686-
|path, contents, executable| {
697+
|path, contents, executable, copy_id| {
687698
let id = store.write_file(path, &mut &contents[..]).block_on()?;
688-
Ok(Merge::normal(TreeValue::File { id, executable }))
699+
Ok(Merge::normal(TreeValue::File {
700+
id,
701+
executable,
702+
copy_id,
703+
}))
689704
},
690705
)?;
691706
Ok(tree_builder.write_tree(store)?)
@@ -1759,7 +1774,11 @@ mod tests {
17591774

17601775
fn to_file_id(tree_value: MergedTreeValue) -> Option<FileId> {
17611776
match tree_value.into_resolved() {
1762-
Ok(Some(TreeValue::File { id, executable: _ })) => Some(id.clone()),
1777+
Ok(Some(TreeValue::File {
1778+
id,
1779+
executable: _,
1780+
copy_id: _,
1781+
})) => Some(id.clone()),
17631782
other => {
17641783
panic!("merge should have been a FileId: {other:?}")
17651784
}

cli/src/merge_tools/external.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use std::sync::Arc;
99

1010
use bstr::BString;
1111
use itertools::Itertools as _;
12+
use jj_lib::backend::CopyId;
1213
use jj_lib::backend::MergedTreeId;
1314
use jj_lib::backend::TreeValue;
1415
use jj_lib::conflicts;
@@ -317,7 +318,11 @@ fn run_mergetool_external_single_file(
317318
let new_tree_value = match new_file_ids.into_resolved() {
318319
Ok(file_id) => {
319320
let executable = file.executable.expect("should have been resolved");
320-
Merge::resolved(file_id.map(|id| TreeValue::File { id, executable }))
321+
Merge::resolved(file_id.map(|id| TreeValue::File {
322+
id,
323+
executable,
324+
copy_id: CopyId::placeholder(),
325+
}))
321326
}
322327
// Update the file ids only, leaving the executable flags unchanged
323328
Err(file_ids) => conflict.with_new_file_ids(&file_ids),

cli/src/merge_tools/mod.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use std::sync::Arc;
2020

2121
use itertools::Itertools as _;
2222
use jj_lib::backend::BackendError;
23+
use jj_lib::backend::CopyId;
2324
use jj_lib::backend::MergedTreeId;
2425
use jj_lib::backend::TreeValue;
2526
use jj_lib::config::ConfigGetError;
@@ -464,8 +465,11 @@ fn pick_conflict_side(
464465
let file = &merge_tool_file.file;
465466
let file_id = file.ids.get_add(add_index).unwrap();
466467
let executable = file.executable.expect("should have been resolved");
467-
let new_tree_value =
468-
Merge::resolved(file_id.clone().map(|id| TreeValue::File { id, executable }));
468+
let new_tree_value = Merge::resolved(file_id.clone().map(|id| TreeValue::File {
469+
id,
470+
executable,
471+
copy_id: CopyId::placeholder(),
472+
}));
469473
tree_builder.set_or_remove(merge_tool_file.repo_path.clone(), new_tree_value);
470474
}
471475
tree_builder.write_tree(tree.store())

cli/tests/test_debug_command.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -166,24 +166,24 @@ fn test_debug_tree() {
166166
// Defaults to showing the tree at the current commit
167167
let output = work_dir.run_jj(["debug", "tree"]);
168168
assert_snapshot!(output.normalize_backslash(), @r#"
169-
dir/subdir/file1: Ok(Resolved(Some(File { id: FileId("498e9b01d79cb8d31cdf0df1a663cc1fcefd9de3"), executable: false })))
170-
dir/subdir/file2: Ok(Resolved(Some(File { id: FileId("b2496eaffe394cd50a9db4de5787f45f09fd9722"), executable: false })))
169+
dir/subdir/file1: Ok(Resolved(Some(File { id: FileId("498e9b01d79cb8d31cdf0df1a663cc1fcefd9de3"), executable: false, copy_id: CopyId("") })))
170+
dir/subdir/file2: Ok(Resolved(Some(File { id: FileId("b2496eaffe394cd50a9db4de5787f45f09fd9722"), executable: false, copy_id: CopyId("") })))
171171
[EOF]
172172
"#
173173
);
174174

175175
// Can show the tree at another commit
176176
let output = work_dir.run_jj(["debug", "tree", "-r@-"]);
177177
assert_snapshot!(output.normalize_backslash(), @r#"
178-
dir/subdir/file1: Ok(Resolved(Some(File { id: FileId("498e9b01d79cb8d31cdf0df1a663cc1fcefd9de3"), executable: false })))
178+
dir/subdir/file1: Ok(Resolved(Some(File { id: FileId("498e9b01d79cb8d31cdf0df1a663cc1fcefd9de3"), executable: false, copy_id: CopyId("") })))
179179
[EOF]
180180
"#
181181
);
182182

183183
// Can filter by paths
184184
let output = work_dir.run_jj(["debug", "tree", "dir/subdir/file2"]);
185185
assert_snapshot!(output.normalize_backslash(), @r#"
186-
dir/subdir/file2: Ok(Resolved(Some(File { id: FileId("b2496eaffe394cd50a9db4de5787f45f09fd9722"), executable: false })))
186+
dir/subdir/file2: Ok(Resolved(Some(File { id: FileId("b2496eaffe394cd50a9db4de5787f45f09fd9722"), executable: false, copy_id: CopyId("") })))
187187
[EOF]
188188
"#
189189
);
@@ -195,8 +195,8 @@ fn test_debug_tree() {
195195
"--id=0958358e3f80e794f032b25ed2be96cf5825da6c",
196196
]);
197197
assert_snapshot!(output.normalize_backslash(), @r#"
198-
dir/subdir/file1: Ok(Resolved(Some(File { id: FileId("498e9b01d79cb8d31cdf0df1a663cc1fcefd9de3"), executable: false })))
199-
dir/subdir/file2: Ok(Resolved(Some(File { id: FileId("b2496eaffe394cd50a9db4de5787f45f09fd9722"), executable: false })))
198+
dir/subdir/file1: Ok(Resolved(Some(File { id: FileId("498e9b01d79cb8d31cdf0df1a663cc1fcefd9de3"), executable: false, copy_id: CopyId("") })))
199+
dir/subdir/file2: Ok(Resolved(Some(File { id: FileId("b2496eaffe394cd50a9db4de5787f45f09fd9722"), executable: false, copy_id: CopyId("") })))
200200
[EOF]
201201
"#
202202
);
@@ -209,8 +209,8 @@ fn test_debug_tree() {
209209
"--id=6ac232efa713535ae518a1a898b77e76c0478184",
210210
]);
211211
assert_snapshot!(output.normalize_backslash(), @r#"
212-
dir/subdir/file1: Ok(Resolved(Some(File { id: FileId("498e9b01d79cb8d31cdf0df1a663cc1fcefd9de3"), executable: false })))
213-
dir/subdir/file2: Ok(Resolved(Some(File { id: FileId("b2496eaffe394cd50a9db4de5787f45f09fd9722"), executable: false })))
212+
dir/subdir/file1: Ok(Resolved(Some(File { id: FileId("498e9b01d79cb8d31cdf0df1a663cc1fcefd9de3"), executable: false, copy_id: CopyId("") })))
213+
dir/subdir/file2: Ok(Resolved(Some(File { id: FileId("b2496eaffe394cd50a9db4de5787f45f09fd9722"), executable: false, copy_id: CopyId("") })))
214214
[EOF]
215215
"#
216216
);
@@ -224,7 +224,7 @@ fn test_debug_tree() {
224224
"dir/subdir/file2",
225225
]);
226226
assert_snapshot!(output.normalize_backslash(), @r#"
227-
dir/subdir/file2: Ok(Resolved(Some(File { id: FileId("b2496eaffe394cd50a9db4de5787f45f09fd9722"), executable: false })))
227+
dir/subdir/file2: Ok(Resolved(Some(File { id: FileId("b2496eaffe394cd50a9db4de5787f45f09fd9722"), executable: false, copy_id: CopyId("") })))
228228
[EOF]
229229
"#
230230
);

cli/tests/test_file_chmod_command.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ fn test_chmod_regular_conflict() {
5050
");
5151
let output = work_dir.run_jj(["debug", "tree"]);
5252
insta::assert_snapshot!(output, @r#"
53-
file: Ok(Conflicted([Some(File { id: FileId("587be6b4c3f93f93c489c0111bba5596147a26cb"), executable: true }), Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: false }), Some(File { id: FileId("8ba3a16384aacc37d01564b28401755ce8053f51"), executable: false })]))
53+
file: Ok(Conflicted([Some(File { id: FileId("587be6b4c3f93f93c489c0111bba5596147a26cb"), executable: true, copy_id: CopyId("") }), Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: false, copy_id: CopyId("") }), Some(File { id: FileId("8ba3a16384aacc37d01564b28401755ce8053f51"), executable: false, copy_id: CopyId("") })]))
5454
[EOF]
5555
"#);
5656
let output = work_dir.run_jj(["file", "show", "file"]);
@@ -69,7 +69,7 @@ fn test_chmod_regular_conflict() {
6969
work_dir.run_jj(["file", "chmod", "x", "file"]).success();
7070
let output = work_dir.run_jj(["debug", "tree"]);
7171
insta::assert_snapshot!(output, @r#"
72-
file: Ok(Conflicted([Some(File { id: FileId("587be6b4c3f93f93c489c0111bba5596147a26cb"), executable: true }), Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: true }), Some(File { id: FileId("8ba3a16384aacc37d01564b28401755ce8053f51"), executable: true })]))
72+
file: Ok(Conflicted([Some(File { id: FileId("587be6b4c3f93f93c489c0111bba5596147a26cb"), executable: true, copy_id: CopyId("") }), Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: true, copy_id: CopyId("") }), Some(File { id: FileId("8ba3a16384aacc37d01564b28401755ce8053f51"), executable: true, copy_id: CopyId("") })]))
7373
[EOF]
7474
"#);
7575
let output = work_dir.run_jj(["file", "show", "file"]);
@@ -86,7 +86,7 @@ fn test_chmod_regular_conflict() {
8686
work_dir.run_jj(["file", "chmod", "n", "file"]).success();
8787
let output = work_dir.run_jj(["debug", "tree"]);
8888
insta::assert_snapshot!(output, @r#"
89-
file: Ok(Conflicted([Some(File { id: FileId("587be6b4c3f93f93c489c0111bba5596147a26cb"), executable: false }), Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: false }), Some(File { id: FileId("8ba3a16384aacc37d01564b28401755ce8053f51"), executable: false })]))
89+
file: Ok(Conflicted([Some(File { id: FileId("587be6b4c3f93f93c489c0111bba5596147a26cb"), executable: false, copy_id: CopyId("") }), Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: false, copy_id: CopyId("") }), Some(File { id: FileId("8ba3a16384aacc37d01564b28401755ce8053f51"), executable: false, copy_id: CopyId("") })]))
9090
[EOF]
9191
"#);
9292
let output = work_dir.run_jj(["file", "show", "file"]);
@@ -158,7 +158,7 @@ fn test_chmod_file_dir_deletion_conflicts() {
158158
// The file-dir conflict cannot be chmod-ed
159159
let output = work_dir.run_jj(["debug", "tree", "-r=file_dir"]);
160160
insta::assert_snapshot!(output, @r#"
161-
file: Ok(Conflicted([Some(File { id: FileId("78981922613b2afb6025042ff6bd878ac1994e85"), executable: false }), Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: false }), Some(Tree(TreeId("133bb38fc4e4bf6b551f1f04db7e48f04cac2877")))]))
161+
file: Ok(Conflicted([Some(File { id: FileId("78981922613b2afb6025042ff6bd878ac1994e85"), executable: false, copy_id: CopyId("") }), Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: false, copy_id: CopyId("") }), Some(Tree(TreeId("133bb38fc4e4bf6b551f1f04db7e48f04cac2877")))]))
162162
[EOF]
163163
"#);
164164
let output = work_dir.run_jj(["file", "show", "-r=file_dir", "file"]);
@@ -180,7 +180,7 @@ fn test_chmod_file_dir_deletion_conflicts() {
180180
// The file_deletion conflict can be chmod-ed
181181
let output = work_dir.run_jj(["debug", "tree", "-r=file_deletion"]);
182182
insta::assert_snapshot!(output, @r#"
183-
file: Ok(Conflicted([Some(File { id: FileId("78981922613b2afb6025042ff6bd878ac1994e85"), executable: false }), Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: false }), None]))
183+
file: Ok(Conflicted([Some(File { id: FileId("78981922613b2afb6025042ff6bd878ac1994e85"), executable: false, copy_id: CopyId("") }), Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: false, copy_id: CopyId("") }), None]))
184184
[EOF]
185185
"#);
186186
let output = work_dir.run_jj(["file", "show", "-r=file_deletion", "file"]);
@@ -214,7 +214,7 @@ fn test_chmod_file_dir_deletion_conflicts() {
214214
"###);
215215
let output = work_dir.run_jj(["debug", "tree", "-r=file_deletion"]);
216216
insta::assert_snapshot!(output, @r#"
217-
file: Ok(Conflicted([Some(File { id: FileId("78981922613b2afb6025042ff6bd878ac1994e85"), executable: true }), Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: true }), None]))
217+
file: Ok(Conflicted([Some(File { id: FileId("78981922613b2afb6025042ff6bd878ac1994e85"), executable: true, copy_id: CopyId("") }), Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: true, copy_id: CopyId("") }), None]))
218218
[EOF]
219219
"#);
220220
let output = work_dir.run_jj(["file", "show", "-r=file_deletion", "file"]);

cli/tests/test_resolve_command.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -680,8 +680,8 @@ fn test_simplify_conflict_sides() {
680680
// Even though the tree-level conflict is a 4-sided conflict, each file is
681681
// materialized as a 2-sided conflict.
682682
insta::assert_snapshot!(work_dir.run_jj(["debug", "tree"]), @r#"
683-
fileA: Ok(Conflicted([Some(File { id: FileId("d00491fd7e5bb6fa28c517a0bb32b8b506539d4d"), executable: false }), Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: false }), Some(File { id: FileId("0cfbf08886fca9a91cb753ec8734c84fcbe52c9f"), executable: false }), Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: false }), Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: false }), Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: false }), Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: false })]))
684-
fileB: Ok(Conflicted([Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: false }), Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: false }), Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: false }), Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: false }), Some(File { id: FileId("d00491fd7e5bb6fa28c517a0bb32b8b506539d4d"), executable: false }), Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: false }), Some(File { id: FileId("0cfbf08886fca9a91cb753ec8734c84fcbe52c9f"), executable: false })]))
683+
fileA: Ok(Conflicted([Some(File { id: FileId("d00491fd7e5bb6fa28c517a0bb32b8b506539d4d"), executable: false, copy_id: CopyId("") }), Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: false, copy_id: CopyId("") }), Some(File { id: FileId("0cfbf08886fca9a91cb753ec8734c84fcbe52c9f"), executable: false, copy_id: CopyId("") }), Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: false, copy_id: CopyId("") }), Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: false, copy_id: CopyId("") }), Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: false, copy_id: CopyId("") }), Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: false, copy_id: CopyId("") })]))
684+
fileB: Ok(Conflicted([Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: false, copy_id: CopyId("") }), Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: false, copy_id: CopyId("") }), Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: false, copy_id: CopyId("") }), Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: false, copy_id: CopyId("") }), Some(File { id: FileId("d00491fd7e5bb6fa28c517a0bb32b8b506539d4d"), executable: false, copy_id: CopyId("") }), Some(File { id: FileId("df967b96a579e45a18b8251732d16804b2e56a55"), executable: false, copy_id: CopyId("") }), Some(File { id: FileId("0cfbf08886fca9a91cb753ec8734c84fcbe52c9f"), executable: false, copy_id: CopyId("") })]))
685685
[EOF]
686686
"#);
687687
insta::assert_snapshot!(work_dir.run_jj(["resolve", "--list"]), @r"

lib/src/absorb.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,12 @@ pub async fn split_hunks_to_trees(
106106
let left_path = entry.path.source();
107107
let right_path = entry.path.target();
108108
let (left_value, right_value) = entry.values?;
109-
let (left_text, executable) = match to_file_value(left_value) {
110-
Ok(Some(mut value)) => (value.read_all(left_path).await?, value.executable),
109+
let (left_text, executable, copy_id) = match to_file_value(left_value) {
110+
Ok(Some(mut value)) => (
111+
value.read_all(left_path).await?,
112+
value.executable,
113+
value.copy_id,
114+
),
111115
// New file should have no destinations
112116
Ok(None) => continue,
113117
Err(reason) => {
@@ -156,7 +160,11 @@ pub async fn split_hunks_to_trees(
156160
.store()
157161
.write_file(left_path, &mut new_text.as_slice())
158162
.await?;
159-
Merge::normal(TreeValue::File { id, executable })
163+
Merge::normal(TreeValue::File {
164+
id,
165+
executable,
166+
copy_id: copy_id.clone(),
167+
})
160168
};
161169
tree_builder.set_or_remove(left_path.to_owned(), new_tree_value);
162170
}

0 commit comments

Comments
 (0)