【问题标题】:Why "git commit -a" is sometimes necessary instead of "git commit"?为什么有时需要“git commit -a”而不是“git commit”?
【发布时间】:2011-07-07 04:19:24
【问题描述】:

玩 Git 和 GitHub,我发现有时候一个

git commit -a

需要提交已修改的文件。 (此文件已添加到项目中)。

但有时,只是一个

git commit

会起作用。如果使用 Mercurial,如果命令 hg com 是之前已添加到存储库的文件,则该命令始终有效。所以我想知道为什么git有时需要-a? “暂存”一词在一些解释中出现,但我不完全理解暂存的概念以及它与向文件提交一些修改有何关系?

【问题讨论】:

    标签: git mercurial


    【解决方案1】:

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

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

    【讨论】:

    • 所以听起来 Mercurial 只有一个 repo 和一个工作目录(2 个不同的地方),但 Git 有 repo、暂存区和一个工作目录(3 个地方)?
    • 在 Mercurial 中,如果您觉得需要一个暂存区,请启用标准的 mq 扩展。
    • 而 mercurial 允许在没有阶段(或使用 mq)的情况下使用记录扩展提交单独的逻辑更改,这类似于 git 的rebase -i
    【解决方案2】:

    仔细看看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

    【讨论】:

      【解决方案3】:

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

      如果您“添加”一个文件(到“索引”也称为“暂存区”),您实际上添加了由该文件中所做的演变所代表的补丁。
      如果您将它添加到索引后在同一个文件中进行了新的演变,实际上您正在做一个新的补丁(自上次“git add "),并且在您能够提交之前,需要添加这些新的演变(到索引中,即“补丁数据库”)。
      或者,在这种情况下,您可以直接发送git commit -a

      【讨论】:

      • 我总是对建议在 git 中存储补丁的任何东西有点谨慎,因为即使它实际上对人们有所帮助,我认为它会在以后引起混乱。
      • @Mark: 但这不是更接近 Git 背后的初衷吗? b/ Git 实际管理的是什么? (即 stackoverflow.com/questions/995636/…stackoverflow.com/questions/612580/… 中提到的“内容”,而不是“文件”)
      • 也许这是最初的意图,但 git 正在跟踪的“内容”不是补丁。我认为将 git 跟踪的内容描述为文件的完整内容(以及完整的树、提交等)更准确,并且该内容是通过散列精确指定的。 AFAIK 补丁永远不会由 git 存储,只有在用户或工具需要时才会计算。
      • @Mark: 在“git 管理什么”前面是真的:它管理一个 repo 的完整内容(不仅仅是一个文件,而是一个完整的树)。但我的“补丁”类比完全是关于索引。
      【解决方案4】:

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

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

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

      $ 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] 如果您想确保历史记录中的每个提交都经过正确测试,那么您应该小心执行此操作 - 如果这在您的项目中很重要,您应该在每次新提交之前测试树,然后再推送...

      【讨论】:

        【解决方案5】:

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

        【讨论】:

          猜你喜欢
          • 2011-02-15
          • 1970-01-01
          • 2018-03-27
          • 2010-11-30
          • 2022-10-20
          • 2011-02-14
          • 1970-01-01
          相关资源
          最近更新 更多