分支A,分支B上都有一个文件foo.el。该文件在不同分支上呈现较多的差异,如何合并该文件,并放到分支C?
已有尝试的步骤:
- 使用magit-file-checkout 把分支A上的foo.el给放到分支C上
- 然后使用magit-ediff-dwim中的range,选择分支B再选择文件foo.el。这个时候会打开一个control panel和两个界面分别为目前C分支上(原A分支上)和B分支上的两个版本的fool.el。可以通过快捷键跳转到差异的代码块并选择应用到不同版本上。
这个方法的问题是:
- 由于代码块位置错开,导致apply差异会把另一个版本上的功能块替代了,所以只能手动编辑代码。
- 由1引出的问题:在magit-ediff上如果要手动修改需要按!进入编辑模式,但是界面和control panel上没看到任何状态提示,而且需要跳frame回到control panel按!退出编辑模式再需要下一个差异块。这里的操作按键就很多了。
自己的想法:
- 如果magit-ediff在两个窗口上选择diff部分并指定插入某个版本的某个位置就好了。
- 或者直接在AB分支之间选择要的部分放到新的buffer里窗口,最终可以导出文件stage到C分支。可能对magit 和 ediff不太熟,也许有这个功能我还没找到。
- 结合以上,目前感觉还是magit-find-file直接开多个文件直接改来的快。
想问问大家合并文件的工作流会是怎样的?
ediff UI在resolve merge conflicts这方面有点不友好, 主要是它的操作都需要在一个自带的面板里操作,和其他同类软件的UI不太一样.
实际上你可以先用UI更直观易懂的同类软件来解决冲突, 熟悉基本操作后再转到emacs (甚至转到emacs后也可以用smerge来做, 见 https://emacs.stackexchange.com/questions/16469/how-to-merge-git-conflicts-in-emacs).
基本上此类软件的界面都差不多, 会同时显示原始版本, A的修改, B的修改, 用户可只选A, 只选B, 或者同时保留A和B的修改. 选择完后会给用户微调最终文本的机会.
我推荐用p4merge, 界面简单直观,还能解决图片冲突,性能也很好. 其他主流编辑器和IDE(例如 IntelliJ IDEA)也都提供了此类功能, 以下是我~/.gitconfig的相关设置,
[mergetool]
# no prompt before merge each file
prompt = false
[mergetool.emacs]
cmd = ediff.sh "$LOCAL" "$REMOTE" "$BASE" "$MERGED"
[mergetool.emacsclient]
cmd = MYEMACSCLIENT=emacsclient ediff.sh "$LOCAL" "$REMOTE" "$BASE" "$MERGED"
[mergetool.p4merge]
# @see https://git-scm.com/book/en/v2/Customizing-Git-Git-Configuration
cmd = p4merge "$BASE" "$LOCAL" "$REMOTE" "$MERGED"
trustExitCode = false
[mergetool.idea]
cmd = idea merge \"$LOCAL\" \"$REMOTE\" \"$BASE\" \"$MERGED\"
在git命令行中可以用 git mergetool -t p4merge来调用p4merge解决冲突.
ediff.sh是我魔改ediff用的,操作有点硬核且依赖于我的emacs配置(GitHub - redguardtoo/emacs.d: Fast and robust Emacs setup. · GitHub),不建议一般人使用,其代码如下,
#!/bin/sh
[ -z "$MYEMACSCLIENT" ] && MYEMACSCLIENT="emacs"
# emacsclient won't work in git mergetool
# $1=$LOCAL $2=$REMOTE $3=$BASE $4=$MERGED
if [ "$MYEMACSCLIENT" = "emacs" ]; then
$MYEMACSCLIENT -nw -Q --eval "(setq startup-now t)" -l "$HOME/.emacs.d/init.el" --eval "(progn (setq ediff-quit-hook 'kill-emacs) (if (file-readable-p \"$3\") (ediff-merge-files-with-ancestor \"$1\" \"$2\" \"$3\" nil \"$4\") (ediff-merge-files \"$1\" \"$2\" nil \"$4\")))"
else
$MYEMACSCLIENT -nw --eval "(progn (setq ediff-quit-hook 'kill-emacs) (if (file-readable-p \"$3\") (ediff-merge-files-with-ancestor \"$1\" \"$2\" \"$3\" nil \"$4\") (ediff-merge-files \"$1\" \"$2\" nil \"$4\")))"
fi
``
3 个赞
花几分钟熟悉一下 ediff 吧,在magit buffer 移动光标到有冲突的文件,安 e 就调出ediff .
感谢回复。ediff UI确实差强人意,但是也算能用,有机会学习你的配置魔改一下再加上p4merge。
现在我解决冲突基本很少用 ediff 了,直接就用默认的 smerge
(defvar-keymap smerge-basic-map
"n" #'smerge-next
"p" #'smerge-prev
"r" #'smerge-resolve
"a" #'smerge-keep-all
"b" #'smerge-keep-base
"o" #'smerge-keep-lower ; for the obsolete keep-other
"l" #'smerge-keep-lower
"m" #'smerge-keep-upper ; for the obsolete keep-mine
"u" #'smerge-keep-upper
"E" #'smerge-ediff
"C" #'smerge-combine-with-next
"R" #'smerge-refine
"C-m" #'smerge-keep-current
"=" (define-keymap :name "Diff"
"<" (cons "base-upper" #'smerge-diff-base-upper)
">" (cons "base-lower" #'smerge-diff-base-lower)
"=" (cons "upper-lower" #'smerge-diff-upper-lower)))
默认绑定在 C-c ^ 前缀下,( 当有冲突的时候 从magit 或diff-mode中 RET 进入冲突的 buffer 后 就自动启用了 smerge-mode. 就可以用上面的keybinding 了。
(with-eval-after-load 'smerge-mode (define-key goto-map "v" smerge-basic-map))
我给改成了 M-gv. 然后 使用GitHub - jixiuf/emacs-leadkey: a modal leader-key package for Emacs. · GitHub 把 M-g 绑定成 SPC g
所以 最终用起来就是 SPC g v n for smerge-next
>>>
aaa
===
bbb
<<<<
smerge-keep-lower: 保留下面的版本,即 "bbb"
smerge-keep-upper: 保留上面的版本,即 "aaa"
2 个赞