从合并的主分支恢复 git 个文件
recover git files from merged master branches
我有一个场景,我认为我不小心从我的本地存储库中删除了所有历史记录和文件,我正在查看是否确实如此(以及是否可以恢复任何文件)我最初克隆了一个从远程回购回购,从未在本地创建新分支。我在其中一个本地目录中创建了几个文件。然后我不小心将远程仓库的 master 分支合并回本地,导致这些文件被删除。我没有办法恢复到另一个分支(就像我看到的其他 SO 问题一样)。没有办法恢复到 'pre-merge' 本地版本吗?
编辑:我还应该注意到,我本地存储库中的文件在任何时候都没有提交过。它们只是保存在 git init
运行 所在的文件夹中。
edit: I also should note that the files in my local repo were never committed at any point. They were just saved within the folder that git init
was run on.
这是关键信息,这意味着一旦文件丢失,Git 将无法帮助您找回文件。如果您有某种 OS-level 文件备份(例如 macOS Time Machine),这就是恢复它们的方法。
使用前须知 Git
使用 Git 时,了解 Git 工作的基础模型很重要。细节变得非常复杂,但总体描述非常简单:Git 存储 提交 ,基本上就是这样。如果已提交,则在 Git 中。如果未提交,则 不在 Git 中。1
适当的存储库主要由两个数据库组成。一个数据库保存 Git 的 对象 — 提交和其他支持对象。另一个保存 names,例如 b运行ch 和标签名称。两个数据库都很简单 key-value stores,名称数据库使用名称作为键存储哈希 ID 值,对象数据库使用哈希 ID 作为键存储对象。在 .git
目录中还有一堆辅助文件,但是 object 数据库被 git clone
复制了,或多或少是批发的。 names 数据库用于在新克隆中播种一个新的独立名称数据库,该克隆包含 不同的名称 但 相同的哈希 ID。散列 ID 是通用的——通过散列算法在 所有 Git 存储库之间共享——但每个 Git 存储库的名称是唯一的。 2
因此,存储库 由这两个数据库组成,存储在隐藏的.git
目录中。 Git 还在 .git
目录中存储了很多额外的数据,当您使用 Git 时,这些数据对 Git 本身的重要性不同,但对 Git 的重要性相对较低您作为 Git 的 用户。这意味着您可以说存储库“是”.git
目录及其内容,或者说存储库“是”两个数据库:任何一种说法都可以,特别是如果您根据需要对其进行限定。
但是你的工作树文件呢?好吧,在我们到达那里之前,让我们注意对象数据库的另一个特性。 Git 使用的哈希 ID 系统 要求 对象 永远不会改变 。某些对象的哈希 ID 只是对象内容的加密校验和:这就是 Git 在算法上管理到处具有相同 ID 的技巧的方式。但是就靠这个“永不改变”属性.
这意味着文件的提交副本字面上 不能 更改。因此,Git 在每次提交中存储 每个 文件的完整快照,压缩为 Git-ified、de-duplicated 和 read-only 时尚。 de-duplication 处理这样一个事实,即大多数提交大多与以前的一些提交具有相同的文件。因为它们 是 相同的,所以它们是 de-duplicated 并且根本不使用 space。对象的 read-only 性质使这成为可能,并且每次提交的 full-snapshot 性质使其成为必要,以一种 Ouroboros 的方式。
但是——这意味着您根本不能使用提交的文件根本。只有 Git 可以读取它们,实际上没有任何东西,甚至 Git 本身也不能写入它们。那他们有什么好处呢?好吧,就像任何存档一样,任何给定提交中的快照都可以提取。 这就是你的工作树的用武之地。 当你 select 一些特定的提交时——例如 git checkout
或 git switch
:你选择了一些 b 运行ch 名称,b运行ch 名称挑选出当前“在”的最新提交,b运行ch—Git 将 提取 提交的文件。文件从存档中出来,进入您的工作树。
标准 Git 存储库中的工作树是您 运行 git init
所在的目录,如果您以这种方式创建存储库,或者 git clone
如果您以这种方式创建存储库,请放置新的克隆。隐藏的 .git
文件夹存储在该工作树中的顶层。 存储库 位于 .git
目录中,但您使用的 文件 位于工作树中。 这意味着您使用的文件不在Git中!它们只在工作树中。直到您将它们保存在提交,这些文件不在 Git 中。其中一些 来自 Git,如果您有现有的提交并且正在使用其中之一;您可以取回它们,因为它们处于提交状态,并且来自 Git。但是您在工作树中修改的任何文件都只是您计算机上的一个文件。不是在Git。 Git如果你毁了它就无法为你取回。
底线是未提交的文件不在Git。这就是为什么您应该尽早并经常做出承诺。 Git 可以让你找回那些文件;它无法取回您从未提交的内容。
(请注意,无论是作为还是不作为,都不要破坏 .git
目录也很重要。不要将 .git
文件夹放在 cloud-shared / cloud-managed 位置,因为 cloud-sharing 软件往往会损坏 Git 的内部文件。Cloud-syncers 假设人类正在处理每个文件,并且人类知道如何处理名为 [=24] 的文件=] 等等。Git 不知道如果云软件重命名其宝贵的数据库文件该怎么办,并且会认为 - 正确地,在这一点上 - 存储库已损坏。)
1这里有一个技术问题。如果您在文件上使用了 git add
,这会导致文件的 content——而不是文件的 name——存储在Git 对象数据库。所以有时这种内容是可以恢复的。 name 存储在 Git 的 index 中,这在重要意义上不如 [=170] 可靠或更短暂=]条目。对象数据库中的实体默认至少保留 14 天,无论其他操作如何。同时,每次更新建议的下一次提交时,索引都会不断更新,或者 运行 git merge
,或者 运行 git checkout
或 git switch
等等。对象数据库中的实体是read-only;但是索引会定期被覆盖,这样丢失的索引条目将永远丢失。
在任何情况下,除了偶尔能够使用 git fsck --lost-found
来恢复 内容 的 git add
-ed 但从未提交的文件, 对于没有提交的文件,Git 无能为力。
2有一种标准映射,如果我克隆你的 Git 存储库,我克隆的名称数据库存储你的 b运行ch 名字作为我的 remote-tracking 名字。我的b运行ch名字,独立于你的b运行ch名字,当第三人克隆的时候,就变成了另一个第三人的remote-tracking名字我的 克隆你的 克隆。但是,标签 名称在默认情况下会被复制 as-is,因此标签名称在所有这些克隆中都是通用的。您作为 运行ning git clone
然后附加 Git 命令的人负责这种映射,所以这只是默认标准。哈希 ID 是通用的这一事实 不是 在您的控制之下,但是名称映射的方式 是 .
我有一个场景,我认为我不小心从我的本地存储库中删除了所有历史记录和文件,我正在查看是否确实如此(以及是否可以恢复任何文件)我最初克隆了一个从远程回购回购,从未在本地创建新分支。我在其中一个本地目录中创建了几个文件。然后我不小心将远程仓库的 master 分支合并回本地,导致这些文件被删除。我没有办法恢复到另一个分支(就像我看到的其他 SO 问题一样)。没有办法恢复到 'pre-merge' 本地版本吗?
编辑:我还应该注意到,我本地存储库中的文件在任何时候都没有提交过。它们只是保存在 git init
运行 所在的文件夹中。
edit: I also should note that the files in my local repo were never committed at any point. They were just saved within the folder that
git init
was run on.
这是关键信息,这意味着一旦文件丢失,Git 将无法帮助您找回文件。如果您有某种 OS-level 文件备份(例如 macOS Time Machine),这就是恢复它们的方法。
使用前须知 Git
使用 Git 时,了解 Git 工作的基础模型很重要。细节变得非常复杂,但总体描述非常简单:Git 存储 提交 ,基本上就是这样。如果已提交,则在 Git 中。如果未提交,则 不在 Git 中。1
适当的存储库主要由两个数据库组成。一个数据库保存 Git 的 对象 — 提交和其他支持对象。另一个保存 names,例如 b运行ch 和标签名称。两个数据库都很简单 key-value stores,名称数据库使用名称作为键存储哈希 ID 值,对象数据库使用哈希 ID 作为键存储对象。在 .git
目录中还有一堆辅助文件,但是 object 数据库被 git clone
复制了,或多或少是批发的。 names 数据库用于在新克隆中播种一个新的独立名称数据库,该克隆包含 不同的名称 但 相同的哈希 ID。散列 ID 是通用的——通过散列算法在 所有 Git 存储库之间共享——但每个 Git 存储库的名称是唯一的。 2
因此,存储库 由这两个数据库组成,存储在隐藏的.git
目录中。 Git 还在 .git
目录中存储了很多额外的数据,当您使用 Git 时,这些数据对 Git 本身的重要性不同,但对 Git 的重要性相对较低您作为 Git 的 用户。这意味着您可以说存储库“是”.git
目录及其内容,或者说存储库“是”两个数据库:任何一种说法都可以,特别是如果您根据需要对其进行限定。
但是你的工作树文件呢?好吧,在我们到达那里之前,让我们注意对象数据库的另一个特性。 Git 使用的哈希 ID 系统 要求 对象 永远不会改变 。某些对象的哈希 ID 只是对象内容的加密校验和:这就是 Git 在算法上管理到处具有相同 ID 的技巧的方式。但是就靠这个“永不改变”属性.
这意味着文件的提交副本字面上 不能 更改。因此,Git 在每次提交中存储 每个 文件的完整快照,压缩为 Git-ified、de-duplicated 和 read-only 时尚。 de-duplication 处理这样一个事实,即大多数提交大多与以前的一些提交具有相同的文件。因为它们 是 相同的,所以它们是 de-duplicated 并且根本不使用 space。对象的 read-only 性质使这成为可能,并且每次提交的 full-snapshot 性质使其成为必要,以一种 Ouroboros 的方式。
但是——这意味着您根本不能使用提交的文件根本。只有 Git 可以读取它们,实际上没有任何东西,甚至 Git 本身也不能写入它们。那他们有什么好处呢?好吧,就像任何存档一样,任何给定提交中的快照都可以提取。 这就是你的工作树的用武之地。 当你 select 一些特定的提交时——例如 git checkout
或 git switch
:你选择了一些 b 运行ch 名称,b运行ch 名称挑选出当前“在”的最新提交,b运行ch—Git 将 提取 提交的文件。文件从存档中出来,进入您的工作树。
标准 Git 存储库中的工作树是您 运行 git init
所在的目录,如果您以这种方式创建存储库,或者 git clone
如果您以这种方式创建存储库,请放置新的克隆。隐藏的 .git
文件夹存储在该工作树中的顶层。 存储库 位于 .git
目录中,但您使用的 文件 位于工作树中。 这意味着您使用的文件不在Git中!它们只在工作树中。直到您将它们保存在提交,这些文件不在 Git 中。其中一些 来自 Git,如果您有现有的提交并且正在使用其中之一;您可以取回它们,因为它们处于提交状态,并且来自 Git。但是您在工作树中修改的任何文件都只是您计算机上的一个文件。不是在Git。 Git如果你毁了它就无法为你取回。
底线是未提交的文件不在Git。这就是为什么您应该尽早并经常做出承诺。 Git 可以让你找回那些文件;它无法取回您从未提交的内容。
(请注意,无论是作为还是不作为,都不要破坏 .git
目录也很重要。不要将 .git
文件夹放在 cloud-shared / cloud-managed 位置,因为 cloud-sharing 软件往往会损坏 Git 的内部文件。Cloud-syncers 假设人类正在处理每个文件,并且人类知道如何处理名为 [=24] 的文件=] 等等。Git 不知道如果云软件重命名其宝贵的数据库文件该怎么办,并且会认为 - 正确地,在这一点上 - 存储库已损坏。)
1这里有一个技术问题。如果您在文件上使用了 git add
,这会导致文件的 content——而不是文件的 name——存储在Git 对象数据库。所以有时这种内容是可以恢复的。 name 存储在 Git 的 index 中,这在重要意义上不如 [=170] 可靠或更短暂=]条目。对象数据库中的实体默认至少保留 14 天,无论其他操作如何。同时,每次更新建议的下一次提交时,索引都会不断更新,或者 运行 git merge
,或者 运行 git checkout
或 git switch
等等。对象数据库中的实体是read-only;但是索引会定期被覆盖,这样丢失的索引条目将永远丢失。
在任何情况下,除了偶尔能够使用 git fsck --lost-found
来恢复 内容 的 git add
-ed 但从未提交的文件, 对于没有提交的文件,Git 无能为力。
2有一种标准映射,如果我克隆你的 Git 存储库,我克隆的名称数据库存储你的 b运行ch 名字作为我的 remote-tracking 名字。我的b运行ch名字,独立于你的b运行ch名字,当第三人克隆的时候,就变成了另一个第三人的remote-tracking名字我的 克隆你的 克隆。但是,标签 名称在默认情况下会被复制 as-is,因此标签名称在所有这些克隆中都是通用的。您作为 运行ning git clone
然后附加 Git 命令的人负责这种映射,所以这只是默认标准。哈希 ID 是通用的这一事实 不是 在您的控制之下,但是名称映射的方式 是 .