Using emacs (and magit?) to visit a file in given commit/branch/etc

前端 未结 4 1557
无人及你
无人及你 2021-01-30 22:34

If I want to see how foo.bar looked like in some certain commit then I can invoke:

git show :foo.bar         


        
相关标签:
4条回答
  • 2021-01-30 23:06

    There's a package called git-timemachine that makes the process of viewing previous versions of a file almost completely seamless; see the link for installation instructions and a demo. (If you are already using MELPA, just do M-x package-install RET git-timemachine RET).

    The way it works is, you call M-x git-timemachine RET from a buffer visiting a tracked file. Then you can:

    • p Visit previous historic version
    • n Visit next historic version
    • w Copy the abbreviated hash of the current historic version
    • W Copy the full hash of the current historic version
    • q Exit the time machine.

    Note that if you know the hash of the commit you want to visit, the custom command from @phils' solution will serve you better for that specific use case. But for navigating between different versions of a file I find that using git-timemachine is even easier than using the functionality that VC provides.

    You can of course bind git-timemachine to a key binding of your choice.

    0 讨论(0)
  • 2021-01-30 23:08

    The canonical way to do that in Emacs is to use VC: C-x v ~ from the file's buffer will ask you for a revision and then show that file as it was at that revision. It should work for any control system supported by VC, such as Git, Bzr, ...

    0 讨论(0)
  • 2021-01-30 23:08

    If you are viewing the commit in magit you can just press Enter on the file or part of the file you are interested in.

    0 讨论(0)
  • 2021-01-30 23:29
    • C-xvl to view the file's history.
    • n and p to move between commits.
    • f to visit the file as of the commit at point.

    That's bound to log-view-find-revision, and if we look at the code we see the critical bit is:

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

    So we could wrap that in a custom function like so:

    (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)))
    

    Edit: Stefan has provided a better answer, but if you liked being able to select the file as well as the revision, here's a version of my function which maintains the interactive file selection, but uses the code from vc-revision-other-window for the revision handling.

    I concluded that using other-window by default does indeed make more sense, so I've done the same here -- unless you provide a prefix argument in which case it uses the current 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)))))
    

    I bind this command to C-xvC-f

    0 讨论(0)
提交回复
热议问题