为什么有时需要“git commit -a”而不是“git commit”?

时间:2011-03-02 10:39:45

标签: git mercurial

玩Git和GitHub,我发现有时候是

git commit -a
提交已修改的文件需要

。 (此文件已添加到项目中)。

但有时候,只是一个

git commit

会奏效。如果使用Mercurial,则命令hg com始终有效,如果它是先前已添加到repo的文件。所以我想知道为什么git有时需要-a? “升级”这个词出现在一些解释中,但我不完全理解升级的概念以及它如何与文件提交一些修改?

5 个答案:

答案 0 :(得分:2)

假设您对文件进行了两次不同的逻辑更改,但只想提交其中一种。如果“git commit”总是提交它知道的所有文件,那么该行为将是不可能的。因此,您需要在执行提交之前暂存每个更改。如果您“git add filename”,则表示您正在暂存该文件中的所有更改。顺便说一句,“git stage”是“git add”的同义词,如果你使用“git stage”,它可能会让行动更清晰。

将暂存区域(索引)视为工作目录和存储库之间的中间区域。命令“git add”和“git stage”将事物移动到索引中,“git commit”将它们从索引移动到存储库。 “git commit -a”同时执行这两个步骤。能够使用登台通常非常有用,可以帮助优化您的提交,以便您提交您想要的内容。

答案 1 :(得分:1)

仔细查看man page of git commit描述了它:

  • 当您向git添加新文件时,可以使用git add执行此操作。这标记了要在下一个commit添加的文件(以及git rm用于删除文件的文件)。
  • 当您更改文件时,您也可以git add将其标记为下次提交,但通常不会。在这种情况下,git commit -a为您完成工作:
      

    告诉命令自动暂存已修改和删除的文件,但未告知git的新文件不受影响

  •   

示例:如果您只想提交一些修改过的文件(例如,您修复了影响两个文件的错误(one.ctwo.c)并删除了其他文件中的一些拼写错误,并希望将错误修正签入与拼写检查分开),您将为每个错误修正文件执行git add,然后提交:

git add one.c
git add two.c
git commit -m "bugfix checkin" 

完成此操作后,您将使用

提交拼写错误
git commit -a -m "fixed typos"

关于分期:
git commit仅提交以某种方式标记的文件以进行提交。例如,可以通过git addgit rm进行此操作。这个标记为提交称为 staging

答案 2 :(得分:1)

另请参阅文章“You could have invented git (and maybe you already have!)”:当您将索引视为“补丁数据库”时,它会有所帮助。

如果您“添加”文件(到“索引”也称为“临时区域”),您实际上会添加由该文件中的演变所代表的补丁。
如果您在将添加到索引之后在同一文件中进行了新的演变,那么您实际上是在做一个新的补丁(包括自上次“{{1以来的所有新演变)在你能够提交之前,需要添加那些新的演变(到索引,“补丁数据库”)。
或者你可以在这种情况下git add

答案 3 :(得分:1)

要了解git commitgit commit -a之间的区别,您需要了解git中的索引,也称为暂存区

索引实质上存储了将进入下一次提交的每个文件的状态。 (这里的“状态”,我的意思是文件的确切内容,git通过其哈希标识。)当你输入git commit而没有任何其他参数时,git将进行一个新的提交,其中所有的状态文件与索引中的文件完全相同。这可能与您的工作树非常不同,这是git的一个有用功能,我将在下面解释。

git add真正做的是“暂存”文件,或将其当前状态添加到索引中。它是否最初被跟踪并不重要,你说“在下一次提交中,我希望这个文件与这个内容完全一致”。重要的是要意识到这会记录您要添加的内容,而不是文件名 - 这意味着如果您在使用git add上传文件后继续对文件进行更改,您将看到来自git status有时会混淆来自其他版本控制系统的人:

$ git status
[...]
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
#   modified:   foo.txt
#
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   foo.txt

...但如果您了解索引,这绝对有意义。您可以看到已经上传的更改(即索引和HEAD中文件状态之间的差异,这通常是您正在处理的分支上的最后一次提交):

$ git diff --cached

...您可以看到尚未上演的所有更改(即工作副本与索引之间的差异):

$ git diff

那为什么这么有用呢?本质上,我们的想法是,当每个提交只包含一组逻辑分组的更改时,项目的历史记录最有用,这些更改可以对项目进行明确的改进。您可以越小越好,因为稍后好的工具git bisect可以快速帮助您跟踪哪个更改引入了错误。除非你非常自律,否则在修复错误的过程中,你最终会编辑其他你不需要改变的文件以解决问题,或者最终可能会修复两个逻辑上不同的问题。决定提交您的更改。在这些情况下,索引可以帮助您分离出这些更改 - 只需git add每个文件包含您在第一次提交中所需的更改,运行git commit,然后执行相同操作以创建第二次提交。 [1]

如果您习惯这样做并且喜欢工作流程,那么有时您最终会想要在文件中而不是其他文件中进行某些更改,在这种情况下您需要了解git add -p(以及其互动se选项!)

然而,回到最初的问题 - git commit -a做什么与众不同?基本上它说,“在创建此提交之前,还要将当前状态下已修改(或删除)的每个文件暂存。”因此,如果您认为在提交之前在索引中小心地暂存文件,您可以一直使用“git commit -a”。但是,我认为使用git的好处之一是它鼓励你创建漂亮的提交,并且积极使用索引对此有很大的帮助。 :)


注意:

为了保持上面的解释简单,一些语句有点近似(例如我没有提到索引还存储文件的(非)可执行状态,它在合并期间可以有多个版本,等等。)

[1]如果你想确保历史记录中的每个提交都经过适当的测试,你应该小心这样做 - 如果这在你的项目中很重要,你应该在推送之前在每次新提交时测试树...

答案 4 :(得分:0)

检查faq。简而言之,它使git更加灵活。