git rebase 冲突之后的 vc-working-revision 怎么算?

目前的 vc-git-working-revision 实现是这样的:

一旦 git rebase <newbase> 产生冲突,函数返回就变成了 <newbase>

感觉这样不太合理,明明 rebase 过程中止了,大部分文件还处于 rebase 之前的状态,此时应该取 REBASE_HEAD 才对。

但既然 git 已经把 HEAD 指针都改了,那么是不是有它的合理性?(或者说 vc-git 这边只好将错就错了?)


重现步骤:

  • 终端
  1. git checkout feat-xxx
  2. git rebase <newbase>
  3. 提示有冲突
  • Emacs 端
  1. M-: (vc-git-working-revision nil)
  2. 返回 "<newbase>“
  3. 期望 "feat-xxx"

没觉得代码有什么问题。 vc-working-revision的文档是"Return the repository version from which FILE was checked out."

在命令行下git log看一下最后一个commit是什么。

“明明 rebase 过程中止了”也不准确,有conflict不等于终止rebase,终止rebase的命令行是git rebase --abort, 没有运行此命令行就还在rebase过程中。

确实"过程中止“不准确,应该说还没完成。

git log 是根据 HEAD 来的,所以显示的是 newbase 分支。

我还是不太理解为什么 rebase 冲突未解决的时候时候,HEAD 要指向 newbase ,假如 shell prompt 跟随 HEAD,就会出现让人困惑的场景,例如:

[🔀 feat-xx] $ git rebase newbase
Auto-merging file.el
CONFLICT (content): Merge conflict in file.el
error: could not apply efab581... *1
...
[🔀 newbase] $ <---- 假如 shell prompt 跟随 HEAD,这里就该显示 newbase 了。

好在 fish-shell 的 fish_git_prompt 命令就比较合理,它返回的是 <feat-xx>|REBASE-i:

git 本身也有个 git-prompt(我刚刚才知道),它也会处理 rebase-mrege 状态:

我为啥纠结这个问题呢。

因为我在 mode line 上显示了 vc 状态,所以面临的窘境跟 shell prompt 显示错误是一回事:当 rebase 冲突,我就看到 mode 上的分支名称从 feat-xx 切到了 <newbase>

(另,这里还有个错误,就是当 <newbase> 名字小于 7 的时候就会出错,因为 vc-git-mode-line-string 有个 (substring ... 0 7) 的操作,但如果返回 feat-xx|REBASE-i 就远大于 7 了,暂时避开了错误😄)

我现在是修复了 vc-git-mode-line-string 函数,当 rebsse 发生冲突时,让其返回 feat-xx|REBASE-i/m(参考 fish_shell_prompt),而不是抛错。但这个修复我感觉太个人化了,所以没打算 PR。

vc-working-revision 如果我理解没错的话,也应当修复,并且可以 PR 试试看会不会被采纳。

rebase的意思就是基于newbase再一个个apply当前branch的commit。既然commit因为冲突没apply上,HEAD不就是newbase的最后一个commit吗?

建议你不用纠结这时的状态显示了. 下一步马上就是git mergetoolgit rebase --continue, git rebase --abort.

你可以读一下电子书 pro git, Git - Book

熟悉git 命令行操作再学emacs的vc或magit就很简单了。