为什么“git commit -a”是有时需要代替“git commit”?

发布于 2024-10-19 15:43:39 字数 325 浏览 3 评论 0原文

在使用 Git 和 GitHub 时,我发现有时

git commit -a

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

但有时,只需一个

git commit

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

Playing with Git and GitHub,I found that sometimes a

git commit -a

is needed to commit a file that is modified. (this file has already been added to the project).

But sometimes, just a

git commit

will work. If using Mercurial, the command hg com always work if it is a file that is already added previously to the repo. So I wonder why git needs the -a sometimes? The word "staging" come up in some explanation but I don't fully understand the concept of staging and how it relates to committing some modifcations to a file?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

撞了怀 2024-10-26 15:43:39

仔细查看 git commit 的手册页 是这样描述的:

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

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

示例:如果您只想对某些已修改的文件进行提交(例如,您修复了影响两个文件的错误(one.c、two.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 来实现。这种提交标记称为“暂存”。

A close look at the man page of git commit describes it:

  • when you add a new file to git, you do it with git add. This marks the file to be added upon next commit (as well as git rm does for removing files).
  • when you change a file, you could also do git add to mark it for the next commit, but usually you don't. In that case, git commit -a does the work for you:

    Tell the command to automatically stage files that have been modified and deleted, but new files you have not told git about are not affected

Example: if you want to do a commit with only some files that are modified (e.g. you fixed a bug affecting two files (one.c, two.c) and removed some typos in other files and want to have the bugfix checkin separate from the typo checkin), you would do a git add for each of the bugfix files and then commit:

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

Once this is done, you commit your typo fixes using

git commit -a -m "fixed typos"

Regarding staging:
git commit only commits files that were marked in some way to be committed. This could happen through git add or git rm for example. This marking-for-commit is called staging.

凝望流年 2024-10-26 15:43:39

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

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

Suppose you have made two distinct logical changes to a file, but only want to commit one of them. If "git commit" always committed all files that it knows about, that act would be impossible. Thus, you need to stage each change before doing a commit. If you "git add filename", you are staging all changes in that file. BTW, "git stage" is a synonym for "git add", and it might make the actions clearer if you use "git stage" instead.

Think of the staging area (the index) as an intermediate area between your working directory and the repository. The commands "git add" and "git stage" move things into the index, and "git commit" moves them from the index to the repository. "git commit -a" does both steps at once. It is often very useful to be able to use the staging are to help refine your commits so that you commit exactly what you want.

王权女流氓 2024-10-26 15:43:39

另请参阅文章“您本可以发明 git(也许您已经发明了!)”:当您将索引视为“补丁数据库”时,它会有所帮助。

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

See also the article "You could have invented git (and maybe you already have!)": it helps when you think of the index as a "patch database".

If you "add" a file (to the "index" also known as "the staging area"), you actually add the patch represented by the evolutions made in that file.
If you made new evolutions in the same file after adding it to the index, you are actually doing a new patch (with all the new evolutions since the last "git add"), and those new evolutions will need to be added (to the index, the "patch database") before you will be able to commit.
Or you can just make git commit -a in that case.

太傻旳人生 2024-10-26 15:43:39

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

To understand the difference between git commit and git commit -a you do need to know about the index in git, also known as the staging area.

The index essentially stores the state of each file that will go into the next commit. (By "the state" here, I mean the exact contents of the file, which git identifies by its hash.) When you type git commit without any other parameters, git will make a new commit in which the states of all the files are exactly as in the index. This can be very different from your working tree, and that's a useful feature of git, as I'll explain below.

What git add really does is to "stage" a file, or add its current state to the index. It doesn't matter whether it was originally tracked or not, you're saying "in the next commit, I want this file to be present with exactly this content". It's important to realize that this records the content you want to add, and not the filename - that means that if you then carry on making changes to a file after you've staged it with git add you'll see output from git status that sometimes confuses people coming from other version control systems:

$ 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

... but that makes absolute sense if you know about the index. You can see the changes you've already staged (i.e. the difference between the state of files in the index and HEAD, which is typically the last commit on the branch you're working on) with:

$ git diff --cached

... and you can see all the changes that haven't been staged yet (i.e. the difference between your working copy and the index) with:

$ git diff

So why is this so useful? Essentially, the idea is that the history of your project is most useful when each commit just contains a logically grouped set of changes that make a well-defined improvement to the project. The smaller you can make these commits the better, since later the wonderful tool git bisect can quickly help you track down which change introduced a bug. Unless you're extraordinarily disciplined, in the process of fixing a bug, you'll often end up editing other files that you don't really need to change in order to fix the problem, or might end up fixing two logically different problems before deciding to commit your changes. In those cases the index can help you separate out those changes - just git add each file that contains changes that you want in the first commit, run git commit, then do the same to create the second commit. [1]

If you get used to doing this and like the workflow, you'll end up sometimes just wanting to stage some of the changes in a file and not others, in which case you'll want to find out about git add -p (and then its interactive s and e options!)

However, to get back to the original question - what does git commit -a do that's different? Essentially it says, "Before creating this commit, also stage every file that's been modified (or deleted) at its current state." So, if you don't think that carefully staging files in the index before committing is of use, you can just use "git commit -a" all the time. However, I think that one of the nice things about using git is that it encourages you create beautiful commits, and actively using the index is a great help for that. :)


Notes:

In order to keep the above explanation simple, some statements are somewhat approximate (e.g. I haven't mentioned that the index also stores the (non-)executable state of the file, that it can have multiple versions during a merge, etc. etc.)

[1] You should be careful doing this if you want to make sure that every commit in your history has been properly tested - if that's important in your project, you should test the tree at every new commit before pushing...

萧瑟寒风 2024-10-26 15:43:39

查看常见问题解答。简而言之,它使 git 更加灵活。

Check the faq. In short, it makes git more flexible.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文