问题
If I want to see how foo.bar
looked like in some certain commit <COMMIT_ID>
then I can invoke:
git show <COMMIT_ID>:foo.bar
Nice... How can I do it in emacs
? Using magit
? Using vc
? Say I am visiting the file foo.bar
and I want to look up how it looked in <COMMIT_ID>
.
回答1:
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, ...
回答2:
- 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)
(unless (vc-backend file)
(error "File %s is not under version control" file))
(list file (vc-read-revision
"Revision to visit (default is working revision): "
(list file)))))
(require 'vc)
(unless (vc-backend file)
(error "File %s is not under version control" file))
(let ((revision (if (string-equal rev "")
(vc-working-revision file)
rev))
(visit (if current-prefix-arg
'switch-to-buffer
'switch-to-buffer-other-window)))
(funcall visit (vc-find-revision file revision))))
回答3:
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 versionn
Visit next historic versionw
Copy the abbreviated hash of the current historic versionW
Copy the full hash of the current historic versionq
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.
回答4:
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.
来源:https://stackoverflow.com/questions/25420282/using-emacs-and-magit-to-visit-a-file-in-given-commit-branch-etc