TL;DR:您必须先git add 文件,然后再git commit 更新的索引。
(这是基于上面的cmets。)
如果您在工作树中创建了一个文件,但没有git add-ed 文件,那是一个未跟踪文件。 未跟踪文件的准确定义是不在索引中的文件。该索引也称为 暂存区,因为它是您更新(即暂存)您将进行的 下一个 提交的文件的地方。 git add 步骤将文件复制到索引中,为下一个 git commit 提交它做好准备。您必须使用git commit 完成此过程(好吧,您最终必须完成它 - 如果您愿意,可以等待,然后将更多文件复制到索引中,甚至覆盖您刚刚复制的文件)。
Git 至少尽可能多地保留未跟踪的文件。只要文件未被跟踪(不在索引中),您就可以随意切换分支,文件就在那里。
一旦您添加并提交文件,它就会成为该提交中的普通文件,就像该提交中的所有其他文件一样。 git commit 步骤只是将索引中的每个文件打包成当您运行git commit 时它在索引中的形式,并将其变为一个新的只读(完全),1 永久(大部分),2 提交。
请注意,当您更改现有的工作树文件时,较旧的 版本仍在索引中(如果它完全在其中,即,如果文件被跟踪)。您仍然需要 git add modified-file 将更新的版本复制到索引中。这就是为什么 Git 不断地强迫你 git add 一切:你必须首先将它复制到索引中,即使索引中已经有一个旧版本。
检查任何现有的提交会使用该提交中的文件填充索引和工作树。签出一些 other 提交将从索引和工作树中删除之前签出提交中但不在新签出提交中的所有文件。 (注意in some cases, you can carry un-committed changes around in your index and work-tree while switching branches, but sometimes you can't do this.细节有点乱。)
因此,在分支feature-A 上运行git add new-file 和git commit 之后,执行git checkout feature-B 将使您从具有文件的新提交中切换(它在索引中→跟踪,并且在工作中-树 → 可见)到您在 feature-B 上的现有旧提交。较旧的提交没有有新文件,因此它从索引中出来,Git 将它从你的工作树中删除。
请注意,现在feature-A 的提示提交有文件。如果您仍在feature-B 上并且您创建 文件并使其不被跟踪,那么它只是一个未跟踪的文件。它不在索引中。你现在不能git checkout feature-A,因为Git 将不得不覆盖你未跟踪的文件。您必须删除它(这样它就不会妨碍)或添加并提交它(以便跟踪和清理它),以便 Git 可以吹走 那个 副本并将其替换为来自feature-A.
(练习:当您从feature-A 签出提交时,当时的新文件会在索引中吗?)
1存储在 Git 存储库中的每个对象始终是完全只读的。有四种对象类型:commit、tree、blob 和annotated tag。您将最直接看到的两个是 commit 和 blob:commit 对象保存您的提交,而 blob 对象保存您的文件数据。
2只要您能找到提交,它们就会一直存在。像master 这样的分支名称标识了一个特定的提交,并且该提交找到了它的父级。父提交找到它自己的父提交,它找到另一个父提交,依此类推。一般来说,在 Git 中,您将添加新的提交,而不会忘记/放弃旧的提交,方法是让 new 提交记住,作为其父提交,无论哪个提交是某个分支上的最新提交在那之前。然后分支名称将仅标识最新的提交。
偶尔你会发现一些提交很糟糕,应该被遗忘。只要您没有将该提交提交给其他人,您就可以简单地将您的分支名称和其他现有提交调整为 forget 或 abandon 您不喜欢的提交.被遗忘/放弃的提交 ID 会保存在名为 reflog 的辅助日志中一段时间。最终,reflog 条目过期,只有到那时 Git 才会真正收回提交。默认情况下,reflog 条目至少存在 30 天,因此您有长达一个月的时间来改变主意并在放弃后重新提交。
这一切都意味着提交是大部分永久的。它们不是 100% 保证永久的,但不会意外丢失。由于它们也是只读的,这意味着保存在这些提交中的历史文件将永远可供您使用。