@@ -477,9 +477,17 @@ fn apply_changes(
477477 }
478478 scm_record:: SelectedContents :: Binary {
479479 old_description : _,
480- new_description : _ ,
480+ new_description : Some ( _ ) ,
481481 } => {
482- let value = select_right ( & path) ?;
482+ let value = override_file_executable_bit ( select_right ( & path) ?, executable) ;
483+ tree_builder. set_or_remove ( path, value) ;
484+ }
485+ scm_record:: SelectedContents :: Binary {
486+ old_description : _,
487+ new_description : None ,
488+ } => {
489+ // File contents emptied out, but file mode is not absent => write empty file.
490+ let value = write_file ( & path, & [ ] , executable) ?;
483491 tree_builder. set_or_remove ( path, value) ;
484492 }
485493 scm_record:: SelectedContents :: Text { contents } => {
@@ -1177,6 +1185,150 @@ mod tests {
11771185 ) ;
11781186 }
11791187
1188+ #[ test]
1189+ fn test_edit_diff_builtin_change_binary_file_with_unselected_file_mode_change ( ) {
1190+ let test_repo = TestRepo :: init ( ) ;
1191+ let store = test_repo. repo . store ( ) ;
1192+
1193+ let binary_file_path = repo_path ( "binary_file" ) ;
1194+ let left_tree = testutils:: create_tree_with ( & test_repo. repo , |builder| {
1195+ builder
1196+ . file ( binary_file_path, vec ! [ 0xff , 0x00 ] )
1197+ . executable ( false ) ;
1198+ } ) ;
1199+ let right_tree = testutils:: create_tree_with ( & test_repo. repo , |builder| {
1200+ builder
1201+ . file ( binary_file_path, vec ! [ 0xff , 0x01 ] )
1202+ . executable ( true ) ;
1203+ } ) ;
1204+
1205+ let ( changed_files, files) = make_diff ( store, & left_tree, & right_tree) ;
1206+ insta:: assert_debug_snapshot!( changed_files, @r#"
1207+ [
1208+ "binary_file",
1209+ ]
1210+ "# ) ;
1211+ insta:: assert_debug_snapshot!( files, @r#"
1212+ [
1213+ File {
1214+ old_path: None,
1215+ path: "binary_file",
1216+ file_mode: Unix(
1217+ 33188,
1218+ ),
1219+ sections: [
1220+ FileMode {
1221+ is_checked: false,
1222+ mode: Unix(
1223+ 33261,
1224+ ),
1225+ },
1226+ Binary {
1227+ is_checked: false,
1228+ old_description: Some(
1229+ "fb296c879f1852c0dca0 (2B)",
1230+ ),
1231+ new_description: Some(
1232+ "cc429d26cbaec338223b (2B)",
1233+ ),
1234+ },
1235+ ],
1236+ },
1237+ ]
1238+ "# ) ;
1239+
1240+ // Select only the binary change
1241+ let mut files = files;
1242+ for file in & mut files {
1243+ for section in & mut file. sections {
1244+ if let scm_record:: Section :: Binary { is_checked, .. } = section {
1245+ * is_checked = true ;
1246+ }
1247+ }
1248+ }
1249+
1250+ let expected_tree = testutils:: create_tree_with ( & test_repo. repo , |builder| {
1251+ builder
1252+ . file ( binary_file_path, vec ! [ 0xff , 0x01 ] )
1253+ . executable ( false ) ;
1254+ } ) ;
1255+ let actual_tree_id = apply_diff ( store, & left_tree, & right_tree, & changed_files, & files) ;
1256+ let actual_tree = store. get_root_tree ( & actual_tree_id) . unwrap ( ) ;
1257+ assert_eq ! (
1258+ expected_tree. id( ) ,
1259+ actual_tree. id( ) ,
1260+ "tree was different:\n expected tree:\n {}\n actual tree:\n {}" ,
1261+ dump_tree( store, & expected_tree. id( ) ) ,
1262+ dump_tree( store, & actual_tree. id( ) ) ,
1263+ ) ;
1264+ }
1265+
1266+ #[ test]
1267+ fn test_edit_diff_builtin_delete_binary_file_with_unselected_file_mode_change ( ) {
1268+ let test_repo = TestRepo :: init ( ) ;
1269+ let store = test_repo. repo . store ( ) ;
1270+
1271+ let binary_file_path = repo_path ( "binary_file" ) ;
1272+ let left_tree = testutils:: create_tree_with ( & test_repo. repo , |builder| {
1273+ builder. file ( binary_file_path, vec ! [ 0xff , 0x00 ] ) ;
1274+ } ) ;
1275+ let right_tree = testutils:: create_tree ( & test_repo. repo , & [ ] ) ;
1276+
1277+ let ( changed_files, files) = make_diff ( store, & left_tree, & right_tree) ;
1278+ insta:: assert_debug_snapshot!( changed_files, @r#"
1279+ [
1280+ "binary_file",
1281+ ]
1282+ "# ) ;
1283+ insta:: assert_debug_snapshot!( files, @r#"
1284+ [
1285+ File {
1286+ old_path: None,
1287+ path: "binary_file",
1288+ file_mode: Unix(
1289+ 33188,
1290+ ),
1291+ sections: [
1292+ FileMode {
1293+ is_checked: false,
1294+ mode: Absent,
1295+ },
1296+ Binary {
1297+ is_checked: false,
1298+ old_description: Some(
1299+ "fb296c879f1852c0dca0 (2B)",
1300+ ),
1301+ new_description: None,
1302+ },
1303+ ],
1304+ },
1305+ ]
1306+ "# ) ;
1307+
1308+ // Select only the binary change
1309+ let mut files = files;
1310+ for file in & mut files {
1311+ for section in & mut file. sections {
1312+ if let scm_record:: Section :: Binary { is_checked, .. } = section {
1313+ * is_checked = true ;
1314+ }
1315+ }
1316+ }
1317+
1318+ let expected_tree = testutils:: create_tree_with ( & test_repo. repo , |builder| {
1319+ builder. file ( binary_file_path, vec ! [ ] ) ;
1320+ } ) ;
1321+ let actual_tree_id = apply_diff ( store, & left_tree, & right_tree, & changed_files, & files) ;
1322+ let actual_tree = store. get_root_tree ( & actual_tree_id) . unwrap ( ) ;
1323+ assert_eq ! (
1324+ expected_tree. id( ) ,
1325+ actual_tree. id( ) ,
1326+ "tree was different:\n expected tree:\n {}\n actual tree:\n {}" ,
1327+ dump_tree( store, & expected_tree. id( ) ) ,
1328+ dump_tree( store, & actual_tree. id( ) ) ,
1329+ ) ;
1330+ }
1331+
11801332 #[ test]
11811333 fn test_edit_diff_builtin_delete_file ( ) {
11821334 let test_repo = TestRepo :: init ( ) ;
0 commit comments