Использование emacs (и magit?) Для посещения файла в данной фиксации / ветке / и т. Д.

Если я хочу увидеть, как foo.bar выглядело в каком-то конкретном коммите <COMMIT_ID>, я могу вызвать:

git show <COMMIT_ID>:foo.bar

Приятно ... Как это сделать в emacs? Используете magit? Используете vc? Допустим, я захожу в файл foo.bar и хочу посмотреть, как он выглядел в <COMMIT_ID>.


person Dror    schedule 21.08.2014    source источник
comment
См. Ответ Кайла Мейера в [этой] [1] ветке [1]: emacs.stackexchange.com/questions/7655   -  person boclodoa    schedule 11.03.2015


Ответы (4)


Канонический способ сделать это в Emacs - использовать VC: C-x v ~ из буфера файла запросит у вас ревизию, а затем покажет этот файл таким, каким он был в этой ревизии. Он должен работать с любой системой управления, поддерживаемой VC, например Git, Bzr, ...

person Stefan    schedule 21.08.2014
comment
Это не работает для перемещенных файлов с параметром --follow. - person choroba; 29.09.2015
comment
Я думаю, что не работает, зависит от того, как вы на это смотрите. Но я согласен, что было бы неплохо, если бы вы могли попросить Emacs указать Git, чтобы он следил за переименованием при попытке найти состояние файла в конкретной ревизии. Я предлагаю вам M-x report-emacs-bug запросить эту функцию. - person Stefan; 29.09.2015
comment
В: Как заставить vc-revision-other-window (C-x v ~) не создавать файл (filename.~branch~), содержащий показанную версию исходного файла (filename)? - person Mekeor Melire; 16.09.2016

  • C-x v l для просмотра истории файла.
  • n и p для перемещения между коммитами.
  • 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)))

Изменить: Стефан дал лучший ответ, но если вам понравилась возможность выбрать файл, а также ревизию, вот версия моей функции, которая поддерживает интерактивный выбор файла, но использует код из 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-x v C-f

person phils    schedule 21.08.2014
comment
Это очень полезный ответ! Стефан, возможно, более точно ответил на этот вопрос, но я благодарен за то, что наткнулся на эту бесценную функцию. - person taranaki; 29.04.2015
comment
my-vc-visit-file-revision теперь поддерживает посещение старых версий исторических путей к файлам, которые больше не существуют. - person phils; 27.05.2020
comment
Пользователи Magit могут использовать M-x magit-find-file, который аналогичным образом поддерживает исторические ревизии и, кроме того, обеспечивает завершение отслеживаемых путей для указанной вами ревизии (поскольку она считывает ревизию первой). Очень хорошо! - person phils; 27.05.2020

Существует пакет под названием 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 к привязке клавиш по вашему выбору.

person itsjeyd    schedule 21.08.2014

Если вы просматриваете фиксацию в magit, вы можете просто нажать Enter на файле или части файла, который вас интересует.

person Robin Green    schedule 25.09.2015
comment
Да, ты можешь! Но есть ли способ посмотреть файл в коммите, который не был изменен для рассматриваемого вами коммита? - person kristianlm; 26.12.2016
comment
Да, скопируйте хеш фиксации, а затем проверьте эту фиксацию с помощью команды b. Если у вас есть незафиксированные изменения, либо зафиксируйте их, поместите в тайник или создайте новое дерево работы. - person Robin Green; 26.12.2016
comment
Спасибо @Robin, но я надеялся, что есть способ просмотреть файл в буфере, не проверяя его. Мы знаем, что это возможно, поскольку вы можете просмотреть измененные файлы, просто нажав клавишу ВВОД. В итоге я искал самую последнюю фиксацию, содержащую файл, а затем открывал файл из этой фиксации. - person kristianlm; 28.12.2016