118

My recent Git merge has resulted in a large number of conflicts. My current approach is to search for the next occurence of '<<<' and then perform the merge by standard text editing.

Question: is there a way Emacs can support merging using the information availabe in Git about my version, their version and the base version of the file?


Edit: This question has a different scope than this related question, since it is not limited to invoking ediff.

Beginner
  • 2,661
  • 3
  • 17
  • 25
  • 9
    If you were to use Magit, you could load up the status buffer and then press `e` on files shown as conflicting. Magit would launch `ediff` to do the merging and prompt you afterwards to confirm your changes, then you could stage the merged file. – wvxvw Sep 09 '15 at 08:27
  • @Beginner: 3 other people thought it was a duplicate, and I was the last vote. Why: the other thread cited gives the same answers (`smerge` and `vc-resolve-conflict`, as well as one on `ediff`) and has been around longer. I agree that the first thread could use a better title, though. – Dan Sep 10 '15 at 11:35
  • 1
    @Dan I disagree: it is a different question and that the answer are similar does not change that. – Beginner Sep 10 '15 at 11:59
  • @Beginner: as you like. It looks like a duplicate to me, but feel free to vote to reopen. – Dan Sep 10 '15 at 12:02
  • @Dan ok, fair enough. – Beginner Sep 10 '15 at 12:04
  • @Dan I think both Beginner and you have valid arguments (though I have voted for this to be reopened). I was wondering whether it would be correct/appropriate to edit the title of the other question, to make it more generic? – Iqbal Ansari Sep 10 '15 at 13:52
  • 1
    @IqbalAnsari: I think the other thread needs a better title so people can find it more easily. In fact, I think Beginner's thread title would be great for it. However, let's wait just a little bit to see if people want to reopen this thread. If not, I'd be in favor of renaming the first thread with Beginner's title. – Dan Sep 10 '15 at 13:57
  • 1
    And for what it's worth, I think this is a good question with good answers. It's just that I also think it's a duplicate -- but others may not share that opinion (about the duplication, that is). – Dan Sep 10 '15 at 13:58

3 Answers3

130

You might want to try out smerge-mode just open the conflicted file and do M-xsmerge-modeRET. It will highlight all the conflicted regions. It also adds keybindings to easily resolve the conflicts, consult its documenation C-hfsmerge-modeRET to know them.

Default prefix

I find the default prefix for smerge-mode C-c^ cumbersome so I have changed it to C-cv

(setq smerge-command-prefix "\C-cv")

Important keybindings

For me the most important bindings are:

  • smerge-next bound to smerge-command-prefixn to move to next conflict.
  • smerge-previous bound to smerge-command-prefixp to move to previous conflict.
  • smerge-keep-current bound to smerge-command-prefixRET to keep the version the cursor is on.
  • smerge-keep-mine bound to smerge-command-prefixm to keep your changes.
  • smerge-keep-other bound to smerge-command-prefixo to keep other changes.
  • smerge-ediff bound to smerge-command-prefixE to start an ediff session to merge the conflicts. This is same as vc-resolve-conflicts (thanks @phils and @Malabarba for pointing this out).

Enabling smerge-mode automatically

UPDATE: The following is relevant only on Emacs versions before 25.1, the following can cause problems on later versions, see https://github.com/magit/magit/issues/3897

Additionally you might be interested in automatically enabling smerge-mode when visiting a file/buffer with conflict markers you can use something like the following to achieve this

(defun my-enable-smerge-maybe ()
  (when (and buffer-file-name (vc-backend buffer-file-name))
    (save-excursion
      (goto-char (point-min))
      (when (re-search-forward "^<<<<<<< " nil t)
        (smerge-mode +1)))))

(add-hook 'buffer-list-update-hook #'my-enable-smerge-maybe)

Note that I am using buffer-list-update-hook and not find-file-hook since most of the times I get conflicts in a buffer which is already open in emacs in which case find-file-hook is of no help.

Also check other methods mentioned in this answer.

alper
  • 1,238
  • 11
  • 30
Iqbal Ansari
  • 7,468
  • 1
  • 28
  • 31
  • 1
    *(1)* Don't forget `smerge-ediff`. *(2)* What Emacs version are you on? On the current emacs master branch, smerge turns on automatically. *(3)* Why are you using `buffer-list-update-hook` instead of `find-file-hook`? – Malabarba Sep 09 '15 at 11:32
  • 4
    For added clarification, note that `smerge-ediff` and `vc-resolve-conflicts` are the same thing. – phils Sep 09 '15 at 11:55
  • @Malabarba **1)** I did mention that `smerge-mode`'s keybindings are documented in, its documentation. Maybe I can quote the manual here for completeness. Thanks for the feedback. **2)** I am on v24.5, though I do try out master branch sometimes, I do not remember smerge being turned automatically (is it a recent change?). **3)** That is because most of the times I get conflicts in already open buffers, in which case I would need to explicitly turn on `smerge-mode` – Iqbal Ansari Sep 11 '15 at 03:01
  • @IqbalAnsari is there any reason to not have `smerge-mode` enabled all the time? Perhaps it doesn't do much until invoked. – PythonNut Sep 14 '15 at 03:45
  • @PythonNut Good question, unfortunately I don't have an answer since I never tried keeping it enabled all the time, its worth trying out though – Iqbal Ansari Sep 14 '15 at 04:47
  • I went and read the code. `smerge-mode` does indeed do minimal work. In fact the only thing it really does is check of there are any conflicts in the buffer, using a method like yours, but which handles more edge cases. I think I'm going to give enabling it permanently a shot. – PythonNut Sep 16 '15 at 03:29
  • With `M-x customize-group smerge ` you can set `smerge-command-prefix` with the string `^Cv` (That's an actual Control-C which you can enter in the customize field with `^Q ^C`. Some may prefer this to editing .emacs. – djb Mar 01 '18 at 13:48
  • `smerge-next` only works for conflict within a focused buffer. Not really useful considering that you can just search for `HEAD` word. – Hi-Angel Jan 29 '19 at 07:22
  • `my-enable-smerge-maybe` is redundant since [Emacs 25.1 which already enables `smerge-mode` from `vc-git-find-file-hook`](https://git.savannah.gnu.org/cgit/emacs.git/commit/?id=b5354531bac4ea261d66804ac81be222fdeaaec2). And it can cause infinite recursion because of this: https://github.com/magit/magit/issues/3897 – npostavs Jun 13 '19 at 15:41
  • Thanks for the heads up @npostavs, I have updated the answer to mention this – Iqbal Ansari Jun 17 '19 at 05:24
  • `my-enable-smerge-maybe` function destroys my `emacs` , I keep having `Variable binding depth exceeds max-specpdl-size error` and I unable to use emacs. be careful do not use it! Correct code piece is here: https://emacs.stackexchange.com/a/20811/18414 – alper Aug 27 '20 at 20:12
  • `"\C-cv"` may bounded to `*Python Check*` if elpy-mode is on – alper Sep 21 '20 at 21:21
  • I am getting following error : `Symbol’s function definition is void: smerge-basic-map` – alper Oct 30 '20 at 22:31
52

Edit: since this answer got more upvotes than I expected, I expanded it a bit.

To supplement the answer by @IqbalAnsari, you could also use vc-resolve-conflicts (as mentioned by others, it is an alias to smerge-ediff). This will start the ediff interface. On the left will be the first merge parent, and the second merge parent on the right. They are labelled on the modeline with MINE and OTHER respectively (Edit: In newer Emacs, these are now labelled as UPPER=HEAD* and LOWER=<sha>*). The merged buffer is shown below (see screenshot).

A screenshot of the ediff interface

Keybindings

  • Navigate through the conflicts with n and p.
  • Accept versions with a or b.
  • Look at the ancestor with /!
  • Quit the ediff session with q.

You can also navigate to the merged buffer with other-window and hand-edit in case resolving a conflict is more complicated than accepting a version. When you are done, you can save the buffer and quit Emacs as usual. For more help, just use ? during the ediff session, there are a whole bunch of very useful commands in there. I still don't know what half of them do!

suvayu
  • 1,568
  • 10
  • 17
  • 2
    This is the nicest method IMO. I have it bound to `C-x v <` , although in practice I'm more likely to be invoking it with Magit (as per wvxvw's comment). – phils Sep 09 '15 at 08:53
  • 2
    Since the year 2000 `vc-resolve-conflict` is an alias for `smerge-ediff`, which as the name suggests starts an Ediff session, not an Emerge session. By the way, the library header of `ediff.el` acknowledges `emerge.el`s influence and then goes on saying " The present version of Ediff supersedes Emerge. It provides a superior user interface and has numerous major features not found in Emerge. In particular, it can do patching, and 2-way and 3-way file comparison, merging, and directory operations." – tarsius Sep 11 '15 at 13:06
  • 7
    Also note that `magit-ediff-resolve` (`Em` or `e` on a file with conflicts) uses `smerge-ediff` internally. It does however override the `ediff-quit-hook` to provide a slightly better session finishing experience. Instead of telling you that you could save "the buffer" (there are several buffers), it asks you whether you want to save the buffer (while showing you its name). – tarsius Sep 11 '15 at 13:15
  • 1
    Is there a way to show 4 windows (ours, parent, theirs, workspace) like vimdiff? – user1133275 Jan 18 '17 at 09:20
  • For me, the top two windows were labeled UPPER and LOWER rather than MINE and OTHER. – user650654 Jul 09 '20 at 05:33
14

If you happen to use Spacemacs, I'd recommend activating "smerge-transient-state", which brings up a hydra menu with all possible smerge commands.

To do that, simply call M-x spacemacs/smerge-transient-state/body, which is per default assigned to SPC-g-r.

Here's a screenshot:

enter image description here

Editing your file should then be intuitive:

  1. Press n to go to the next hunk.
  2. Choose a merge action.
  3. Repeat until done.

EDIT: Solution for those without Spacemacs, adapted from John Kitchin's scimax, which I take is based off of the spacemacs solution and Iqbal's accepted answer above.

(use-package hydra)
(use-package smerge
  :config
  (defhydra scimax-smerge (:color red :hint nil)
    "
Navigate       Keep               other
----------------------------------------
_p_: previous  _c_: current       _e_: ediff
_n_: next      _m_: mine  <<      _u_: undo
_j_: up        _o_: other >>      _r_: refine
_k_: down      _a_: combine       _q_: quit
               _b_: base
"
    ("n" smerge-next)
    ("p" smerge-prev)
    ("c" smerge-keep-current)
    ("m" smerge-keep-mine)
    ("o" smerge-keep-other)
    ("b" smerge-keep-base)
    ("a" smerge-keep-all)
    ("e" smerge-ediff)
    ("j" previous-line)
    ("k" forward-line)
    ("r" smerge-refine)
    ("u" undo)
    ("q" nil :exit t))

  (defun enable-smerge-maybe ()
    (when (and buffer-file-name (vc-backend buffer-file-name))
      (save-excursion
        (goto-char (point-min))
        (when (re-search-forward "^<<<<<<< " nil t)
          (smerge-mode +1)
          (scimax-smerge/body))))))
Daniel
  • 3,563
  • 16
  • 41
  • How can I install `smerge-transient-mode` does it have an alternative for native emacs? – alper Mar 08 '22 at 16:25
  • Sorry, it seems that was a typo. What you really wanted was smerge-transient-state, which is a hydra defined by spacemacs. But with that said, I've expanded the answer to include a non-spacemacs solution. – Daniel Mar 09 '22 at 00:14
  • Thanks I was hoping to find a solution for native emacs, maybe this could help https://emacs.stackexchange.com/questions/20636/displaying-bindings-for-prefix-keymaps/20668#20668 – alper Mar 09 '22 at 09:24
  • right, just substitute the hydra for custom keybindings – Daniel Mar 09 '22 at 15:58