我希望能够使用ediff与"git mergetool".
我找到了一些改变源代码的补丁,我不想这样做.相反,我想在我的.gitconfig中添加ediff支持.
我知道git已经内置了对emerge的支持,但我更喜欢ediff.
我试图将这些行添加到我的.gitconfig:
[mergetool "ediff"] cmd = emacs --eval "(ediff-merge-files-with-ancestor \"$LOCAL\" \"$REMOTE\" \"$BASE\" nil \"$MERGED\")"
但是当我尝试使用"git mergetool --tool = ediff"运行时,我得到了这个:
eval: 1: Syntax error: "(" unexpected
我究竟做错了什么?
我用了一个更复杂的命令.据我记得,我从这个帖子http://kerneltrap.org/mailarchive/git/2007/6/28/250230得到它(可能和你指的一样).
[mergetool.ediff] cmd = emacs --eval \"\ (progn\ (defun ediff-write-merge-buffer ()\ (let ((file ediff-merge-store-file))\ (set-buffer ediff-buffer-C)\ (write-region (point-min) (point-max) file)\ (message \\\"Merge buffer saved in: %s\\\" file)\ (set-buffer-modified-p nil)\ (sit-for 1)))\ (setq ediff-quit-hook 'kill-emacs\ ediff-quit-merge-hook 'ediff-write-merge-buffer)\ (ediff-merge-files-with-ancestor \\\"$LOCAL\\\" \\\"$REMOTE\\\"\ \\\"$BASE\\\" nil \\\"$MERGED\\\"))\"
请注意,我已将其拆分为多行,以提高可读性并转义新行,\
因此git config将其视为单行.
我通常使用emacsclient来编辑例如提交消息.遗憾的是,上面的mergetool配置不使用emacsclient,当我试图让它与emacsclient一起工作时,我遇到了各种问题,包括emacsclient立即返回的事实.
但是你刚才提醒我这个问题,所以我可能会尽快解决这个问题.但是,如果其他人已经找到了一个当然很棒的解决方案;-)
我使用以下脚本作为mergetool工作得很好.
#!/bin/bash # test args if [ ! ${#} -ge 3 ]; then echo 1>&2 "Usage: ${0} LOCAL REMOTE MERGED BASE" echo 1>&2 " (LOCAL, REMOTE, MERGED, BASE can be provided by \`git mergetool'.)" exit 1 fi # tools _EMACSCLIENT=/usr/local/bin/emacsclient _BASENAME=/bin/basename _CP=/bin/cp _EGREP=/bin/egrep _MKTEMP=/bin/mktemp # args _LOCAL=${1} _REMOTE=${2} _MERGED=${3} if [ -r ${4} ] ; then _BASE=${4} _EDIFF=ediff-merge-files-with-ancestor _EVAL="${_EDIFF} \"${_LOCAL}\" \"${_REMOTE}\" \"${_BASE}\" nil \"${_MERGED}\"" else _EDIFF=ediff-merge-files _EVAL="${_EDIFF} \"${_LOCAL}\" \"${_REMOTE}\" nil \"${_MERGED}\"" fi # console vs. X if [ "${TERM}" = "linux" ]; then unset DISPLAY _EMACSCLIENTOPTS="-t" else _EMACSCLIENTOPTS="-c" fi # run emacsclient ${_EMACSCLIENT} ${_EMACSCLIENTOPTS} -a "" -e "(${_EVAL})" 2>&1 # check modified file if [ ! $(egrep -c '^(<<<<<<<|=======|>>>>>>>|####### Ancestor)' ${_MERGED}) = 0 ]; then _MERGEDSAVE=$(${_MKTEMP} --tmpdir `${_BASENAME} ${_MERGED}`.XXXXXXXXXX) ${_CP} ${_MERGED} ${_MERGEDSAVE} echo 1>&2 "Oops! Conflict markers detected in $_MERGED." echo 1>&2 "Saved your changes to ${_MERGEDSAVE}" echo 1>&2 "Exiting with code 1." exit 1 fi exit 0
要将它与`git mergetool'一起使用,请在git config中添加以下内容:
[merge] tool = ediff [mergetool "ediff"] cmd = /path/to/ediff-merge-script $LOCAL $REMOTE $MERGED $BASE trustExitCode = true
此外,您应该检查(在脚本中)使用的工具的路径以及穷人的控制台检测是否适合您.
脚本本身启动一个emacs客户端(或emacs后面跟一个emacs客户端-a ""
),并且ediff-merge-files-with-ancestor
或者ediff-merge-files
如果没有基本版本(例如合并两个独立创建相同路径/文件的分支时).
emacs客户端完成后,检查合并文件是否有冲突标记.如果找到这些文件,您的工作将被保存到临时文件中,脚本将以代码1退出,git将恢复合并文件的预合并工具内容.
当没有冲突标记存在时,脚本以代码0退出,git将合并视为成功.
重要提示:设置合并工具选项trustExitCode
来true
以及为冲突标记编辑后检查,如果你开始将无法正常工作emacsclient
与--no-wait
选项.
这是我的设置,它运行得相当好,至少使用Emacs 23.3.我使用的技巧是在钩子中使用(递归编辑),这样emacsclient就不会退出,直到建议的ediff-quit钩子调用(exit-recursive-edit).
我使用了一个建议的ediff-quit来确保退出 - 递归 - 编辑是最后完成的事情.
还有钩子来保存当前帧和窗口状态并在之后恢复它,钩子使当前帧填满屏幕.您可能希望修改它,但我发现合并全屏是最好的方法.
我没有解决中止ediff并使emacsclient返回非零退出的问题.
放入你的gitconfig:
[mergetool "ediff"] cmd = emacsclient --eval \"(git-mergetool-emacsclient-ediff \\\"$LOCAL\\\" \\\"$REMOTE\\\" \\\"$BASE\\\" \\\"$MERGED\\\")\" trustExitCode = true [mergetool] prompt = false [merge] tool = ediff
放入你的.emacs或同等的:
;; ;; Setup for ediff. ;; (require 'ediff) (defvar ediff-after-quit-hooks nil "* Hooks to run after ediff or emerge is quit.") (defadvice ediff-quit (after edit-after-quit-hooks activate) (run-hooks 'ediff-after-quit-hooks)) (setq git-mergetool-emacsclient-ediff-active nil) (defun local-ediff-frame-maximize () (let* ((bounds (display-usable-bounds)) (x (nth 0 bounds)) (y (nth 1 bounds)) (width (/ (nth 2 bounds) (frame-char-width))) (height (/ (nth 3 bounds) (frame-char-height)))) (set-frame-width (selected-frame) width) (set-frame-height (selected-frame) height) (set-frame-position (selected-frame) x y))) (setq ediff-window-setup-function 'ediff-setup-windows-plain) (setq ediff-split-window-function 'split-window-horizontally) (defun local-ediff-before-setup-hook () (setq local-ediff-saved-frame-configuration (current-frame-configuration)) (setq local-ediff-saved-window-configuration (current-window-configuration)) (local-ediff-frame-maximize) (if git-mergetool-emacsclient-ediff-active (raise-frame))) (defun local-ediff-quit-hook () (set-frame-configuration local-ediff-saved-frame-configuration) (set-window-configuration local-ediff-saved-window-configuration)) (defun local-ediff-suspend-hook () (set-frame-configuration local-ediff-saved-frame-configuration) (set-window-configuration local-ediff-saved-window-configuration)) (add-hook 'ediff-before-setup-hook 'local-ediff-before-setup-hook) (add-hook 'ediff-quit-hook 'local-ediff-quit-hook 'append) (add-hook 'ediff-suspend-hook 'local-ediff-suspend-hook 'append) ;; Useful for ediff merge from emacsclient. (defun git-mergetool-emacsclient-ediff (local remote base merged) (setq git-mergetool-emacsclient-ediff-active t) (if (file-readable-p base) (ediff-merge-files-with-ancestor local remote base nil merged) (ediff-merge-files local remote nil merged)) (recursive-edit)) (defun git-mergetool-emacsclient-ediff-after-quit-hook () (exit-recursive-edit)) (add-hook 'ediff-after-quit-hooks 'git-mergetool-emacsclient-ediff-after-quit-hook 'append)
除了我在上面的评论中发现的git vs bzr问题之外,我能够确认你需要逃避这些问题.
cmd = emacs --eval "\\(ediff-merge-files-with-ancestor \"$LOCAL\" \"$REMOTE\" \"$BASE\" nil \"$MERGED\"\\)"
请注意双反斜杠字符.我有点明白,他们需要(而不是单一的)来完成sh/bash引用和emacs启动引用机制.我会留给那些更好地掌握Emacs和shell引用来解释血腥细节的人.
-pmr