使用Emacs Ediff解决冲突:如何更改两个版本

时间:2012-03-11 15:36:18

标签: emacs emacs-ediff

(问题改编自How do I combine the two variants of a conflict in emacs' emerge?

我有一个包含合并冲突标记的文件。它看起来与此相似:

<<<<<<< HEAD
            522ADC9C14B2FD9D00F56BAD /* close_test_button.png in Resources */,
            522ADC9D14B2FD9D00F56BAD /* close_test_button@2x.png in Resources */,
            522ADCA014B2FDB100F56BAD /* test_failed.png in Resources */,
            522ADCA114B2FDB100F56BAD /* test_failed@2x.png in Resources */,
=======
            EC1633C014B2F3E3004B52E7 /* arrow.png in Resources */,
            EC1633C114B2F3E3004B52E7 /* arrow@2x.png in Resources */,
            EC1633C214B2F3E3004B52E7 /* groups.png in Resources */,
            EC1633C314B2F3E3004B52E7 /* groups@2x.png in Resources */,
>>>>>>> beta_2.8

我使用 M-x vc-resolve-conflicts 来启动Ediff。我可以通过在键盘上按 a b 来选择 A B 变体,但如何将两者结合使用变种,一个接一个?

4 个答案:

答案 0 :(得分:28)

这与Trey Jackson的有用答案完全相同,而且更为简单。按d将A和B复制到缓冲区C.

(defun ediff-copy-both-to-C ()
  (interactive)
  (ediff-copy-diff ediff-current-difference nil 'C nil
                   (concat
                    (ediff-get-region-contents ediff-current-difference 'A ediff-control-buffer)
                    (ediff-get-region-contents ediff-current-difference 'B ediff-control-buffer))))
(defun add-d-to-ediff-mode-map () (define-key ediff-mode-map "d" 'ediff-copy-both-to-C))
(add-hook 'ediff-keymap-setup-hook 'add-d-to-ediff-mode-map)

答案 1 :(得分:8)

您可以切换到缓冲区“C”并进行编辑。按 + 如果您已选择A或B来恢复差异。

如果你想要的是按一个键来自动删除差异标记,我只能说这似乎是一个糟糕的主意。

手动合并应留给用户。删除每个差异区域来自哪里的线索对我来说感觉不对。

您可以使用以下标记将标记自定义为空行:

M-:

(setq ediff-combination-pattern '("" A "" B "" Ancestor))

答案 2 :(得分:4)

vc-resolve-conflicts 的文档字符串表示它是 smerge-ediff 的别名。

如果它按照我的预期工作,那么你的缓冲区应该是smerge minor-mode,并且应该有一个smerge菜单。该菜单包含您需要的所有内容。

答案 3 :(得分:4)

是的,我完全想要这样做!使用以下代码块,您可以通过键入 d 来获取两者 - 这将从合并中获取缓冲区A和缓冲区B中的代码(按此顺序)缓冲液中。

此代码中唯一真正的困难是ediff在一个地方使用宏,并且需要使用新宏重新评估函数的编译版本。无论如何,尝试代码。使用Emacs 23.2进行测试。

(require 'ediff-init)           ;ensure the macro is defined, so we can override it

(defmacro ediff-char-to-buftype (arg)
  `(cond ((memq ,arg '(?a ?A)) 'A)
     ((memq ,arg '(?b ?B)) 'B)
     ((memq ,arg '(?c ?C)) 'C)
     ((memq ,arg '(?d ?D)) 'D)
     ))

(require 'ediff)

;; Literally copied from ediff-util
;; need to re-evaluate because it uses the macro defined above
;; and the compiled version needs to be re-compiled with the new definition
;; why a macro????
(defun ediff-diff-to-diff (arg &optional keys)
  "Copy buffer-X'th difference region to buffer Y \(X,Y are A, B, or C\).
If numerical prefix argument, copy the difference specified in the arg.
Otherwise, copy the difference given by `ediff-current-difference'.
This command assumes it is bound to a 2-character key sequence, `ab', `ba',
`ac', etc., which is used to determine the types of buffers to be used for
copying difference regions.  The first character in the sequence specifies
the source buffer and the second specifies the target.

If the second optional argument, a 2-character string, is given, use it to
determine the source and the target buffers instead of the command keys."
  (interactive "P")
  (ediff-barf-if-not-control-buffer)
  (or keys (setq keys (this-command-keys)))
  (if (eq arg '-) (setq arg -1)) ; translate neg arg to -1
  (if (numberp arg) (ediff-jump-to-difference arg))

  (let* ((key1 (aref keys 0))
     (key2 (aref keys 1))
     (char1 (ediff-event-key key1))
     (char2 (ediff-event-key key2))
     ediff-verbose-p)
(ediff-copy-diff ediff-current-difference
         (ediff-char-to-buftype char1)
         (ediff-char-to-buftype char2))
;; recenter with rehighlighting, but no messages
(ediff-recenter)))

(defun ediff-copy-D-to-C (arg)
  "Copy ARGth difference region from both buffers A and B to C.
ARG is a prefix argument.  If nil, copy the current difference region."
  (interactive "P")
  (ediff-diff-to-diff arg "dc"))

(defun ediff-copy-diff (n from-buf-type to-buf-type
              &optional batch-invocation reg-to-copy)
  (let* ((to-buf (ediff-get-buffer to-buf-type))
     ;;(from-buf (if (not reg-to-copy) (ediff-get-buffer from-buf-type)))
     (ctrl-buf ediff-control-buffer)
     (saved-p t)
     (three-way ediff-3way-job)
     messg
     ediff-verbose-p
     reg-to-delete reg-to-delete-beg reg-to-delete-end)

(setq reg-to-delete-beg
      (ediff-get-diff-posn to-buf-type 'beg n ctrl-buf))
(setq reg-to-delete-end
      (ediff-get-diff-posn to-buf-type 'end n ctrl-buf))

(if (eq from-buf-type 'D)
    ;; want to copy *both* A and B
    (if reg-to-copy
    (setq from-buf-type nil)
      (setq reg-to-copy (concat (ediff-get-region-contents n 'A ctrl-buf)
                (ediff-get-region-contents n 'B ctrl-buf))))
  ;; regular code
  (if reg-to-copy
      (setq from-buf-type nil)
    (setq reg-to-copy (ediff-get-region-contents n from-buf-type ctrl-buf))))

(setq reg-to-delete (ediff-get-region-contents
             n to-buf-type ctrl-buf
             reg-to-delete-beg reg-to-delete-end))

(if (string= reg-to-delete reg-to-copy)
    (setq saved-p nil) ; don't copy identical buffers
  ;; seems ok to copy
  (if (or batch-invocation (ediff-test-save-region n to-buf-type))
      (condition-case conds
      (progn
        (ediff-with-current-buffer to-buf
          ;; to prevent flags from interfering if buffer is writable
          (let ((inhibit-read-only (null buffer-read-only)))

        (goto-char reg-to-delete-end)
        (insert reg-to-copy)

        (if (> reg-to-delete-end reg-to-delete-beg)
            (kill-region reg-to-delete-beg reg-to-delete-end))
        ))
        (or batch-invocation
        (setq
         messg
         (ediff-save-diff-region n to-buf-type reg-to-delete))))
    (error (message "ediff-copy-diff: %s %s"
            (car conds)
            (mapconcat 'prin1-to-string (cdr conds) " "))
           (beep 1)
           (sit-for 2) ; let the user see the error msg
           (setq saved-p nil)
           )))
  )

;; adjust state of difference in case 3-way and diff was copied ok
(if (and saved-p three-way)
    (ediff-set-state-of-diff-in-all-buffers n ctrl-buf))

(if batch-invocation
    (ediff-clear-fine-differences n)
  ;; If diff3 job, we should recompute fine diffs so we clear them
  ;; before reinserting flags (and thus before ediff-recenter).
  (if (and saved-p three-way)
      (ediff-clear-fine-differences n))

  (ediff-refresh-mode-lines)

  ;; For diff2 jobs, don't recompute fine diffs, since we know there
  ;; aren't any.  So we clear diffs after ediff-recenter.
  (if (and saved-p (not three-way))
      (ediff-clear-fine-differences n))
  ;; Make sure that the message about saving and how to restore is seen
  ;; by the user
  (message "%s" messg))
))

;; add keybinding in a hook b/c the keymap isn't defined until the hook is run
(add-hook 'ediff-keymap-setup-hook 'add-d-to-ediff-mode-map)

(defun add-d-to-ediff-mode-map ()
  (define-key ediff-mode-map "d" 'ediff-copy-D-to-C))