如何使用Git查看一个文件的旧版本?

1932
有没有 Git 命令可以查看(以文本方式显示或者在 $PAGER 或 $EDITOR 中打开)特定文件的特定版本?

10
如何在Git仓库中获取旧版本的文件副本? - phuclv
3
如果您来到这个问题是想要查看二进制文件的旧版本(例如图片),最好还是回滚到旧的提交版本,查看您需要的内容,然后返回到最新版本。为此,请执行 git checkout <需要查看的提交版本号> 命令,之后执行 git checkout HEAD 命令即可。记住要保持原文意思并使翻译通俗易懂。 - Homero Esmeraldo
11个回答

2211
你可以使用git show与存储库根路径下的路径(相对路径为./../):
$ git show REVISION:path/to/file

请将REVISION替换为实际的版本号(可以是Git提交的SHA、标签名、分支名、相对提交名或Git中任何其他标识提交的方式)

例如,要查看4个提交之前的文件<repository-root>/src/main.c的版本,请使用以下命令:

$ git show HEAD~4:src/main.c

在Windows下使用Git时,即使是相对于当前目录的路径,也需要使用正斜杠。要了解更多信息,请查看git-show的手册页面。


6
似乎那并没有起作用--你试过了吗?针对"git show HEAD:path/to/file.c",我遇到了一个"ambiguous argument"错误。 - mike
5
必须提供完整的路径,从git仓库的顶层开始。 - richq
25
如果您在使用Windows操作系统,可能是由于路径分隔符所引起的问题。如果我运行git show HEAD:dir\subdir\file命令,则会出现模糊参数错误。如果我改为运行git show HEAD:dir/subdir/file命令,则会按预期正常工作。请注意,这两个命令的意思相同,只是路径分隔符不同。 - Matt McMinn
14
冒号后必须提供的路径是从git仓库根目录开始计算的。(这是下面给出的答案,但我认为它是作为对这个答案的评论提供的。) - Tyler
10
如果您想在Vim分屏中同时滚动它们,我写了一篇简短的博客文章来展示如何实现。 - Flaviu
显示剩余28条评论

300

按日期进行操作,如果提交是在过去的90天内,则看起来像这样

git show HEAD@{2013-02-25}:./fileInCurrentDirectory.txt
注意,HEAD@{2013-02-25} 在这个代码库中表示“2013年2月25日时HEAD的状态”(使用reflog),而不是“在历史记录中2013年2月25日之前的该分支中的最后一次提交”。
这很重要!这意味着,默认情况下,此方法仅适用于过去90天内的历史记录。否则,您需要执行以下操作:
git show $(git rev-list -1 --before="2013-02-26" HEAD):./fileInCurrentDirectory.txt

5
如果你在一个分支上,那么在使用master而不是HEAD@{2013-02-25}时,这个命令会很有用。 - funroll
1
你能否像 git log --since='2016-04-28 23:59:59 +0100' 这样包含时间? - dumbledad
15
这种语法使用 reflog 是非常重要的,并且应该强调,因为 reflog 并不包含所有提交。请参见 http://blog.endpoint.com/2014/05/git-checkout-at-specific-date.html。 - Alice Heaton
1
我错过的一件事是:在冒号 : 和文件名之间__不能__有空格。 - Abhishek Divekar
@AliceHeaton 这点无论如何都不能强调得太多了。(谢谢!) - Skippy le Grand Gourou
@AliceHeaton - 更新了(4年后,哈哈!) - Jim Hunziker

131

如果您喜欢图形用户界面(GUI),您可以使用gitk:

  1. 使用以下命令启动gitk:

  2. gitk /path/to/file
    
  3. 在屏幕顶部选择修订版本,例如按描述或日期。默认情况下,屏幕的下半部分显示该修订版本的差异(对应“补丁”单选按钮)。

  4. 要查看所选修订版的文件:

    • 点击“树形结构”单选按钮。这将显示该修订版本的文件树根目录。
    • 逐级浏览到您的文件。

8
这也适用于tig,它是一个基于curses的Git仓库查看器。 - Matthew G
1
@Paul Slocum: 可能是因为这个命令不是常规命令,也不是git的内置命令。我认为这个命令只适用于Windows操作系统。 - Envil
请注意,这似乎仅在您从 git 存储库的根目录开始时才起作用。 - Marc
如果你想使用gitk检查某个特定版本,你也可以使用这个快捷方式:gitk REVISION /path/to/file。当你想要检查某个特定版本时,这会非常方便。 - Christian.D
1
在Ubuntu上,运行sudo apt install gitk安装Gitk。 - run_the_race

112
您也可以使用git show命令指定一个提交哈希值(通常也称为提交ID)。


简介

git show <commitHash>:/path/to/file


步骤

  1. 使用git log /path/to/file显示给定文件的所有更改的日志
  2. 在更改列表中,它显示诸如commit 06c98...(其中06c98...是提交哈希值)的提交哈希值
  3. 复制提交哈希值
  4. 使用步骤3中的提交哈希值和步骤1中的path/to/file运行git show <commitHash>:/path/to/file命令。

注意: 在指定相对路径时添加./似乎很重要,即:git show b2f8be577166577c59b55e11cfff1404baf63a84:./flight-simulation/src/main/components/nav-horiz.html


1
如果您不知道文件路径,请使用 git show <SHA1> --name-only 命令获取它。 - Tiina
这个命令 op - 甚至可以从内存中自动完成 - 在已删除的目录上进行了测试... 没有比这更强大的了 gg - treyBake
debian 中,添加 ./ 对路径没有影响。 - Timo

54

除了Jim Hunziker的答案外,

您还可以从修订版中导出该文件,

git show HEAD@{2013-02-25}:./fileInCurrentDirectory.txt > old_fileInCurrentDirectory.txt
希望这能帮到你 :)

53

快速查看文件与旧版本的差异:

git show -1 filename.txt > 与文件的上一版本进行比较

git show -2 filename.txt > 与文件的倒数第二个版本进行比较

git show -3 fielname.txt > 与文件的倒数第三个版本进行比较


25
这些命令展示了对我来说当前版本的差异,但并未显示整个文件。 - Jean Paul
3
需要注意的是,这个答案适用于问题“如何显示最近提交中文件的差异?”而不是“如何使用Git查看旧版本文件?”,这是原始问题所问的。 - Mikko Rantalainen
区别在于: - 双冒号 - 在提交哈希和文件之间,评论者提到整个文件和与另一个旧版本的差异。 - Timo

34

git log -p 命令将展示每个提交的差异(除了合并提交),而不仅仅是提交记录。您可以按下 /,输入文件名,然后按下 enter 。按下 np 前往下一个/上一个匹配项。这样,您不仅可以看到文件中的更改,还可以查看提交信息。


4
似乎git log -pm也会显示合并提交。 - sanbor
7
您还可以运行 git log -p -- filename.txt 以将历史记录限制为所需文件。 - Jean Paul

9

方式1:(我更喜欢这个方式,不会丢失未提交的数据)

  1. 使用以下命令查找提交ID:git reflog

  2. 从提交中列出文件:git diff-tree --no-commit-id --name-only -r <commitHash>

    例如:

    git diff-tree --no-commit-id --name-only -r d2f9ba4
    d2f9ba4 是第一步骤中的提交ID。

  3. 使用以下命令打开所需文件:

    git show <commitHash>:/path/to/file

    例如:

    git show d2f9ba4:Src/Ext/MoreSwiftUI/ListCustom.swift
    Src/... 是第二步骤中的文件路径。


方式2:(有可能丢失未提交的数据)

  1. 使用以下命令查找提交ID:git reflog

  2. 将本地代码库强制重置到此提交:git reset --hard %commit ID%

    例如:

    git reset --hard c14809fa

  3. 进行必要的更改并将其提交到所需的分支。


警告:请小心使用第二种方法,因为在进行硬重置时,您将失去所有未提交的更改! - Enn Michael
是的,使用硬重置是可以的。这是因为重置是“硬”而不是“软”。但是你需要进行硬重置是因为可能会发生冲突。 - Andrew_STOP_RU_WAR_IN_UA

4
您可以使用以下脚本将文件的所有版本转储到单独的文件中:
例如:
git_dump_all_versions_of_a_file.sh path/to/somefile.txt

在另一个类似的问题中,这里提供了脚本。


1
git_rootgit_log_shortgit_log_message_for_commit都没有找到。 - mogsie
干得好!我把这个答案发到了两个不同的地方,刚刚删除了这一个并链接到另一个地方,在那里人们之前就告诉了我...谢谢 @mogsie! - Brad Parks
这个脚本非常有用! - XMAN

2

从给定的版本中获取多个文件的帮助程序

在尝试解决合并冲突时,这个帮助程序非常有用:

#!/usr/bin/env python3

import argparse
import os
import subprocess

parser = argparse.ArgumentParser()
parser.add_argument('revision')
parser.add_argument('files', nargs='+')
args = parser.parse_args()
toplevel = subprocess.check_output(['git', 'rev-parse', '--show-toplevel']).rstrip().decode()
for path in args.files:
    file_relative = os.path.relpath(os.path.abspath(path), toplevel)
    base, ext = os.path.splitext(path)
    new_path = base + '.old' + ext
    with open(new_path, 'w') as f:
        subprocess.call(['git', 'show', '{}:./{}'.format(args.revision, path)], stdout=f)

GitHub upstream.

使用方法:

git-show-save other-branch file1.c path/to/file2.cpp

结果:以下是文件的备选版本:
file1.old.c
path/to/file2.old.cpp

通过这种方式,您可以保留文件扩展名,以避免编辑器出现问题,并且可以轻松地找到旧文件和新文件并排存在。

@MickeyPerlstein 如果你能用更好的实现方式来实现相同的接口,我全听着呢。 - Ciro Santilli OurBigBook.com
也许我理解有误(如果是这样,我道歉),但难道不只是:“git show version:./path > new_path”? - Mickey Perlstein
@MickeyPerlstein 你好,是的,我的命令生成了那个CLI,但它会循环遍历多个文件并根据输入生成输出名称,这样你就不必输入太多内容了。当然,这并不是什么革命性的东西,但很方便。 - Ciro Santilli OurBigBook.com

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