git commit< file>之间有什么区别?和git commit --only? [英] what"s the difference between git commit <file> and git commit --only?

查看:56
本文介绍了git commit< file>之间有什么区别?和git commit --only?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这两个选项的功能似乎相同.

也许是因为我的英语阅读能力差,所以我看不到它们之间的差异.

你能告诉我真相吗?

解决方案

使用 git commit 的三种方法(始终不使用-amend ):

  • git commit ,而不命名任何文件:这意味着提交当前索引.

  • git commit-仅 file1 ... fileN ,在其中您命名一些文件使用-仅选项.我们待会儿会描述.

  • git commit --include file1 ... fileN ,您在其中命名一些文件使用-include 选项.我们也会对此进行描述.

如果您选择列出一些非零数量的文件,但忽略了-only 选项,则Git 假定 -only 选项.如果不想使用-only 选项,则必须指定-include 选项.如果您选择在命令行上列出某些文件,则必须选择这两个选项之一,如果您没有选择,则Git会为您选择.所以-only 只是-include 相反.

索引及其在提交中的作用

要正确理解所有三种操作模式,您需要了解Git通过索引构建提交.通常,它使用 the 索引.那是上面列出的第一种模式: git commit ,不带任何文件名,使用当前索引中的任何内容.

索引本身是某种程度上隐藏的数据结构.它具有三个名称,反映了它的重要性,或者反映了较差的初始名称,即索引".第二个名称是 staging area ,因为索引的作用是充当您构建(或 stage ) next 的位置>提交您将要做出的承诺.此事物的第三个名称(此索引或暂存区域)是缓存.

该索引开始时保存的是当前提交中所有文件的副本 ,这是您运行 git checkout 分支 时提取的.这些文件从分支提示提交复制到索引/暂存区域,并复制到工作树中,您可以在其中进行处理.名称​​ index 来自以下事实:索引跟踪工作树:它 indexes .(请参见动词定义此处.)

常规提交的工作方式

在正常模式下运行 git commit 时,Git会立即打包索引中位于 的所有文件-您在提交中的所有文件检出,并用 git add 编辑的文件覆盖工作树中的文件.这些文件成为新的快照.Git会写出快照本身,您作为提交作者的名称和电子邮件地址以及其他元数据(例如日志消息).它将新提交的 parent 设置到分支的上一个尖端,然后将新提交的哈希ID写入当前分支名称,以便新提交现在是当前提交.

由于Git刚从索引中构建了 new 提交 ,所以新的,当前的提交和索引匹配.因此,通过修改工作树文件并将其复制到索引中,一切都准备好进行 next 提交.

-仅-include 的工作方式

要使用-include 构建新的提交,Git本质上只是将文件添加到索引中并提交. 1 非常简单:它看起来就像您运行 git添加 file1 ... fileN 然后运行 git commit 一样.新提交是从修改后的索引(现在为 the 索引)构建的,因为它现在与新的当前提交匹配.

仅对于-,Git有问题. 索引(常规索引)很可能已被修改,可能不再与当前提交匹配.因此,Git所做的实际上是将当前提交提取到临时索引中,使用 git add 将工作树文件复制到该临时索引中,然后进行构建来自临时索引的提交.这部分并不那么复杂:新提交是从索引构建的,而不仅仅是 the 索引.但是一旦完成,Git便会回到问题所在:实际索引(您可能已修改的索引)与Git刚进行的新提交不匹配,并且可能与先前的提交不匹配.它什么都没有匹配,这真是一团糟.

在成功提交之后,Git此时要做的是将那些相同文件复制到 real 索引中,从而使 file1 ... fileN索引中的会进行更新以匹配您刚刚提交的内容.同时,实际索引中的所有剩余文件均会保留,但是它们在您运行 git commit --only 之前就已查找.

请注意,您已经仔细地在真实索引中暂存的文件(例如,使用 git add --patch )既不匹配工作树也不匹配旧的(不再是当前的)提交可能仍然是您上演它们的方式.但是,如果您将其中一个文件命名为仅文件之一,那么经过精心设计的版本现在就消失了!由于后提交 git add .已将其替换为工作树版本. 2


1 在内部,它更复杂:Git仍会建立临时索引,这仅适用于(仅适用于).但是,如果提交成功,则临时索引将变为常规索引.因此,这比-only 复杂.请注意,这个本质上"的短语体现了许多缺点:例如,如果文件是 git 的全新文件,则-include 部分将失败至少在某些版本的Git中有效,而直接的 git add 可以使用.

我在这里至少说 是因为我刚刚在Git 2.24.0中对其进行了测试,这是最新的,这可能意味着它在所有版本中均失败;但这似乎是一个错误,因此它可能会在将来的Git版本中得到修复.尤其令人恐惧的是,它只是默默地忽略新文件!您可以获得不包含您命名的文件的提交.这似乎不仅是一个错误,而且是一个不好的错误.

2 git commit --include 一样,这具有粗糙的边缘,尤其是对于当前不在索引中的文件.但是,至少Git 2.24中的行为要好一些,因为Git会在此处生成错误消息,而不是默默地忽略该文件.

It seems that the two options function the same way.

Maybe there is a difference between them which I can't see, cause of my poor English reading skills.

Could you tell me the truth?

解决方案

There are three ways to use git commit (without --amend anyway):

  • git commit, without naming any files: this means commit the current index.

  • git commit --only file1 ... fileN, where you name some number of files and use the --only option. We'll describe this in a moment.

  • git commit --include file1 ... fileN, where you name some number of files and use the --include option. We'll describe this in a moment as well.

If you choose to list some nonzero number of files, but omit the --only option, Git assumes the --only option. If you don't want the --only option, you must specify the --include option. If you choose to list some files on the command line, you must choose one of these two options, and if you fail to choose, Git will choose for you. So --only is merely the opposite of --include.

The index and its role in commits

To properly understand all three modes of operation, you need to understand that Git builds commits from an index. Normally it uses the index. That's the first mode listed above: git commit, without any file names, uses whatever is in the index right now.

The index itself is a somewhat hidden data structure. It has three names, reflecting either its great importance, or perhaps the rather bad initial name, i.e., "index". The second name is the staging area, because the role of the index is to act as the place in which you build—or stage—the next commit you will make. The third name of this thing—this index or staging-area—is the cache.

The index starts out holding copies of all the files in the current commit, as extracted when you ran git checkout branch. These files were copied from the branch-tip commit into the index / staging-area, and also into the work-tree where you can work on them. The name index comes from the fact that the index keeps track of the work-tree: it indexes it. (See the verb definitions here.)

How a regular commit works

When you run git commit in the normal mode, Git packages up all the files that are in the index right then—all the files that were in the commit you checked out, with files that you git add-ed overwritten with files from the work-tree. These files become the new snapshot. Git writes out the snapshot itself, your name and email address as the author of the commit, and your other metadata such as your log message. It sets the parent of the new commit to the previous tip of the branch, and then writes the new commit's hash ID into the current branch name, so that the new commit is now the current commit.

Since Git just built the new commit from the index, the new, now-current, commit and the index match. Hence everything is all ready for the next commit that you might make, by modifying work-tree files and copying them into the index.

How --only and --include work

To build a new commit with --include, Git in essence just adds the files to the index and commits.1 That's very straightforward: it looks as though you ran git add file1 ... fileN and then ran git commit. The new commit is built from this modified index, which is now the index, since it now matches the new current commit.

For --only, however, Git has a problem. The index—the regular one—has quite possibly been modified and may no longer match the current commit. So what Git does is, in effect, to extract the current commit into a temporary index, use git add to copy work-tree files into that temporary index, and then build the commit from the temporary index. This part is not that complicated: the new commit is built from an index, it's just not the index. But once this is done, Git is right back to the problem: the real index—the one you probably modified—doesn't match the new commit Git just made, and probably doesn't match the previous commit. It doesn't match anything, and this is a big mess.

What Git does at this point, following the successful commit, is to copy those same files to the real index, so that file1 ... fileN in the index are updated to match what you just committed. Meanwhile all remaining files in the real index remain however they looked before you ran git commit --only.

Note that files that you had carefully staged in the real index—using git add --patch, for instance—that neither matched the work-tree nor matched the old (no longer current) commit may still be the way you staged them. However, if you named one of those files as one of the --only files, the carefully-staged version is now gone! It has been replaced with the work-tree version because of the post-commit git add.2


1Internally, it's more complicated: Git still builds a temporary index, the way it does for --only. However, if the commit succeeds, the temporary index becomes the regular index. So this is less complicated than --only. Note that this "in essence" phrase papers over a multitude of sins: for instance, if the file is totally new to git, the --include part fails in at least some versions of Git, while a direct git add would work.

I say at least some here because I just tested it in Git 2.24.0, which is pretty current, which probably means it fails in all versions; but this seems like a bug, so it might get fixed in a future version of Git. What's particularly scary is that it just silently ignores new files! You can get a commit that does not include a file you named. That seems like not just a bug, but a bad one.

2As with git commit --include, this has rough edges, especially around the case of files that aren't currently in the index. However, the behavior in Git 2.24, at least, is slightly better in that Git produces an error message here, instead of silently ignoring the file.

这篇关于git commit< file>之间有什么区别?和git commit --only?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆