除了现有的(正确的)答案之外,值得注意的是,在使用git commit [flags] file1 file2 ... fileN 时,您可以输入标志--only 或--include:
这很简单,但有点错误,因为--only 也必须采取提交后 操作。
正确理解需要知道 Git 的 index 是什么,以及 git commit 实际上如何提交 index 中的内容,而不是工作树中的内容。
Git 程序员设想您使用 Git 的方式
索引是一个相当复杂的东西,但大部分归结为:索引包含将进入您的下一个的文件集 也就是说,如果您现在运行git commit(不列出任何文件),new 提交将是索引右侧所有文件的快照现在,现在保存索引中的内容。
this 的意思是紧接着:
$ git clone <some-url>
$ cd <repository>
$ git checkout <branch>
在您的索引中,具有相同内容的所有相同文件,与您在工作树中看到的一样。
也就是说,每个提交都是该提交中所有文件的完整快照,以一种特殊的、压缩的、仅限 Git 的形式永久冻结。这意味着您始终可以通过让 Git 提取和解压缩它们来取回所有这些文件的原始形式,这就是 git checkout 所做的:它在分支上找到 latest 提交,并提取和解压缩文件。 (这太简单了:git checkout 真的很花哨。但这是它所做的最基本的事情。)
有用的格式文件位于您的工作树中,您可以在其中查看并处理它们。这很好,因为已提交的已冻结且仅限 Git,这显然是个问题。 :-)
但是,要进行 new 提交,而不是重新压缩所有工作树文件(在很多情况下这需要很长时间),Git 所做的是 save 这个东西中的(解冻但仍然压缩且仅 Git)文件,不同地称为 index、暂存区 或 缓存。因此,如果您的工作树中有 README.txt 和 main.py,那么您的当前提交(它们被冻结的地方)和中也有它们(仅 Git 形式) (解冻的地方,但仍然仅限 Git)。
运行 git add README.txt 告诉 Git 用工作树副本覆盖索引副本:获取普通格式文件并将其重新压缩为仅 Git 格式,替换 README.txt在工作树中的索引中。它还没有冻结——你可以在提交之前再次覆盖它——但它现在准备好了。
运行git commit,不指定任何文件,告诉Git:立即打包索引中的任何内容,并从中进行新的提交。很快,因为文件已经是正确的形式:Git 只需要将它们冻结到新的提交中。 (当然,除非您将索引中的文件 不同于 中的文件与 current 提交中的文件,否则没有意义。)
请注意,在git commit 从索引进行new 提交后,您通常会回到索引和当前提交匹配的正常情况。如果您 git add-ed 更改了所有文件,则每个文件的所有 三个 副本(HEAD、索引和工作树)都匹配。
介绍--only 和--include
运行git commit 列出的一些文件有点不同,这就是--only 与--include 的用武之地。如果你使用--include,Git 基本上是@987654346 @ 在列出的文件上。它只是git add <those files> && git commit 的简写,或多或少。
但是,如果你使用--only——或者不指定,这意味着--only——Git 所做的就是将常规索引排除在外,而是创建一个新的临时索引来自冻结提交中的任何内容。对于这个新的临时索引,Git 将 git add 您列出的每个文件。然后 Git 将从这个 other 索引进行新的提交。但是现在出现了一个问题,因为 Git 现在需要回到正常的索引,这就是它变得有点棘手的地方。
从临时索引提交 new 后,Git 现在需要以同样的方式更新 real 索引。本质上,在从临时索引提交后,Git 会将您列出的 same 文件集重新添加到 real 索引中,以便它们再次匹配。
让我们再次使用README.txt 和main.py 的两个文件示例。这一次,让我们在每个文件后添加一个版本号。它不是文件名称的一部分,只是为了帮助我们记住:
HEAD index work-tree
------------- ------------- -------------
README.txt(1) README.txt(1) README.txt(1)
main.py(1) main.py(1) main.py(1)
它们开始时每个文件的所有三个版本都相同。 (请注意,您不能更改HEAD 副本。您只能进行新 提交,然后变成 HEAD复制,因为 HEAD 命名了新的提交。)
现在您在工作树中编辑两个文件:
HEAD index work-tree
------------- ------------- -------------
README.txt(1) README.txt(1) README.txt(2)
main.py(1) main.py(1) main.py(2)
假设您现在使用git add main.py 将工作树版本复制到索引中:
HEAD index work-tree
------------- ------------- -------------
README.txt(1) README.txt(1) README.txt(2)
main.py(1) main.py(2) main.py(2)
如果您现在运行一个普通的git commit,新的HEAD 将有旧的README.txt,因为索引 有旧的README.txt。但是,让我们运行git commit --only README.txt。这会创建一个 临时 索引,因此我们有:
HEAD temp-index work-tree
------------- ------------- -------------
README.txt(1) README.txt(2) README.txt(2)
main.py(1) main.py(1) main.py(2)
接下来,这会从临时索引中创建一个新的提交:
HEAD temp-index work-tree
------------- ------------- -------------
README.txt(2) README.txt(2) README.txt(2)
main.py(1) main.py(1) main.py(2)
同时,real 索引还没有改变。向上滚动一下看看:main.py 是哪个版本的?其中README.txt是哪个版本的?
如果 Git 现在只是切换回真正的索引,同时保留你刚刚所做的提交,这就是你所拥有的:
HEAD ugly-index work-tree
------------- ------------- -------------
README.txt(2) README.txt(1) README.txt(2)
main.py(1) main.py(2) main.py(2)
也就是说,您的工作树是所有最新文件。您的提交有更新的README.txt。但是这种丑陋的状态意味着下一个提交将使用README.txt的旧/错误版本!所以这就是为什么 Git 现在将 README.txt 重新添加到真正的索引中,这样你就可以得到:
HEAD index work-tree
------------- ------------- -------------
README.txt(2) README.txt(2) README.txt(2)
main.py(1) main.py(2) main.py(2)
现在您可以根据需要使用更新后的main.py 进行第二次提交。