【问题标题】:Conflict resolution with Emacs Ediff: How can I take the changes of both versions使用 Emacs Ediff 解决冲突:如何同时更改两个版本
【发布时间】:2012-03-11 15:36:18
【问题描述】:

(问题改编自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。我可以通过点击键盘上的 ab 来选择变体 AB,但是如何将两者结合起来变种,一个接一个?

【问题讨论】:

  • 我想要这个很久了,谢谢你的推动。

标签: emacs emacs-ediff


【解决方案1】:

这与 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)

【讨论】:

  • 这很棒。为了完整起见,是否可以在快速帮助菜单中添加一行?
  • 这太棒了。结合~ 交换缓冲区的顺序,您可以得到 A 然后 B B 然后 A,这有时也会派上用场。
  • 键绑定d 与跳转到差异冲突。我把它绑定到B(大写)。
  • 太棒了,效果很好。正如@chengiz 建议的那样,如果您想在帮助消息中添加一行以记住它,请查看 ediff-help.el 中的变量 ediff-long-help-message-merge。它定义了整个表。您可以将它复制到您的初始化文件中,并在其中添加一个包含此命令的新行。
【解决方案2】:

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

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

手动合并应该留给用户。删除每个差异区域来自何处的线索对我来说并不合适。

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

M-:

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

【讨论】:

  • 重点不仅仅是删除差异标记,而是要求将两个差异都包含在最终结果中 - 强迫人们手动执行此操作是 PITA。通常,差异只是显示两个人将内容添加到列表的位置。显然,用户可以选择它并破坏他们的代码,但他们也可以通过按 A 或 B 来做到这一点......
  • 同意特雷。按下快捷键是因为用户想做某事。根据你的理由,他们应该删除 xa 和 xb 的快捷键……大多数其他体面的工具都具有这种先 A 然后 B 或 B 然后 A 的能力。 .. 这是我离开 edfiff 的唯一原因.. 由于这个短暂的到来,合并似乎很糟糕。
【解决方案3】:

是的,我完全想这样做!使用以下代码块,您可以通过键入 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))

【讨论】:

    【解决方案4】:

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

    如果按我预期的那样工作,那么您的缓冲区应该处于 smerge 次要模式,并且应该有一个用于 smerge 的菜单。该菜单包含您需要的一切。

    【讨论】:

    • 实际上与ediff 功能无关(它不使用smerge-mode——或者至少现在不使用,如果有的话),但如果你 正在使用smerge-mode
    猜你喜欢
    • 2015-11-26
    • 1970-01-01
    • 1970-01-01
    • 2015-07-02
    • 2018-10-26
    • 1970-01-01
    • 2018-05-28
    • 2012-07-20
    • 2013-06-04
    相关资源
    最近更新 更多