还原以前进行的更改(或:撤消对.git/index的更改)

还原以前进行的更改(或:撤消对.git/index的更改),git,git-stage,git-plumbing,Git,Git Stage,Git Plumbing,当我试图理解撤销各种git操作的方法时,我想到了一个场景,我不知道如何处理它。免责声明:我在“生产”中实际使用git时没有这种情况,但我仍然认为这不仅仅是一个学术问题 让我们看看下面的场景 操作先前提交的文件:echo“some content”>>example.txt 阶段更改:git add example.txt 上次提交的签出更改:git checkout@--example.txt 意识到您选择了错误的文件,并且希望撤消最后一个命令以恢复更改(“某些内容”) 我认为发生在引擎盖下

当我试图理解撤销各种git操作的方法时,我想到了一个场景,我不知道如何处理它。免责声明:我在“生产”中实际使用git时没有这种情况,但我仍然认为这不仅仅是一个学术问题

让我们看看下面的场景
  • 操作先前提交的文件:
    echo“some content”>>example.txt
  • 阶段更改:
    git add example.txt
  • 上次提交的签出更改:
    git checkout@--example.txt
  • 意识到您选择了错误的文件,并且希望撤消最后一个命令以恢复更改(
    “某些内容”
我认为发生在引擎盖下的事情 每次使用git add进行暂存更改时,都会在.git/objects/下创建一个blob对象,并更新索引文件(.git/index)。如果我多次更改和添加内容,将出现多个blob。旧的垃圾不会立即被回收

当从上面运行checkout命令时,索引立即得到更新(我也会假设内容只在我的工作目录中,但未被保存)。这样,引用就消失了,我不能使用像
git checkout index
这样的东西来还原它们

除非垃圾收集开始,否则从技术上讲,内容仍然存在。但我不知道如何将其取回,然后手动尝试以某种方式查找散列并使用
git cat file
读取内容。例如,多次运行
git add
也是如此,尽管在这里想要恢复之前进行的更改可能不是一个真正的用例。(或者,当从隐藏处弹出更改时?…)


所有这些问题归结为以下几个问题:

  • 索引是否有类似于
    git reflog
    的内容
  • git checkout@--file
    是否被认为是像git
    reset--hard
    这样的危险命令,在这里您可能会丢失您的工作
如果答案是“否”/“是”(我目前的假设):

  • 是否有手动更改/重写索引的管道命令?(请参见上面的情况,其中对象仍然存在)

奖励:有没有其他方法可以签出单个文件而不立即将其暂存?

您的幕后描述基本正确。唯一与此部件无关的是:

每次使用
git add进行暂存更改时,都会在.git/objects下创建一个blob对象/

在内部,
git add
散列工作树文件中的数据内容,即la
git散列对象-w-t blob
。这并不一定会创建一个新对象:如果哈希内容已经在存储库中,它只会重新使用现有对象。现有对象可能已打包,即在
.git/objects/pack
中,而不是作为单独的blob松散

此外,由于干净的过滤器,写入blob对象的内容可能与工作树中的内容任意不同。更常见的情况是,由于行结束设置,CR LF行结束与工作树中的内容不同。清洁过滤器和行尾设置部分(或大部分,取决于Git的使用情况)通过
.gittributes
文件控制,部分(或大部分)通过配置中的设置控制

在任何情况下,重要的是获得blob对象的散列ID。blob对象肯定以松散对象或包文件的形式存在于
.git/objects
目录中的某个位置。现在,
git add
可以写入
.git/index
(或者
git\u index\u file
指示的任何其他文件):它将在暂存槽0处的索引中存储给定
路径的条目,使用计算出的blob哈希和模式
100644
100755
,具体取决于工作树文件是否应在以后标记为可执行

如果你失去了它,你大部分都是运气不佳 [场景被截断,但它以
git checkout HEAD--path
关闭索引项结束,其
$path
表示
$blobhash
和mode
$mode
信息,关闭
路径中文件的工作树副本)

除非垃圾收集开始,否则从技术上讲,内容仍然存在。但我不知道如何将其取回,然后手动尝试以某种方式查找哈希并使用
git cat file
读取内容

事实上,你不能:散列ID计算是一个复杂的过程,只有你有散列,你才能让Git溢出内容,但是如果你没有散列,你需要有内容。这是你的问题

如果这是一个非常重要的“如果”-内容是唯一的,因此,
git add
确实创建了一个新的blob对象,并且您刚刚覆盖了索引中的blob引用,该blob对象确实不再在任何地方被引用。另一方面,如果
git hash object-w
最终重用了一些现有的blob,则blob对象仍然被引用所以现在有两个有趣的例子:blob是唯一的,现在可以进行垃圾收集,或者blob不是唯一的,也不是唯一的

使用
git-fsck--lost-found
git-fsck--unreable
git-fsck--hanging
(默认),您可以让Git遍历整个对象数据库,确定哪些对象是可访问的,哪些是不可访问的,并告诉您一些或所有无法访问的对象,和/或将这些对象的信息复制到
.Git/lost-find
。如果无法访问blob对象,它将被列为这些无法访问或悬空的blob之一,或ha把它的内容写下来
git show :file          # file in index at stage zero
git show :3:file        # file in index at stage three, during merge conflict
git show HEAD:file      # file in current commit
git show master~7:file  # file in commit 7 first-parent hops back from master
git reset HEAD -- file  # copy HEAD:file to :file leaving work-tree file undisturbed