首页 > 解决方案 > git add 之后的 git checkout?

问题描述

我想知道是否有办法回到 git 上文件的先前更改。如果我创建一个 .txt 文件,我编辑它但我没有“git add”我可以运行“git checkout - file.txt”并返回,但是在执行“git add”之后有没有办法做到这一点?

标签: gitgit-checkoutgit-add

解决方案


我想知道是否有办法回到 git 上文件的先前更改。如果我创建一个 .txt 文件,我编辑它但我没有“git add”我可以运行“git checkout - file.txt”并返回,但是在执行“git add”之后有没有办法做到这一点?

如果文件Git 中,答案是肯定的。

重要的是要意识到一些已经提交的文件不是一个而是两个可修改的副本,以及许多无法更改的副本。只读副本位于每个提交中,因为您所做的每个提交都会保存每个文件的完整快照。1 但它使此快照不是来自看到和使用的副本。它从第二个可修改副本创建快照,Git 将其保存在 Git 有时称为index有时称为staging area的地方。

名称索引暂存区指的是同一件事。它有时也称为缓存gitglossary缓存定义为“索引过时”。考虑索引的一种好方法是它是建议的 next commit。当您签出一些现有提交时,Git 会从该现有提交中填充索引工作树。当您运行 时,Git 将 的当前版本复制到索引中,替换索引中的副本。也就是说,只需更新提议的新提交。git add filefilegit add

(如果 Git 直接从工作树提交,你根本不需要索引。但是 Git 不会从工作树提交,并且索引在冲突合并期间扮演扩展角色,所以你是有点坚持学习索引。)

通常,您使用切换到一个分支,但您也可以编写或。2 这些都不同于:git checkout branchnamegit checkout [--] filenamegit checkout branchname [--] filenamegit checkout branchname

  • git checkout branchname表示切换分支
  • git checkout branchname [--] filename表示从命名分支尖端的提交中获取给定文件3
  • git checkout [--] filename表示从索引/暂存区获取给定文件

我喜欢考虑这个问题的方式是,当您进行新提交时,该文件有三个活动副本。一个是您当前(HEAD@)提交中的冻结文件,一个是您在索引中提议的下一个提交中的可修改副本,第三个是您可以查看和使用的普通文件。使用git checkout -- file.txtgets,进入你可以使用它的工作树,中间的副本——索引副本——你已经用你之前的git add. 因此,您想要git checkout HEAD -- file.txt:这将获得只读的、已提交的副本。此时,它会在索引您的工作树中结束,因此两个可修改的副本都已被此命令覆盖。4 您提议的新提交具有file.txt当前提交之外的旧版本,并且您的工作树具有file.txt当前提交之外的旧版本。所有三个副本——<code>HEAD、索引和工作树——再次匹配。


1即使git log -pgit show向您展示了提交的父级和提交之间的差异,这也是正确的。那是因为git log -porgit show发现差异的方式是它提取文件的父提交的副本和提交的副本,然后比较它们以查看有什么不同。

Because the committed copies are read-only, every commit that re-uses an old version of the file, doesn't make a new copy, it just refers back to the existing, already-frozen copy. So the fact that, say, README.md is in a thousand commits, with all the README.md copies exactly the same, really means that there's one copy, shared across the thousand commits.

2The square brackets in [--] indicate that the -- is optional. It's a good habit to get into using it when you mean the next part is a file name. Suppose you create a file named master. Later, you run:

git checkout master

Did you mean: Get me the file named master, or did you mean: *Switch to branch master`? If you type in:

git checkout -- master

Git knows you meant Get me the file named master. Whatever comes after -- is assumed to be a file name. If you type this in without the --, Git thinks you mean switch to branch master.

3You can put in a commit hash ID, or any other name or string that resolves to a commit, here.

4Git being what it is, there's another way to do all of this. Actually there are many ways, but there is one other main way: you can use git reset [--] filename to copy from HEAD to the index, then git checkout [--] filename to copy from index to work-tree. But git checkout commit-ish -- filename is shorter and faster.


推荐阅读