@@ -157,7 +157,7 @@ enum ConflictIndexEntryPathHint {
157
157
}
158
158
159
159
/// A utility to help define which side is what in the [`Conflict`] type.
160
- #[ derive( Debug , Clone , Copy ) ]
160
+ #[ derive( Debug , Clone , Copy , Eq , PartialEq ) ]
161
161
enum ConflictMapping {
162
162
/// The sides are as described in the field documentation, i.e. `ours` is `ours`.
163
163
Original ,
@@ -175,13 +175,19 @@ impl ConflictMapping {
175
175
ConflictMapping :: Swapped => ConflictMapping :: Original ,
176
176
}
177
177
}
178
+ fn to_global ( self , global : ConflictMapping ) -> ConflictMapping {
179
+ match global {
180
+ ConflictMapping :: Original => self ,
181
+ ConflictMapping :: Swapped => self . swapped ( ) ,
182
+ }
183
+ }
178
184
}
179
185
180
186
impl Conflict {
181
187
/// Return `true` if this instance is considered unresolved based on the criterion specified by `how`.
182
188
pub fn is_unresolved ( & self , how : TreatAsUnresolved ) -> bool {
183
189
use crate :: blob;
184
- let content_merge_matches = |info : & ContentMerge | match how. content_merge {
190
+ let content_merge_unresolved = |info : & ContentMerge | match how. content_merge {
185
191
treat_as_unresolved:: ContentMerge :: Markers => matches ! ( info. resolution, blob:: Resolution :: Conflict ) ,
186
192
treat_as_unresolved:: ContentMerge :: ForcedResolution => {
187
193
matches ! (
@@ -192,20 +198,28 @@ impl Conflict {
192
198
} ;
193
199
match how. tree_merge {
194
200
treat_as_unresolved:: TreeMerge :: Undecidable => {
195
- self . resolution . is_err ( ) || self . content_merge ( ) . map_or ( false , |info| content_merge_matches ( & info) )
201
+ self . resolution . is_err ( )
202
+ || self
203
+ . content_merge ( )
204
+ . map_or ( false , |info| content_merge_unresolved ( & info) )
196
205
}
197
206
treat_as_unresolved:: TreeMerge :: EvasiveRenames | treat_as_unresolved:: TreeMerge :: ForcedResolution => {
198
207
match & self . resolution {
199
208
Ok ( success) => match success {
200
209
Resolution :: SourceLocationAffectedByRename { .. } => false ,
201
- Resolution :: Forced ( _) => how. tree_merge == treat_as_unresolved:: TreeMerge :: ForcedResolution ,
210
+ Resolution :: Forced ( _) => {
211
+ how. tree_merge == treat_as_unresolved:: TreeMerge :: ForcedResolution
212
+ || self
213
+ . content_merge ( )
214
+ . map_or ( false , |merged_blob| content_merge_unresolved ( & merged_blob) )
215
+ }
202
216
Resolution :: OursModifiedTheirsRenamedAndChangedThenRename {
203
217
merged_blob,
204
218
final_location,
205
219
..
206
- } => final_location. is_some ( ) || merged_blob. as_ref ( ) . map_or ( false , content_merge_matches ) ,
220
+ } => final_location. is_some ( ) || merged_blob. as_ref ( ) . map_or ( false , content_merge_unresolved ) ,
207
221
Resolution :: OursModifiedTheirsModifiedThenBlobContentMerge { merged_blob } => {
208
- content_merge_matches ( merged_blob)
222
+ content_merge_unresolved ( merged_blob)
209
223
}
210
224
} ,
211
225
Err ( _failure) => true ,
@@ -249,6 +263,7 @@ impl Conflict {
249
263
match failure {
250
264
ResolutionFailure :: OursRenamedTheirsRenamedDifferently { merged_blob } => * merged_blob,
251
265
ResolutionFailure :: Unknown
266
+ | ResolutionFailure :: OursDirectoryTheirsNonDirectoryTheirsRenamed { .. }
252
267
| ResolutionFailure :: OursModifiedTheirsDeleted
253
268
| ResolutionFailure :: OursModifiedTheirsRenamedTypeMismatch
254
269
| ResolutionFailure :: OursModifiedTheirsDirectoryThenOursRenamed {
@@ -321,6 +336,17 @@ pub enum ResolutionFailure {
321
336
/// The path at which `ours` can be found in the tree - it's in the same directory that it was in before.
322
337
renamed_unique_path_to_modified_blob : BString ,
323
338
} ,
339
+ /// *ours* is a directory, but *theirs* is a non-directory (i.e. file), which wants to be in its place, even though
340
+ /// *ours* has a modification in that subtree.
341
+ /// Rename *theirs* to retain that modification.
342
+ ///
343
+ /// Important: there is no actual modification on *ours* side, so *ours* is filled in with *theirs* as the data structure
344
+ /// cannot represent this case.
345
+ // TODO: Can we have a better data-structure? This would be for a rewrite though.
346
+ OursDirectoryTheirsNonDirectoryTheirsRenamed {
347
+ /// The non-conflicting path of *their* non-tree entry.
348
+ renamed_unique_path_of_theirs : BString ,
349
+ } ,
324
350
/// *ours* was added (or renamed into place) with a different mode than theirs, e.g. blob and symlink, and we kept
325
351
/// the symlink in its original location, renaming the other side to `their_unique_location`.
326
352
OursAddedTheirsAddedTypeMismatch {
@@ -376,8 +402,10 @@ pub struct Options {
376
402
/// If `None`, tree irreconcilable tree conflicts will result in [resolution failures](ResolutionFailure).
377
403
/// Otherwise, one can choose a side. Note that it's still possible to determine that auto-resolution happened
378
404
/// 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.
405
+ /// If `Some(…)`, irreconcilable conflicts are reconciled by making a choice.
406
+ /// Note that [`Conflict::entries()`] will still be set, to not degenerate information, even though they then represent
407
+ /// the entries what would fit the index if no forced resolution was performed.
408
+ /// It's up to the caller to handle that information mindfully.
381
409
pub tree_conflicts : Option < ResolveWith > ,
382
410
}
383
411
@@ -386,7 +414,10 @@ pub struct Options {
386
414
pub enum ResolveWith {
387
415
/// On irreconcilable conflict, choose neither *our* nor *their* state, but keep the common *ancestor* state instead.
388
416
Ancestor ,
389
- /// On irreconcilable conflict, choose *our* side
417
+ /// On irreconcilable conflict, choose *our* side.
418
+ ///
419
+ /// Note that in order to get something equivalent to *theirs*, put *theirs* into the side of *ours*,
420
+ /// swapping the sides essentially.
390
421
Ours ,
391
422
}
392
423
@@ -439,6 +470,9 @@ pub mod apply_index_entries {
439
470
}
440
471
} ,
441
472
Err ( failure) => match failure {
473
+ ResolutionFailure :: OursDirectoryTheirsNonDirectoryTheirsRenamed {
474
+ renamed_unique_path_of_theirs,
475
+ } => ( Some ( renamed_unique_path_of_theirs. as_bstr ( ) ) , conflict. ours . location ( ) ) ,
442
476
ResolutionFailure :: OursRenamedTheirsRenamedDifferently { .. } => {
443
477
( Some ( conflict. theirs . location ( ) ) , conflict. ours . location ( ) )
444
478
}
0 commit comments