使用Git恢复一些旧文件的副本,同时保留其最新版本



我有几个文件(比如file1file2),我想从旧提交中恢复它们的副本。但我也想保留他们的最新版本,因为旧版本和新版本最终做了两件不同且有用的事情。更确切地说,我想摆脱以下情况:

project/
|- file1  (latest version)
|- file2  (latest version)

针对以下情况:

project/
|- new/
|- file1  (latest version)
|- file2  (latest version)
|- old/
|- file1  (old version)
|- file2  (old version)

如何使用Git实现这一点?

每个提交都会存储每个文件的完整快照,或者更确切地说,存储该特定提交中的每个文件。一旦做出承诺,就永远无法更改。因此,所有旧的、现有的提交都包含所有文件的所有版本,以及提交时文件中的内容。它们一直被冻结——为了在不占用太多磁盘空间的情况下保证它们的安全,它们采用了一种特殊的、压缩的、只读的、仅限Git的形式

每个提交都有一个"真名":原始哈希ID。当你运行git log时,你会看到这些大而丑陋的哈希ID,或者有时是它们的精简版本。该原始哈希ID将始终用于命名提交的。其他名称(如master或其他分支或标记名称)也用于命名一个特定的提交,但分支名称会随着时间的推移而变化:分支名称只是保存最后一个提交的哈希ID,该哈希ID应被视为该分支的一部分。

因为提交中的文件是冻结的,并且仅限于Git,所以您需要一种处理这些文件的未冻结和重构版本的方法。Git允许您使用自己的文件的方式是,它将冻结的、压缩的、仅限Git的文件(我称之为冻干)复制到一个工作区,在那里您的文件将恢复到正常格式。Git将此工作区域称为工作树,有时也称为workingtreeworkingdirectory或者这些名称的变体。("工作目录"意味着只有一个级别的文件夹,所以几年来,Git的人一直试图让它一直使用"工作树"这个短语。我有时喜欢用连字符。)

您可以使用git checkout任何特定提交中的所有文件获取到工作树中。为此,您可以为git checkout提供历史提交的原始哈希ID1当然,问题是这会检查整个提交,删除您正在处理的任何分支中上次提交的文件版本,并用旧提交的版本替换它们。

因此,正如knittl的回答一样,您可能只想从旧提交中提取一个(或多个)文件到您的工作树区域,这样您就可以看到它并使用它。git show命令可以使用git showhash:path显示任何提交中的一个文件。这会将文件的内容显示为git show的标准输出,因此您需要将输出重定向到计算机上的某个新文件(工作树内外的任何位置都可以)。

另一种方法是创建第二个工作树。自从Git 2.5(通过Git 2.15在几个版本中修复了一些重要的错误)以来,2Git已经有了git worktree命令。这个命令可以被告知在当前工作树之外的某个地方创建一个新的工作树。Git过去每个存储库只有一个工作树。既然Git有能力拥有多个,我们必须把原来的一个称为:我在这里使用"main"或"primary"这个词。

要使用git worktree add获得分离的HEAD提交(再次参见脚注1),请运行git worktree addpathcommit-hash。例如,如果希望使用的所有文件的旧版本都在提交28014c1084中,并且/tmp/foo是放置它们的好地方,则可以运行:

$ git worktree add /tmp/foo 28014c1084

它会打印这样的东西(取决于Git的年份):

Preparing worktree (detached HEAD 28014c1084)
HEAD is now at 28014c1084

此时,/tmp/foo中存在一个充满文件的新树,这些文件是所有从提交28014c1084中提取的文件。

当你完成了添加的工作树——已经复制了你关心的所有文件,只需删除它:

$ rm -r /tmp/foo

然后使用CCD_ 17将其从工作树列表中删除:

$ git worktree list
[path]    d9f6f3b619 [master]
/tmp/foo  28014c1084 (detached HEAD)
$ git worktree prune
$ git worktree list
[path]    d9f6f3b619 [master]

1这会产生Git所称的分离的HEAD。这有利于查看历史提交,但不利于进行新工作。要摆脱这种模式,只需git checkout任意分支名称。

2如果你的Git版本早于2.15,那么使用git worktree add是可以的,只要你不要让添加的工作树停留太久。2.15中修复的最糟糕的错误是,大约两周后,如果您在主工作树中工作两周或两周以上,同时留下一个添加的工作树,则在某些情况下,添加的工作树内的对象可能会意外损坏。因此,我建议任何使用Git 2.5到2.14的人的简单经验法则是:如果可能的话,升级;如果没有,最多只使用添加的工作树一周左右。

您可以使用git show在任何给定提交时显示文件的内容:

git show deadbeef:path/to/file1 > file1.old

相关内容

最新更新