MergeWithBailOnConflict attempts to merge a branch into the current branch and aborts if there are conflicts. Returns true if merge was successful, false if there were conflicts (but abort succeeded). Returns an error if the merge failed for a reason other than conflicts, or if both merge and abort
(path, branch string)
| 91 | // Returns true if merge was successful, false if there were conflicts (but abort succeeded). |
| 92 | // Returns an error if the merge failed for a reason other than conflicts, or if both merge and abort fail. |
| 93 | func MergeWithBailOnConflict(path, branch string) (bool, error) { |
| 94 | _, mergeErr := Run(context.Background(), path, "merge", "--no-ff", branch) |
| 95 | if mergeErr == nil { |
| 96 | return true, nil |
| 97 | } |
| 98 | |
| 99 | // Detect "merge in progress" via MERGE_HEAD: presence means git stopped on conflicts and is waiting for resolution. |
| 100 | // Other merge failures (e.g., invalid ref, untracked-file overwrite that git auto-aborts) leave no MERGE_HEAD, |
| 101 | // and should surface as real errors rather than be silently treated as conflicts. |
| 102 | merging, err := mergeInProgress(path) |
| 103 | if err != nil { |
| 104 | return false, fmt.Errorf("merge failed: %w; could not check merge state: %w", mergeErr, err) |
| 105 | } |
| 106 | if !merging { |
| 107 | return false, mergeErr |
| 108 | } |
| 109 | |
| 110 | if _, abortErr := Run(context.Background(), path, "merge", "--abort"); abortErr != nil { |
| 111 | return false, fmt.Errorf("merge failed with error: %w, and abort also failed with error: %w", mergeErr, abortErr) |
| 112 | } |
| 113 | return false, nil |
| 114 | } |
| 115 | |
| 116 | // mergeInProgress reports whether the repository at path is in the middle of a merge. |
| 117 | func mergeInProgress(path string) (bool, error) { |