@@ -8,7 +8,7 @@ use git2::build::CheckoutBuilder;
88use gitbutler_branch_actions:: internal:: list_virtual_branches;
99use gitbutler_branch_actions:: { update_workspace_commit, RemoteBranchFile } ;
1010use gitbutler_cherry_pick:: { ConflictedTreeKey , RepositoryExt as _} ;
11- use gitbutler_command_context:: CommandContext ;
11+ use gitbutler_command_context:: { gix_repository_for_merging , CommandContext } ;
1212use gitbutler_commit:: {
1313 commit_ext:: CommitExt ,
1414 commit_headers:: { CommitHeadersV2 , HasCommitHeaders } ,
@@ -18,6 +18,7 @@ use gitbutler_operating_modes::{
1818 operating_mode, read_edit_mode_metadata, write_edit_mode_metadata, EditModeMetadata ,
1919 OperatingMode , EDIT_BRANCH_REF , WORKSPACE_BRANCH_REF ,
2020} ;
21+ use gitbutler_oxidize:: { git2_to_gix_object_id, gix_to_git2_index, GixRepositoryExt } ;
2122use gitbutler_project:: access:: { WorktreeReadPermission , WorktreeWritePermission } ;
2223use gitbutler_reference:: { ReferenceName , Refname } ;
2324use gitbutler_repo:: { rebase:: cherry_rebase, RepositoryExt } ;
@@ -28,42 +29,47 @@ use serde::Serialize;
2829
2930pub mod commands;
3031
32+ /// Returns an index of the the tree of `commit` if it is unconflicted, *or* produce a merged tree
33+ /// if `commit` is conflicted. That tree is turned into an index that records the conflicts that occurred
34+ /// during the merge.
3135fn get_commit_index ( repository : & git2:: Repository , commit : & git2:: Commit ) -> Result < git2:: Index > {
3236 let commit_tree = commit. tree ( ) . context ( "Failed to get commit's tree" ) ?;
3337 // Checkout the commit as unstaged changes
3438 if commit. is_conflicted ( ) {
3539 let base = commit_tree
3640 . get_name ( ".conflict-base-0" )
37- . context ( "Failed to get base" ) ?;
38- let base = repository
39- . find_tree ( base. id ( ) )
40- . context ( "Failed to find base tree" ) ?;
41- // Ours
41+ . context ( "Failed to get base" ) ?
42+ . id ( ) ;
4243 let ours = commit_tree
4344 . get_name ( ".conflict-side-0" )
44- . context ( "Failed to get base" ) ?;
45- let ours = repository
46- . find_tree ( ours. id ( ) )
47- . context ( "Failed to find base tree" ) ?;
48- // Theirs
45+ . context ( "Failed to get base" ) ?
46+ . id ( ) ;
4947 let theirs = commit_tree
5048 . get_name ( ".conflict-side-1" )
51- . context ( "Failed to get base" ) ?;
52- let theirs = repository
53- . find_tree ( theirs. id ( ) )
54- . context ( "Failed to find base tree" ) ?;
55-
56- let index = repository
57- . merge_trees ( & base, & ours, & theirs, None )
58- . context ( "Failed to merge trees" ) ?;
59-
60- Ok ( index)
49+ . context ( "Failed to get base" ) ?
50+ . id ( ) ;
51+
52+ let gix_repo = gix_repository_for_merging ( repository. path ( ) ) ?;
53+ // Merge without favoring a side this time to get a tree containing the actual conflicts.
54+ let mut merge_result = gix_repo. merge_trees (
55+ git2_to_gix_object_id ( base) ,
56+ git2_to_gix_object_id ( ours) ,
57+ git2_to_gix_object_id ( theirs) ,
58+ gix_repo. default_merge_labels ( ) ,
59+ gix_repo. tree_merge_options ( ) ?,
60+ ) ?;
61+ let merged_tree_id = merge_result. tree . write ( ) ?;
62+ let mut index = gix_repo. index_from_tree ( & merged_tree_id) ?;
63+ if !merge_result. index_changed_after_applying_conflicts (
64+ & mut index,
65+ gix:: merge:: tree:: TreatAsUnresolved :: git ( ) ,
66+ ) {
67+ tracing:: warn!( "There must be an issue with conflict-commit creation as re-merging the conflicting trees didn't yield a conflicting index." ) ;
68+ }
69+ gix_to_git2_index ( & index)
6170 } else {
6271 let mut index = git2:: Index :: new ( ) ?;
63- index
64- . read_tree ( & commit_tree)
65- . context ( "Failed to set index tree" ) ?;
66-
72+ index. read_tree ( & commit_tree) ?;
6773 Ok ( index)
6874 }
6975}
0 commit comments