Git提交提交暂存和未暂存的文件

Git提交提交暂存和未暂存的文件,git,Git,TL;DR:当一个文件有暂存和未暂存的更改时,提交将提交两个版本,以及对该文件的最新更改。为什么?我认为提交只会提交阶段版本,如下所述: 假设我们的工作目录中有一个文件。(此前已承诺回购。) 文件内容当前仅为一个字符(数字1): 让我们将文件的内容更改为“12”。现在我们有了这个: $ cat foo.txt 12 我们的工作目录显示了更改(为了简洁起见,删除了git教学输出): 现在,git add会将该文件添加到staging索引中 $ git add foo.txt 您在此处看不到它,

TL;DR:当一个文件有暂存和未暂存的更改时,提交将提交两个版本,以及对该文件的最新更改。为什么?我认为提交只会提交阶段版本,如下所述:

假设我们的工作目录中有一个文件。(此前已承诺回购。)

文件内容当前仅为一个字符(数字1):

让我们将文件的内容更改为“12”。现在我们有了这个:

$ cat foo.txt
12
我们的工作目录显示了更改(为了简洁起见,删除了git教学输出):

现在,
git add
会将该文件添加到staging索引中

$ git add foo.txt
您在此处看不到它,但文件名现在为绿色,表示它已暂存:

$ git status
modified:   foo.txt
此时,我们可以提交该文件,它将成为本地存储库的一部分。但是,让我们先更改
foo.txt
,看看会发生什么

$ cat foo.txt
123
如果我们检查
git status
,我们会看到foo.txt的两个版本:

$ git status
On branch master
Changes to be committed:

        modified:   foo.txt

Changes not staged for commit:

        modified:   foo.txt
第一个
foo.txt
为绿色。第二个是红色的。第一份报告的内容是“12”。第二个有“123”。如果我们现在就承诺会发生什么?只应提交暂存的
foo.txt
。因此,以“12”为主体的
foo.txt
将出现在我们的本地回购协议中。另一个版本的
foo.txt
仍在我们的工作目录中

foo.txt
提交给我们的本地回购协议,就像我们添加它时一样:

$ git commit -m "Added 2 to foo." foo.txt
然而,事实并非如此。我们的工作目录现在没有变化。两个版本都已提交。为什么?

$ git status
On branch master
nothing to commit, working tree clean

因为您使用的是git commit[…]foo.txt:

git提交[…]
[…]…​]

…​
当在命令行上提供文件时,该命令将提交命名文件的内容,而不记录已转移的更改。这些文件的内容也将转移到以前转移的内容之上,以便下次提交


如果只想提交暂存版本,请在不指定任何文件的情况下运行
git commit

例如:

$ echo 2 > foo
$ git add foo
$ echo 3 > foo
$ git commit -m haha
现在已提交暂存版本,未暂存的更改仍保留在您的工作目录中。这很容易验证:

$ git show HEAD:foo
2
$ git diff
--- a/foo
+++ b/foo
@@ -1 +1 @@
-2
+3

也许让我用另一个例子来演示这种行为(
git commit
with file):

执行以下操作:

$ git init
$ echo 1 > foo
$ echo 1 > bar
$ git add foo bar
$ git commit -m 1
现在
foo
bar
都已提交

$ echo 2 > foo
$ echo 2 > bar
现在这两个都改变了,让我们进行stage
foo
和commit
bar

$ git add foo
$ git commit -m 2 bar
$ git status
Changes to be committed:
    modified: foo
$ git diff --name-only HEAD~ HEAD
bar
您可以看到,
foo
在提交中没有更改,但保留了暂存状态。

除了现有的(正确的)答案之外,值得注意的是,在使用
git commit[flags]file1 file2…fileN时,您可以输入标志
--仅
--包含

  • --只有
    是默认值,这意味着不管我到目前为止做了什么,只要添加这些文件就可以提交

  • ——include
    意味着到目前为止我所做的工作,也要添加这些文件

这很简单,但有点错误,因为
--只有
也必须执行after-commit操作

正确理解Git需要知道Git的索引是什么,以及Git提交的方式实际上是提交索引中的内容,而不是工作树中的内容

Git程序员设想您使用Git的方式 索引是一件相当复杂的事情,但大部分可以归结为:索引包含一组文件,这些文件将进入您的下一次提交。也就是说,如果您现在运行
git commit
,而不列出任何文件,那么新提交将是当前索引中所有文件的快照,并保存cont现在索引中的元素

这意味着:

$ git clone <some-url>
$ cd <repository>
$ git checkout <branch>
开始时,每个文件的所有三个版本都是相同的。(请注意,您不能更改
副本。您只能进行一次新的提交,然后成为
副本,因为
命名了新的提交。)

现在编辑工作树中的两个文件:

    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)
同时,真正的索引还没有改变。向上滚动一点,看看它:哪个版本的
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
进行第二次提交了。

因此,默认行为是提交甚至未保存的更改?如果是这样,为什么还要麻烦执行
git add
?您将如何仅提交暂存版本?@BobHorn要仅提交暂存版本,请运行
git commit
没有指定任何文件。啊,这就是我所缺少的。谢谢你。当。谢谢你提供的信息。这比我想象的要多。:)
    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)
    HEAD         ugly-index       work-tree
-------------   -------------   -------------
README.txt(2)   README.txt(1)   README.txt(2)
main.py(1)      main.py(2)      main.py(2)
    HEAD            index         work-tree
-------------   -------------   -------------
README.txt(2)   README.txt(2)   README.txt(2)
main.py(1)      main.py(2)      main.py(2)