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