@@ -8,7 +8,7 @@ use git2::build::CheckoutBuilder;
8
8
use gitbutler_branch_actions:: internal:: list_virtual_branches;
9
9
use gitbutler_branch_actions:: { update_workspace_commit, RemoteBranchFile } ;
10
10
use gitbutler_cherry_pick:: { ConflictedTreeKey , RepositoryExt as _} ;
11
- use gitbutler_command_context:: CommandContext ;
11
+ use gitbutler_command_context:: { gix_repository_for_merging , CommandContext } ;
12
12
use gitbutler_commit:: {
13
13
commit_ext:: CommitExt ,
14
14
commit_headers:: { CommitHeadersV2 , HasCommitHeaders } ,
@@ -18,6 +18,7 @@ use gitbutler_operating_modes::{
18
18
operating_mode, read_edit_mode_metadata, write_edit_mode_metadata, EditModeMetadata ,
19
19
OperatingMode , EDIT_BRANCH_REF , WORKSPACE_BRANCH_REF ,
20
20
} ;
21
+ use gitbutler_oxidize:: { git2_to_gix_object_id, gix_to_git2_index, GixRepositoryExt } ;
21
22
use gitbutler_project:: access:: { WorktreeReadPermission , WorktreeWritePermission } ;
22
23
use gitbutler_reference:: { ReferenceName , Refname } ;
23
24
use gitbutler_repo:: { rebase:: cherry_rebase, RepositoryExt } ;
@@ -28,42 +29,48 @@ use serde::Serialize;
28
29
29
30
pub mod commands;
30
31
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.
31
35
fn get_commit_index ( repository : & git2:: Repository , commit : & git2:: Commit ) -> Result < git2:: Index > {
32
36
let commit_tree = commit. tree ( ) . context ( "Failed to get commit's tree" ) ?;
33
37
// Checkout the commit as unstaged changes
34
38
if commit. is_conflicted ( ) {
35
39
let base = commit_tree
36
40
. 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 ( ) ;
42
43
let ours = commit_tree
43
44
. 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 ( ) ;
49
47
let theirs = commit_tree
50
48
. 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
+ gix:: merge:: tree:: apply_index_entries:: RemovalMode :: Mark ,
67
+ ) {
68
+ tracing:: warn!( "There must be an issue with conflict-commit creation as re-merging the conflicting trees didn't yield a conflicting index." ) ;
69
+ }
70
+ gix_to_git2_index ( & index)
61
71
} else {
62
72
let mut index = git2:: Index :: new ( ) ?;
63
- index
64
- . read_tree ( & commit_tree)
65
- . context ( "Failed to set index tree" ) ?;
66
-
73
+ index. read_tree ( & commit_tree) ?;
67
74
Ok ( index)
68
75
}
69
76
}
0 commit comments