2
2
use anyhow:: { Context , Result } ;
3
3
use gitbutler_cherry_pick:: RepositoryExt as _;
4
4
use gitbutler_command_context:: CommandContext ;
5
- use gitbutler_oxidize:: {
6
- GixRepositoryExt , ObjectIdExt , OidExt , RepoExt , git2_to_gix_object_id, gix_to_git2_oid,
7
- } ;
5
+ use gitbutler_oxidize:: { GixRepositoryExt , ObjectIdExt , OidExt } ;
8
6
use gitbutler_repo:: { RepositoryExt , SignaturePurpose } ;
9
7
use gitbutler_stack:: { Stack , VirtualBranchesHandle } ;
10
8
use gix:: merge:: tree:: TreatAsUnresolved ;
@@ -24,7 +22,7 @@ pub fn merge_worktree_with_workspace<'a>(
24
22
25
23
// The tree of where the gitbutler workspace is at
26
24
let workspace_tree = gix_repo
27
- . find_commit ( super :: head ( ctx) ?. to_gix ( ) ) ?
25
+ . find_commit ( super :: remerged_workspace_commit_v2 ( ctx) ?. to_gix ( ) ) ?
28
26
. tree_id ( ) ?
29
27
. detach ( ) ;
30
28
@@ -42,36 +40,32 @@ pub fn merge_worktree_with_workspace<'a>(
42
40
Ok ( ( outcome, conflict_kind) )
43
41
}
44
42
45
- /// Creates and returns a merge commit of all active branch heads.
46
- ///
47
- /// This is the base against which we diff the working directory to understand
48
- /// what files have been modified.
49
- ///
50
- /// This should be used to update the `gitbutler/workspace` ref with, which is usually
51
- /// done from [`update_workspace_commit()`], after any of its input changes.
52
- /// This is namely the conflicting state, or any head of the virtual branches.
53
- #[ instrument( level = tracing:: Level :: DEBUG , skip( ctx) ) ]
54
- pub fn head ( ctx : & CommandContext ) -> Result < git2:: Oid > {
43
+ /// Merge all currently stored stacks together into a new tree and return `(merged_tree, stacks, target_commit)` id accordingly.
44
+ /// `gix_repo` should be optimised for merging.
45
+ pub fn remerged_workspace_tree_v2 < ' git2_repo > (
46
+ ctx : & ' git2_repo CommandContext ,
47
+ gix_repo : & gix:: Repository ,
48
+ ) -> Result < ( git2:: Oid , Vec < Stack > , git2:: Commit < ' git2_repo > ) > {
55
49
let vb_state = VirtualBranchesHandle :: new ( ctx. project ( ) . gb_dir ( ) ) ;
56
50
let target = vb_state
57
51
. get_default_target ( )
58
52
. context ( "failed to get target" ) ?;
59
- let repo: & git2:: Repository = ctx. repo ( ) ;
60
-
53
+ let repo = ctx. repo ( ) ;
61
54
let mut stacks: Vec < Stack > = vb_state. list_stacks_in_workspace ( ) ?;
62
55
63
56
let target_commit = repo. find_commit ( target. sha ) ?;
64
- let mut workspace_tree = repo. find_real_tree ( & target_commit, Default :: default ( ) ) ?;
65
- let mut workspace_tree_id = git2_to_gix_object_id ( workspace_tree. id ( ) ) ;
57
+ let workspace_tree = repo. find_real_tree ( & target_commit, Default :: default ( ) ) ?;
58
+ let mut workspace_tree_id = workspace_tree. id ( ) . to_gix ( ) ;
66
59
67
- let gix_repo = ctx. gix_repo_for_merging ( ) ?;
68
60
let ( merge_options_fail_fast, conflict_kind) = gix_repo. merge_options_fail_fast ( ) ?;
69
- let merge_tree_id = git2_to_gix_object_id ( repo. find_commit ( target. sha ) ?. tree_id ( ) ) ;
61
+ let merge_tree_id = repo. find_commit ( target. sha ) ?. tree_id ( ) . to_gix ( ) ;
70
62
for stack in stacks. iter_mut ( ) {
71
- stack. migrate_change_ids ( ctx) . ok ( ) ; // If it fails thats ok - best effort migration
72
- let branch_head = repo. find_commit ( stack. head_oid ( & gix_repo) ?. to_git2 ( ) ) ?;
73
- let branch_tree_id =
74
- git2_to_gix_object_id ( repo. find_real_tree ( & branch_head, Default :: default ( ) ) ?. id ( ) ) ;
63
+ stack. migrate_change_ids ( ctx) . ok ( ) ; // If it fails that's ok - best effort migration
64
+ let branch_head = repo. find_commit ( stack. head_oid ( gix_repo) ?. to_git2 ( ) ) ?;
65
+ let branch_tree_id = repo
66
+ . find_real_tree ( & branch_head, Default :: default ( ) ) ?
67
+ . id ( )
68
+ . to_gix ( ) ;
75
69
76
70
let mut merge = gix_repo. merge_trees (
77
71
merge_tree_id,
@@ -90,11 +84,26 @@ pub fn head(ctx: &CommandContext) -> Result<git2::Oid> {
90
84
vb_state. set_stack ( stack. clone ( ) ) ?;
91
85
}
92
86
}
93
- workspace_tree = repo. find_tree ( gix_to_git2_oid ( workspace_tree_id) ) ?;
87
+ Ok ( ( workspace_tree_id. to_git2 ( ) , stacks, target_commit) )
88
+ }
89
+
90
+ /// Creates and returns a merge commit of all active branch heads.
91
+ ///
92
+ /// This is the base against which we diff the working directory to understand
93
+ /// what files have been modified.
94
+ ///
95
+ /// This should be used to update the `gitbutler/workspace` ref with, which is usually
96
+ /// done from [`update_workspace_commit()`], after any of its input changes.
97
+ /// This is namely the conflicting state, or any head of the virtual branches.
98
+ #[ instrument( level = tracing:: Level :: DEBUG , skip( ctx) ) ]
99
+ pub fn remerged_workspace_commit_v2 ( ctx : & CommandContext ) -> Result < git2:: Oid > {
100
+ let repo = ctx. repo ( ) ;
101
+ let gix_repo = ctx. gix_repo_for_merging ( ) ?;
102
+ let ( workspace_tree_id, stacks, target_commit) = remerged_workspace_tree_v2 ( ctx, & gix_repo) ?;
103
+ let workspace_tree = repo. find_tree ( workspace_tree_id) ?;
94
104
95
105
let committer = gitbutler_repo:: signature ( SignaturePurpose :: Committer ) ?;
96
106
let author = gitbutler_repo:: signature ( SignaturePurpose :: Author ) ?;
97
- let gix_repo = repo. to_gix ( ) ?;
98
107
let mut heads: Vec < git2:: Commit < ' _ > > = stacks
99
108
. iter ( )
100
109
. filter_map ( |stack| stack. head_oid ( & gix_repo) . ok ( ) )
0 commit comments