@@ -276,6 +276,40 @@ func ResolveCustomCodeConflicts(ctx context.Context) error {
276276
277277 hadConflicts := false
278278
279+ // First pass: identify targets with conflicts and unstage those without conflicts
280+ // This is necessary because git add . stages everything, including targets that weren't regenerated
281+ for targetName , target := range wf .Targets {
282+ outDir := getTargetOutput (target )
283+
284+ // Check if this target has conflicted files
285+ checkConflictCmd := exec .Command ("git" , "diff" , "--name-only" , "--diff-filter=U" , "--" , outDir )
286+ conflictCheckOutput , err := checkConflictCmd .Output ()
287+ if err != nil {
288+ return fmt .Errorf ("failed to check for conflicts in target %s: %w" , targetName , err )
289+ }
290+
291+ hasConflicts := strings .TrimSpace (string (conflictCheckOutput )) != ""
292+
293+ if ! hasConflicts {
294+ // Unstage and restore this target's files to prevent them from being included in conflict resolution
295+ // This is necessary because the target was never regenerated in this run
296+ logger .Info (fmt .Sprintf ("Target %s has no conflicts, unstaging and restoring its files to HEAD" , targetName ))
297+
298+ // First unstage
299+ unstageCmd := exec .Command ("git" , "reset" , "--" , outDir )
300+ if output , err := unstageCmd .CombinedOutput (); err != nil {
301+ logger .Warn (fmt .Sprintf ("Failed to unstage target %s: %v\n Output: %s" , targetName , err , string (output )))
302+ }
303+
304+ // Then restore to HEAD state (removes modifications from working directory)
305+ checkoutCmd := exec .Command ("git" , "checkout" , "HEAD" , "--" , outDir )
306+ if output , err := checkoutCmd .CombinedOutput (); err != nil {
307+ logger .Warn (fmt .Sprintf ("Failed to restore target %s to HEAD: %v\n Output: %s" , targetName , err , string (output )))
308+ }
309+ }
310+ }
311+
312+ // Second pass: process targets with conflicts
279313 for targetName , target := range wf .Targets {
280314 outDir := getTargetOutput (target )
281315
@@ -289,6 +323,19 @@ func ResolveCustomCodeConflicts(ctx context.Context) error {
289323 continue
290324 }
291325
326+ // Check if this target actually has conflicted files from the current generation
327+ // Only targets that were regenerated and have conflicts should be processed
328+ checkConflictCmd := exec .Command ("git" , "diff" , "--name-only" , "--diff-filter=U" , "--" , outDir )
329+ conflictCheckOutput , err := checkConflictCmd .Output ()
330+ if err != nil {
331+ return fmt .Errorf ("failed to check for conflicts in target %s: %w" , targetName , err )
332+ }
333+
334+ if strings .TrimSpace (string (conflictCheckOutput )) == "" {
335+ logger .Info (fmt .Sprintf ("Target %s has no conflicts (not regenerated in this run), skipping conflict resolution" , targetName ))
336+ continue
337+ }
338+
292339 logger .Info (fmt .Sprintf ("Resolving conflicts for target %s" , targetName ))
293340
294341 // Step 1: Undo patch application - extract clean new generation from "ours" side
@@ -425,19 +472,48 @@ func completeConflictResolution(ctx context.Context, wf *workflow.Workflow) erro
425472
426473 logger .Info ("Completing conflict resolution registration" )
427474
475+ // First, identify which targets were part of the conflict resolution
476+ targetsInResolution := make (map [string ]bool )
477+ for targetName , target := range wf .Targets {
478+ outDir := getTargetOutput (target )
479+ checkCommitCmd := exec .Command ("git" , "log" , "-1" , "--grep=clean generation (conflict resolution)" , "--format=%H" , "--" , outDir )
480+ commitOutput , err := checkCommitCmd .Output ()
481+ if err == nil && strings .TrimSpace (string (commitOutput )) != "" {
482+ targetsInResolution [targetName ] = true
483+ logger .Info (fmt .Sprintf ("Target %s was part of conflict resolution" , targetName ))
484+ }
485+ }
486+
428487 targetPatches , err := getPatchesPerTarget (wf )
429488 if err != nil {
430489 return err
431490 }
432491
433- for _ , target := range wf .Targets {
492+ // Only revert patches for targets that were part of conflict resolution
493+ for targetName , target := range wf .Targets {
494+ if ! targetsInResolution [targetName ] {
495+ logger .Info (fmt .Sprintf ("Skipping patch revert for target %s (not part of conflict resolution)" , targetName ))
496+ continue
497+ }
498+
434499 if err := RevertCustomCodePatch (ctx , target ); err != nil {
435- return fmt .Errorf ("failed to revert custom code patch: %w" , err )
500+ // If reverting fails, it might be because the patch was already removed (user accepted ours)
501+ // Log but continue - we'll handle this in the next phase
502+ logger .Warn (fmt .Sprintf ("Could not revert patch for target %s (may already be reverted): %v" , targetName , err ))
436503 }
437504 }
438505
439506 for targetName , target := range wf .Targets {
440507 if targetPatches [targetName ] == "" {
508+ // Check if this target was part of the conflict resolution using the map we built earlier
509+ if ! targetsInResolution [targetName ] {
510+ // This target was not part of conflict resolution (wasn't regenerated)
511+ // Keep its existing patch unchanged
512+ logger .Info (fmt .Sprintf ("Target %s was not part of conflict resolution, preserving existing patch" , targetName ))
513+ continue
514+ }
515+
516+ // Target was part of conflict resolution but has no new patches
441517 // Check if there's actually a patch to clean up
442518 if patchFileExists (getTargetOutput (target )) {
443519 fmt .Printf ("No changes detected for target %s after conflict resolution, cleaning up patch registration\n " , targetName )
0 commit comments