Emacs:在magit状态缓冲区中暂存或取消暂存更改时更新git-gutter注释

9
我使用git-gutter来显示我对版本控制文件所做的更改,使用magit进行分阶段/提交/差异等操作。
在项目中工作时,我通常始终保持一个magit-status窗口处于打开状态。我遇到的问题是,当我在magit-status缓冲区中暂存或取消暂存更改,然后切换回显示我刚更新状态的文件的窗口时,git-gutter产生的边缘注释没有自动调整。(我目前的解决方法是按下SPCBackspace,然后按下C-x C-s保存文件以触发更新,但这不太有效率。)
我查看了git-gutter.el,果然它提供了一个名为git-gutter:update-hooks的可定制变量,其设置为
(after-save-hook after-revert-hook window-configuration-change-hook)

默认情况下,Emacs并没有与切换窗口相关的钩子函数。所以,我需要将正确的钩子函数添加到列表中就可以了。当然,我也查看了Elisp手册的各个部分,但是并没有找到我需要的内容。另外,magit是否提供了一个在暂存或取消暂存更改时运行的钩子函数呢?


编辑:

如果您正在阅读这篇文章,因为您也遇到了类似的问题:下面两个答案都是有效的解决方案!对于较新版本的 magit @lunaryorn的解决方案简短而简洁。 @Jordon Biondo的解决方案需要添加一些自定义代码,但是提供了通用的建议,可以创建自定义钩子函数并将它们注入到现有功能中。因此,由于我只能接受一个答案:通过给这两个回答者点赞来提高您在stackoverflow上的声望 :)


我简要查看了Magit源代码,没有看到在暂存函数的末尾、调用过程函数的末尾或刷新缓冲区函数上有任何钩子。因此,一种可能性是为magit-stage-item创建自己的函数,并将您的git-gutter更新函数放置在其末尾。虽然这可能有点过度,但post-command-hook每次眨眼或打喷嚏时都会运行(我想包括眨眼)。 - lawlist
1
@lawlist 在每次操作后,Magit会在存储库的任何缓冲区中运行'magit-revert-buffer-hook'。 - user355252
1
@lunaryorn -- 谢谢你 -- 我的 Magit 安装没有那个钩子,所以我会查看最新版本并看看它有什么提供。 - lawlist
3个回答

8

编辑: 使用最新版本的magit和git-gutter,这不再需要如此多的配置,请参阅lunaryorns答案以获取更加实时和简单的解决方案。


原始答案:

切换窗口方法可能有点过度,因为您将会刷新超过您需要的。

Magit没有提供before/after stage/unstage hooks,但我们可以使用advice来创建自己的hooks!

您可以为stage和unstage hook定义两个变量。

(defvar my-magit-after-stage-hooks nil
  "Hooks to be run after staging one item in magit.")

(defvar my-magit-after-unstage-hooks nil
  "Hooks to be run after unstaging one item in magit.")

有一个非常好的函数可以运行钩子: run-hooks,我们将使用函数建议magit-stage-itemmagit-unstage-item之后运行自定义钩子。

(defadvice magit-stage-item (after run-my-after-stage-hooks activate)
  "Run `my-magit-after-stage-hooks` after staging an item in magit."
  (when (called-interactively-p 'interactive)
    (run-hooks 'my-magit-after-stage-hooks)))

(defadvice magit-unstage-item (after run-my-after-unstage-hooks activate)
  "Run `my-magit-after-unstage-hooks` after unstaging an item in magit."
  (when (called-interactively-p 'interactive)
    (run-hooks 'my-magit-after-unstage-hooks)))

对于我们的钩子,我们只需要遍历所有缓冲区,并在适用时刷新git-gutter,因为我们不知道哪些是已暂存或未暂存的。因此,我们将在所有正在运行git-gutter-mode的可见缓冲区上刷新git-gutter显示。(如果您想要执行所有git-gutter缓冲区,请删除get-buffer-window调用。)

(defun my-refresh-visible-git-gutter-buffers ()
  "Refresh git-gutter-mode on all visible git-gutter-mode buffers."
  (dolist (buff (buffer-list))
    (with-current-buffer buff
      (when (and git-gutter-mode (get-buffer-window buff))
        (git-gutter-mode t)))))

最后,将您的钩子函数添加到您的自定义钩子中即可!
(add-hook 'my-magit-after-unstage-hooks
          'my-refresh-visible-git-gutter-buffers)
(add-hook 'my-magit-after-stage-hooks
          'my-refresh-visible-git-gutter-buffers)

理想情况下,我们应该知道哪些文件被暂存/未暂存,并仅刷新这些缓冲区。如果您可以在更深层次的magit函数中使用环绕建议并获取您正在操作的magit状态缓冲区项目的名称,并仅刷新该项目,则会更好。但这是一个很好的开始!auto git gitter refreshing

1
这太棒了!非常感谢您抽出时间对我的问题进行如此详尽的回答。我在我的*scratch*缓冲区中评估了您发布的代码,它似乎正好做我想要的事情。多次点赞真的太棒了 ;) 但是说真的,我从中学到了很多,所以再次感谢! - itsjeyd

6

这是我需要用当前的magit完成的事情:

(add-hook 'magit-post-refresh-hook
          #'git-gutter:update-all-windows)

git-gutter:update-all-windows 命令对我没有任何效果,除非我直接在带有 Git gutter 的缓冲区之一中运行它。这可能是由于 git-gutter 最近的更改,因为我记得你的修复在九月份对我有效! - ntc2
这对我来说仍然正常工作,我刚刚更新了所有的包。 我正在使用 global-git-gutter-mode 运行。 - Mattias Bengtsson
我还有(add-hook 'magit-status-mode-hook #'magit-filenotify-mode),不确定是否重要。 - Mattias Bengtsson
我还没有尝试将 magit-filenotify-mode 添加到 magit-status-mode-hook 中,但它依赖于另一个包:https://github.com/magit/magit-filenotify。 - ntc2

2
请注意,当前版本的Magit不会使用`magit-revert-buffer-hook`。因此,lunaryorn的解决方案可能无法正常工作。
您可以添加git-gutter更新钩子函数magit-after-revert-hookmagit-not-reverted-hook,当Magit刷新所有来自当前存储库的已访问缓冲区时调用这些函数(例如,在提交或“g”命令之后)。
(add-hook 'git-gutter:update-hooks 'magit-after-revert-hook)
(add-hook 'git-gutter:update-hooks 'magit-not-reverted-hook)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接