在暂存文件(跟踪文件)后,我意识到它需要进行一些更改,因此为了取消暂存,我使用了
git rm --cached <filename>
。因此,我丢失了所有更改。有办法撤消吗?
答案 0 :(得分:2)
git rm --cached
仅从索引中删除新文件,而不从工作树中删除。这样做要小心。如果这是现有文件,则只需暂存该文件。
您可以使用git add <filename>
重新添加。
更常见的取消变更的方法是使用git reset HEAD <filename>
。
但是...不必取消暂存文件即可添加更多更改。您可以进行进一步的更改,然后使用git add <filename>
重新进行更改。
答案 1 :(得分:1)
您需要再次添加。这是命令示例集。
echo testmodify>> FOO //Appends "testmodify" to FOO
git add FOO // Stage FOO to commit
git rm --cached FOO // Unstage FOO
git add FOO // Stage FOO
FOO仍包含“ testmodify”
答案 2 :(得分:0)
Git使用短语阶段性更改或阶段性更改可能会引起很大的困惑。
为避免混淆,这是您需要了解的内容:
Git有一个被Git调用的东西,称为 index ,临时区域,有时甚至是现在很少使用的 cache 。这三个名称都只涉及一件事情。在这里,我将其称为索引。
索引最初包含每个文件的副本 1 ,位于您检出的提交中。 (此当前提交也称为HEAD
。)这些文件为仅Git格式。 您看不到这些文件。(这是一个夸大的说法-有一些特殊的Git技巧可以查看它们,但通常它们是不可见的。)您可以的文件见在您的工作树中,该树包含普通的日常文件。
当您提交 next 提交时,Git将使用当时索引中的文件。也就是说,当您运行git commit -m "some message"
(或在git commit
且没有-m
收集到您的消息之后)时,Git将在那时打包索引中的所有文件。当时的 ,并使用它们进行新的提交。
因此,如果您已经更改或替换了工作树中的文件,则必须首先将其复制回索引。否则,Git只会重新使用原始文件。
运行git add file
时,Git会获取工作树副本,将其压缩为仅Git的特殊格式,然后将压缩后的副本填充到索引中。现在,索引副本不再与HEAD
副本匹配,但与工作树副本匹配。
如果再次更改工作树副本 ,那么现在这三个副本都是不同的!此时,git status
会告诉您,您已经“已将变更暂存为提交”,并且也已“已将变更 not 已暂存为提交”。
您可以随时将工作树副本更改为任何内容。这对索引副本没有影响。
使用计算机上任何可删除文件的工具,您可以删除工作树副本而无需删除索引副本。您也可以使用git rm --cached
删除 index 副本,而无需删除工作树副本。而且,您可以使用git rm
删除两个副本。这些都不会影响任何现有的提交-无法更改永远的任何现有提交!但是删除索引副本确实会影响 next 提交,因为运行git commit
时,Git会打包当时索引中的所有文件,因此如果文件是< 从索引中消失了,它将不在 next 提交中。
由于索引中的内容是下一次提交中的内容,因此可以很好地描述索引:无论如何,索引还是下一次提交中的内容。确实还有一些其他的角色,尤其是在合并过程中,但是我们将不在这里讨论。
1 从技术上讲,索引实际上包含对副本的引用。但是效果至少与索引拥有实际副本一样,至少直到您开始研究如何直接使用git update-index
来操纵索引为止。
要将当前(HEAD
)提交中的文件以当前提交中的格式返回索引 ,可以使用git reset -- file
。仅当文件名类似于--
选项或分支名称时,才需要使用git reset
。例如,如果您有一个名为master
的文件和一个分支名称为master
的,则git reset master
似乎要使用分支名称,因此您必须写git reset -- master
来告诉git您的意思是文件 master
。
因此: git reset -- file
将文件从HEAD
提交复制到索引。即使您删除了索引副本,这也是正确的:reset只会将其放回原处。如果HEAD
提交中的文件不是,也是如此。如果您已将文件F
添加到索引中,然后决定它根本不应该包含在索引中,则可以git reset -- F
并将其从索引中删除。
(如果愿意,您也可以git rm --cached F
:在这一点上具有相同的效果。但是,如果您只想使索引副本与HEAD
副本匹配,请使用git reset
因为这对两种情况都有效:存在 个HEAD
副本,或者没有。)
同样,您实际上不能看到索引中文件的副本。那么您如何知道它是否与其他副本匹配?答案是:git status
以简短有用的方式告诉您。
假设您的工作树中有三个文件,分别为README.md
,main.py
和util.py
。这些文件中的前两个来自HEAD
提交,您现在已经自己创建了util.py
,因此HEAD
提交中的 not 索引中的不是。
git status
命令运行两个比较:
首先,它将HEAD
中的每个文件与索引中的每个文件进行比较。因此,这将HEAD:README.md
(HEAD副本)与:README.md
(索引副本)进行比较。 2 然后将HEAD:main.py
与:main.py
比较。>
对于每个相同的文件,git status
表示没有。
对于每个不同的文件,git status
表示存在为提交而进行的更改。如果文件已完全从索引中删除,则您已进行了删除。如果索引中的文件是全新文件,则说明您已暂存了一个新添加的文件。
因此,如果您知道HEAD
提交中的内容,则现在知道索引中的哪些文件相同:任何git status
都没有提及的。
接下来,HEAD
告诉了您git status
与索引之间的区别之后,继续将索引中的每个文件与工作树中的每个文件进行比较。因此,在这里,它将:README.md
与README.md
进行比较,将:main.py
与main.py
进行比较,并发现索引中没有util.py
。
对于每个相同的文件,git status
表示没有。
对于每个不同的文件,git status
报告不是准备提交的更改。没错,因为git commit
不会使用工作树,而只会使用索引。
对于类似util.py
的文件,该文件位于工作树中,但不包含在索引中的 中,git status
将其报告为未跟踪的文件 。这就是未跟踪的文件:在工作树中但不在索引中的文件。
请注意,如果您从索引中删除文件,该文件将立即被取消跟踪!如果您git add
将文件放在索引中,那么现在就可以对其进行跟踪了。
2 这种有趣的HEAD:file
和:file
语法特定于Git本身,并且仅适用于 some Git命令。其中之一是git show
:例如,实际上您可以使用README.md
来查看git show :README.md
的索引副本。由于git show
是面向用户的命令,因此可以非常安全地执行此操作:git show HEAD:file
,git show :file
和git show <commit:>file
都是查看特定副本的非常好的方法已转换为内部Git形式的特定文件,可以保存在提交中,也可以准备提交。
您还可以使用git ls-files
查看文件的所有索引副本的名称。在一个大的存储库中,这会打印出 lot 个名称!但是,它并不适合日常使用,也不是非常用户友好的命令。
git checkout
向其写入 要进行新的提交,只需将正确的文件复制到索引中并运行git commit
。索引已经具有 current 提交中的所有文件,因此,您只需要更新要更改的任何文件,或添加所需的任何新文件,或者删除所有要删除的文件。然后您git commit
进行一次 new 提交。现在,此新提交是HEAD
提交,现在是HEAD
提交和索引匹配。
如果HEAD
提交和索引匹配,而这两个匹配工作树,则一切都是“干净的”,您可以使用以下命令轻松切换到另一个提交:
git checkout otherbranch
(或新的Git 2.23 git switch
命令,它像git checkout branch
的友好变体,没有将所有其他Git工具推入一个命令中,git checkout
可以(取决于您的计算方式)在三到七个不同的工作之间。
假设此检查成功, 3 必须:
otherbranch
开头的所有文件填充索引(并删除所有不相关的文件); otherbranch
开头的所有文件填充您的工作树(并删除所有不相关的文件);和HEAD
指的是otherbranch
的尖端提交。完成所有操作后,您的HEAD
提交,索引和工作树将再次匹配。
3 即使索引和工作树不是“干净的”,git checkout
命令有时也会成功 *。 “干净”在这里定义不明确,但是要详细了解git checkout
何时允许您在进行修改时切换分支,请参见Checkout another branch when there are uncommitted changes on the current branch。
您不能看到文件的索引副本!您可以并且应该做的是使用git status
,该文件将HEAD
文件比较到索引副本。在一个拥有成百上千个甚至数百万个文件的大型项目中,Git几乎对所有文件都什么都不说。它只会提及不同的那些。那更有用。
只要您的HEAD
,索引和工作树都匹配,git status
就说没什么。当git status
看到某些不匹配的内容时,它会根据是否在为提交而进行的更改和/或在没有为提交而进行的更改下打印文件名,具体取决于是否是HEAD
和索引副本不同意,或者是索引和工作树副本不同意,或者两者都有。
git add
将文件复制到索引中。如果他们以前已经在那儿了,那么现在它们被工作树中的副本所覆盖。如果他们以前不在那里,那么现在就可以了。
git rm
从索引中删除文件。如果没有--cached
,它会也从工作树中删除相同的文件。使用--cached
,它可以单独保留工作树副本,这对 now 来说很好,但是以后的git checkout
可能需要删除工作树副本!
通常,Git将尽力不破坏具有宝贵数据的任何工作树文件。 What's "precious", though?好吧,如果已经添加并提交了工作树文件util.py
并与HEAD:util.py
和:util.py
匹配,那么此时util.py
不是 不再珍贵,因为如果您愿意,它就在提交中。因此,您可以git checkout
进行 没有util.py
的旧提交,而Git从您的工作树中删除util.py
将会非常安全。只需git checkout
它返回的最新命令即可。
一些Git命令,包括git reset --hard
,将销毁工作树文件。 git reset --hard
背后的理论是您想要重置索引和您的工作树。默认模式为git reset --mixed
,仅重置索引副本。 4 这就是git reset -- file
“取消登台”文件的原因-将HEAD:file
复制到{{ 1}} –但不会碰到:file
的工作树副本。
4 特别是file
,git reset --soft
和git reset --mixed
仅允许您执行每个文件。当您只想使用git reset --hard
来制作一个文件时,它总是使用git reset -- file
。对于其他情况,您必须使用--mixed
的许多备用模式之一。 Git 2.23引入了一个新命令git checkout
,目的是减少混乱。时间会证明它是否这样做:git restore
在技术上仍处于试验阶段。