@@ -57,6 +57,8 @@ pub struct TreatAsUnresolved {
57
57
58
58
///
59
59
pub mod treat_as_unresolved {
60
+ use crate :: tree:: TreatAsUnresolved ;
61
+
60
62
/// Which kind of content merges should be considered unresolved?
61
63
#[ derive( Default , Debug , Copy , Clone , Eq , PartialEq , Ord , PartialOrd , Hash ) ]
62
64
pub enum ContentMerge {
@@ -80,6 +82,34 @@ pub mod treat_as_unresolved {
80
82
/// with a [resolution strategy](super::ResolveWith).
81
83
ForcedResolution ,
82
84
}
85
+
86
+ /// Instantiation/Presets
87
+ impl TreatAsUnresolved {
88
+ /// Return an instance with the highest sensitivity to what should be considered unresolved as it
89
+ /// includes entries which have been resolved using a [merge strategy](super::ResolveWith).
90
+ pub fn forced_resolution ( ) -> Self {
91
+ Self {
92
+ content_merge : ContentMerge :: ForcedResolution ,
93
+ tree_merge : TreeMerge :: ForcedResolution ,
94
+ }
95
+ }
96
+
97
+ /// Return an instance that considers unresolved any conflict that Git would also consider unresolved.
98
+ /// This is the same as the `default()` implementation.
99
+ pub fn git ( ) -> Self {
100
+ Self :: default ( )
101
+ }
102
+
103
+ /// Only undecidable tree merges and conflict markers are considered unresolved.
104
+ /// This also means that renamed entries to make space for a conflicting one is considered acceptable,
105
+ /// making this preset the most lenient.
106
+ pub fn undecidable ( ) -> Self {
107
+ Self {
108
+ content_merge : ContentMerge :: Markers ,
109
+ tree_merge : TreeMerge :: Undecidable ,
110
+ }
111
+ }
112
+ }
83
113
}
84
114
85
115
impl Outcome < ' _ > {
@@ -157,7 +187,7 @@ enum ConflictIndexEntryPathHint {
157
187
}
158
188
159
189
/// A utility to help define which side is what in the [`Conflict`] type.
160
- #[ derive( Debug , Clone , Copy ) ]
190
+ #[ derive( Debug , Clone , Copy , Eq , PartialEq ) ]
161
191
enum ConflictMapping {
162
192
/// The sides are as described in the field documentation, i.e. `ours` is `ours`.
163
193
Original ,
@@ -175,13 +205,19 @@ impl ConflictMapping {
175
205
ConflictMapping :: Swapped => ConflictMapping :: Original ,
176
206
}
177
207
}
208
+ fn to_global ( self , global : ConflictMapping ) -> ConflictMapping {
209
+ match global {
210
+ ConflictMapping :: Original => self ,
211
+ ConflictMapping :: Swapped => self . swapped ( ) ,
212
+ }
213
+ }
178
214
}
179
215
180
216
impl Conflict {
181
217
/// Return `true` if this instance is considered unresolved based on the criterion specified by `how`.
182
218
pub fn is_unresolved ( & self , how : TreatAsUnresolved ) -> bool {
183
219
use crate :: blob;
184
- let content_merge_matches = |info : & ContentMerge | match how. content_merge {
220
+ let content_merge_unresolved = |info : & ContentMerge | match how. content_merge {
185
221
treat_as_unresolved:: ContentMerge :: Markers => matches ! ( info. resolution, blob:: Resolution :: Conflict ) ,
186
222
treat_as_unresolved:: ContentMerge :: ForcedResolution => {
187
223
matches ! (
@@ -192,20 +228,28 @@ impl Conflict {
192
228
} ;
193
229
match how. tree_merge {
194
230
treat_as_unresolved:: TreeMerge :: Undecidable => {
195
- self . resolution . is_err ( ) || self . content_merge ( ) . map_or ( false , |info| content_merge_matches ( & info) )
231
+ self . resolution . is_err ( )
232
+ || self
233
+ . content_merge ( )
234
+ . map_or ( false , |info| content_merge_unresolved ( & info) )
196
235
}
197
236
treat_as_unresolved:: TreeMerge :: EvasiveRenames | treat_as_unresolved:: TreeMerge :: ForcedResolution => {
198
237
match & self . resolution {
199
238
Ok ( success) => match success {
200
239
Resolution :: SourceLocationAffectedByRename { .. } => false ,
201
- Resolution :: Forced ( _) => how. tree_merge == treat_as_unresolved:: TreeMerge :: ForcedResolution ,
240
+ Resolution :: Forced ( _) => {
241
+ how. tree_merge == treat_as_unresolved:: TreeMerge :: ForcedResolution
242
+ || self
243
+ . content_merge ( )
244
+ . map_or ( false , |merged_blob| content_merge_unresolved ( & merged_blob) )
245
+ }
202
246
Resolution :: OursModifiedTheirsRenamedAndChangedThenRename {
203
247
merged_blob,
204
248
final_location,
205
249
..
206
- } => final_location. is_some ( ) || merged_blob. as_ref ( ) . map_or ( false , content_merge_matches ) ,
250
+ } => final_location. is_some ( ) || merged_blob. as_ref ( ) . map_or ( false , content_merge_unresolved ) ,
207
251
Resolution :: OursModifiedTheirsModifiedThenBlobContentMerge { merged_blob } => {
208
- content_merge_matches ( merged_blob)
252
+ content_merge_unresolved ( merged_blob)
209
253
}
210
254
} ,
211
255
Err ( _failure) => true ,
@@ -249,6 +293,7 @@ impl Conflict {
249
293
match failure {
250
294
ResolutionFailure :: OursRenamedTheirsRenamedDifferently { merged_blob } => * merged_blob,
251
295
ResolutionFailure :: Unknown
296
+ | ResolutionFailure :: OursDirectoryTheirsNonDirectoryTheirsRenamed { .. }
252
297
| ResolutionFailure :: OursModifiedTheirsDeleted
253
298
| ResolutionFailure :: OursModifiedTheirsRenamedTypeMismatch
254
299
| ResolutionFailure :: OursModifiedTheirsDirectoryThenOursRenamed {
@@ -321,6 +366,17 @@ pub enum ResolutionFailure {
321
366
/// The path at which `ours` can be found in the tree - it's in the same directory that it was in before.
322
367
renamed_unique_path_to_modified_blob : BString ,
323
368
} ,
369
+ /// *ours* is a directory, but *theirs* is a non-directory (i.e. file), which wants to be in its place, even though
370
+ /// *ours* has a modification in that subtree.
371
+ /// Rename *theirs* to retain that modification.
372
+ ///
373
+ /// Important: there is no actual modification on *ours* side, so *ours* is filled in with *theirs* as the data structure
374
+ /// cannot represent this case.
375
+ // TODO: Can we have a better data-structure? This would be for a rewrite though.
376
+ OursDirectoryTheirsNonDirectoryTheirsRenamed {
377
+ /// The non-conflicting path of *their* non-tree entry.
378
+ renamed_unique_path_of_theirs : BString ,
379
+ } ,
324
380
/// *ours* was added (or renamed into place) with a different mode than theirs, e.g. blob and symlink, and we kept
325
381
/// the symlink in its original location, renaming the other side to `their_unique_location`.
326
382
OursAddedTheirsAddedTypeMismatch {
@@ -376,8 +432,10 @@ pub struct Options {
376
432
/// If `None`, tree irreconcilable tree conflicts will result in [resolution failures](ResolutionFailure).
377
433
/// Otherwise, one can choose a side. Note that it's still possible to determine that auto-resolution happened
378
434
/// despite this choice, which allows carry forward the conflicting information, possibly for later resolution.
379
- /// If `Some(…)`, irreconcilable conflicts are reconciled by making a choice. This mlso means that [`Conflict::entries()`]
380
- /// won't be set as the conflict was officially resolved.
435
+ /// If `Some(…)`, irreconcilable conflicts are reconciled by making a choice.
436
+ /// Note that [`Conflict::entries()`] will still be set, to not degenerate information, even though they then represent
437
+ /// the entries what would fit the index if no forced resolution was performed.
438
+ /// It's up to the caller to handle that information mindfully.
381
439
pub tree_conflicts : Option < ResolveWith > ,
382
440
}
383
441
@@ -386,7 +444,10 @@ pub struct Options {
386
444
pub enum ResolveWith {
387
445
/// On irreconcilable conflict, choose neither *our* nor *their* state, but keep the common *ancestor* state instead.
388
446
Ancestor ,
389
- /// On irreconcilable conflict, choose *our* side
447
+ /// On irreconcilable conflict, choose *our* side.
448
+ ///
449
+ /// Note that in order to get something equivalent to *theirs*, put *theirs* into the side of *ours*,
450
+ /// swapping the sides essentially.
390
451
Ours ,
391
452
}
392
453
@@ -439,6 +500,9 @@ pub mod apply_index_entries {
439
500
}
440
501
} ,
441
502
Err ( failure) => match failure {
503
+ ResolutionFailure :: OursDirectoryTheirsNonDirectoryTheirsRenamed {
504
+ renamed_unique_path_of_theirs,
505
+ } => ( Some ( renamed_unique_path_of_theirs. as_bstr ( ) ) , conflict. ours . location ( ) ) ,
442
506
ResolutionFailure :: OursRenamedTheirsRenamedDifferently { .. } => {
443
507
( Some ( conflict. theirs . location ( ) ) , conflict. ours . location ( ) )
444
508
}
0 commit comments