使用emacs(和magit?)访问给定提交/分支等中的文件

32
如果我想查看某个特定提交 <COMMIT_ID> 中的 foo.bar 是什么样子的,那么我可以调用以下命令:
git show <COMMIT_ID>:foo.bar

不错... 我该如何在emacs中实现呢?使用magit吗?还是使用vc?假设我正在访问文件foo.bar,并且我想查看它在<COMMIT_ID>中的样子。


1
请查看Kyle Meyer在这个帖子中的回答。 - boclodoa
2
我可能误解了一些事情,但是M-x magit-find-file呢?它首先要求您选择一个版本,然后再让您打开一个文件... - Stefan Kamphausen
4个回答

33
在Emacs中实现该操作的标准方法是使用VC:C-x v ~。从文件缓冲区执行此命令将要求您选择一个版本,然后显示该版本下的文件。对于 VC 支持的任何控制系统,如Git、Bzr等都可使用该方法。

带有 --follow 选项的移动文件不起作用。 - choroba
我猜“不起作用”取决于你如何看待它。但我同意,如果你可以要求Emacs告诉Git在尝试查找特定修订版本下的“文件”状态时遵循重命名,那将是很好的。我建议您键入 M-x report-emacs-bug 来请求此功能。 - Stefan
如何使 vc-revision-other-window (C-x v ~) 不创建包含原始文件 (filename) 显示版本的文件 (filename.~branch~)? - Mekeor Melire
我本来期望TAB自动完成会在提示符上生成提交列表,但它没有(你需要手动输入/粘贴提交ID),所以phils的答案前三行对我更有帮助。 - Chrisuu

26
  • 使用C-xvl查看文件的历史记录。
  • 使用np在提交之间移动。
  • 使用f以点处提交的方式访问文件。

这是绑定到log-view-find-revision,如果我们查看代码,我们会看到关键部分是:

(switch-to-buffer (vc-find-revision file revision)))

所以我们可以像这样将其包装在自定义函数中:
(defun my-vc-visit-file-revision (file revision)
  "Visit FILE as it was at REVISION."
  (interactive
   (list (expand-file-name
          (read-file-name (if (buffer-file-name)
                              (format "File (%s): " (file-name-nondirectory
                                                     (buffer-file-name)))
                            "File: ")))
         (read-string "Revision: ")))
  (require 'vc)
  (switch-to-buffer
   (vc-find-revision file revision)))

编辑:Stefan提供了更好的答案,但如果您喜欢能够选择文件和修订版本,这里是我的函数版本,它保持交互式文件选择,但使用vc-revision-other-window中的代码进行修订处理。

我得出结论, 默认情况下使用其他窗口确实更有意义,因此我在这里也这样做了 - 除非您提供前缀参数,否则它将使用当前窗口。

(defun my-vc-visit-file-revision (file rev)
  "Visit revision REV of FILE in another window.
With prefix argument, uses the current window instead.
If the current file is named `F', the revision is named `F.~REV~'.
If `F.~REV~' already exists, use it instead of checking it out again."
  ;; based on `vc-revision-other-window'.
  (interactive
   (let ((file (expand-file-name
                (read-file-name
                 (if (buffer-file-name)
                     (format "File (%s): " (file-name-nondirectory
                                            (buffer-file-name)))
                   "File: ")))))
     (require 'vc)
     (list file (if (vc-backend file)
                    (vc-read-revision
                     "Revision to visit (default is working revision): "
                     (list file))
                  (vc-read-revision "Revision to visit: " t
                                    (or (vc-deduce-backend)
                                        (vc-responsible-backend file)))))))
  (require 'vc)
  (let ((revision (if (string-equal rev "")
                      (if (vc-backend file)
                          (vc-working-revision file)
                        (error "No revision specified for unregistered file %s"
                               file))
                    rev))
        (backend (or (vc-backend file)
                     (vc-deduce-backend)
                     (vc-responsible-backend file)))
        (visit (if current-prefix-arg
                   'switch-to-buffer
                 'switch-to-buffer-other-window)))
    (condition-case err
        (funcall visit (vc-find-revision file revision backend))
      ;; The errors which can result when we request an invalid combination of
      ;; file and revision tend to be opaque side-effects of some unexpected
      ;; failure within the backend; so we simply trap everything and signal a
      ;; replacement error indicting the assumed cause.
      (error (error "File not found at revision %s: %s" revision file)))))

我将此命令绑定到C-xvC-f

1
这是一个非常有用的答案!Stefan可能更准确地回答了问题,但我很感激能够发现这个宝贵的功能。 - taranaki
my-vc-visit-file-revision 现在支持访问不存在的历史文件路径的旧版本。 - phils
2
Magit用户可以使用M-x magit-find-file,它同样支持历史版本,并且为您指定的修订版本提供跟踪路径的自动完成(因为它首先读取修订版本)。非常棒! - phils

9
有一个叫做 git-timemachine 的包,可以使查看文件的历史版本变得非常流畅。请参考链接中的安装说明和演示。(如果您已经在使用 MELPA,则只需执行 M-x package-install RET git-timemachine RET 即可)。
它的工作方式是,在访问跟踪文件的缓冲区时调用 M-x git-timemachine RET。然后您可以:
  • p 访问上一个历史版本
  • n 访问下一个历史版本
  • w 复制当前历史版本的缩写哈希值
  • W 复制当前历史版本的完整哈希值
  • q 退出时间机器。

请注意,如果您知道要访问的提交哈希值,则 @phils 解决方案中的自定义命令将更适合您的特定用例。但是对于在不同版本之间进行导航,我发现使用 git-timemachine 比使用 VC 提供的功能更容易。
当然,您可以将 git-timemachine 绑定到您选择的键绑定上。

7
如果您正在Magit中查看提交,您只需在您感兴趣的文件或文件的一部分上按Enter即可。

你可以!但是有没有一种方法可以查看提交中未被修改的文件呢? - kristianlm
是的,请复制提交哈希值,然后使用 b 命令检出该提交。如果您有未提交的更改,请将它们提交、存储或创建一个新的工作树。 - Robin Green
谢谢@Robin,但我希望有一种方法可以在不检出文件的情况下查看缓冲区中的文件。我们知道这是可能的,因为您只需按Enter键即可查看已修改的文件。最终,我查找了包含该文件的最新提交,然后从该提交中打开了该文件。 - kristianlm

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