为了账号安全,请及时绑定邮箱和手机立即绑定

Git之暂存区

标签:
Java

前篇

之前提交过demo,如何查看日志呢

$ cd /git/test/demo
$ git log --stat
commit ac01ff39a78fa388e1e628754fd55a76feb358d2 (HEAD -> master)
Author: smxknife <2323937771@qq.com>
Date:   Tue Mar 27 23:38:05 2018 +0800

    init hellogit file

 hellogit | 1 +
 1 file changed, 1 insertion(+)

可以看到修改记录

diff

现在对文件进行修改

$ echo "new change" >> hellogit

使用diff命令进行比较

$ git diff
diff --git a/hellogit b/hellogit
index d974466..c49fee4 100644
--- a/hellogit
+++ b/hellogit
@@ -1 +1,2 @@
 Hello Git.
+new change

从上面来看确实修改了,也存在差异,那么久提交吧

$ git commit -m "modify hellofile, add new change"
On branch master
Changes not staged for commit:
    modified:   hellogit

no changes added to commit

从输出结果上看好像有点问题,貌似没提交成功,通过日志来看

$ git log --pretty=oneline
ac01ff39a78fa388e1e628754fd55a76feb358d2 (HEAD -> master) init hellogit file

日志里也只有一行输出,查看文件状态

$ git status或者$ git status -s(简略输出信息)
输出如下:

$ git status -s
 M hellogit

无论怎么看都是提交失败,什么原因????这就涉及到了暂存区的概念

暂存区(stage)

git规定修改文件之后要先执行add操作,虽然感觉很别扭,但是无奈只能这么做

$ git add hellogit

再用git diff会发现没有任何输出,再执行git status -s

$ git status -s
M  hellogit

乍一看没什么变化,但是请与上面对比来看,是不是M的位置发生了变化,在add操作之前M的位置在第二列,add之后M的位置为第一列

第一列M代表的含义是:仓库中的文件与暂存区中的文件相比有改动
第二列M代表的含义是:工作区中的当前文件与暂存区的文件相比有改动

那么执行add之前,M位于第二列,说明比较的是工作区与暂存区,而add之后比较的是仓库与暂存区

从这可以看出add的目的就是将工作区的文件提交到暂存区

那么再修改一下文件内容

$ echo "third change." >> hellogit 

$ git status -s
MM hellogit

$ git diff
diff --git a/hellogit b/hellogit
index c49fee4..990080f 100644
--- a/hellogit
+++ b/hellogit
@@ -1,2 +1,3 @@
 Hello Git.
 new change
+third change.

从上面的结果来看,hellogit的status存在两个M,说明工作区相比暂存区有更改,暂存区相比仓库有更改。而此时git diff命令有输出结果了,说明git diff 默认是工作区与暂存区进行比较

从这个结果来看,文件在Git中会存在三种状态,仓库中的状态、暂存区中的状态、工作区中的当前状态

将工作区和HEAD(当前工作分支)相比

$ git diff HEAD
diff --git a/hellogit b/hellogit
index d974466..990080f 100644
--- a/hellogit
+++ b/hellogit
@@ -1 +1,3 @@
 Hello Git.
+new change
+third change.

将暂存区和仓库相比 (--cached或--staged)

$ git diff --cached
diff --git a/hellogit b/hellogit
index d974466..c49fee4 100644
--- a/hellogit
+++ b/hellogit
@@ -1 +1,2 @@
 Hello Git.
+new change

$ git diff --staged
diff --git a/hellogit b/hellogit
index d974466..c49fee4 100644
--- a/hellogit
+++ b/hellogit
@@ -1 +1,2 @@
 Hello Git.
+new change

好了,现在进行commit操作,那么将会提交的是哪个版本呢?

$ git commit -m "which version checked in?"
[master 0789463] which version checked in?
 1 file changed, 1 insertion(+)

通过上面来看只有一行插入,所以两个变化只提交了一个

再通过一系列命令来查看

$ git status -s
 M hellogit

$ git diff
diff --git a/hellogit b/hellogit
index c49fee4..990080f 100644
--- a/hellogit
+++ b/hellogit
@@ -1,2 +1,3 @@
 Hello Git.
 new change
+third change.

$ git diff HEAD
diff --git a/hellogit b/hellogit
index c49fee4..990080f 100644
--- a/hellogit
+++ b/hellogit
@@ -1,2 +1,3 @@
 Hello Git.
 new change
+third change.

$ git diff --staged
# 没有任何输出

通过上面一系列的输出来看,这次commit只提交了暂存区的文件修改,工作区的依然没有变化,所以,本地工作区每次修改文件后都需要先add到暂存区,然后再commit到仓库中。那么将所有的更改先提交到仓库吧

前面提到过.git/index文件,其实这个index就是暂存区文件,当执行git status扫描工作区改动的时候,先根据.git/index文件记录的时间戳、长度等信息判断工作区文件是否改变,如果工作区文件时间戳改变了,说明文件内容可能被改变了,需要打开文件读取内容,与原始文件进行比较,判断文件是否被改变。如果没有变化就将新的时间戳记录到.git/index文件中。通过时间戳和文件长度比较比文件内容比较快的多,这正是git高效的原因之一

通过下面的一张图来形象的理解一下工作区、暂存区、仓库(版本库)的原理

index其实就是一个索引目录树,记录了文件名和文件状态信息(时间戳和长度),真正的文件内容是存储在.git/objects目录中

$ git reset HEAD重写暂存区的目录树,此时会被master分支指向的目录树替换,但是不影响工作区

$ git rm --staged <fileName>会直接从暂存区删除文件,工作区不受影响

$ git checkout$ git checkout -- <fileName> 这是两个非常危险的操作,前者会将暂存区所有的文件替换工作区的文件,后者是替换指定的文件。这两个操作都会导致工作区修改的且未添加的修改丢失,慎重!!!

$ git checkout HEAD$ git checkout -- <fileName>这个与上面的类似,但是更加危险,会用仓库里面文件替换暂存区和工作区两个地方

一些命令

查看HEAD指向的目录树

git ls-tree -l HEAD

清理工作区

突然发现工作区太乱了,没有有用的东西需要清理

$ git clean -fd # 清楚工作区中没有加入仓库的文件和目录
$ git checkout . # 使用暂存区进行刷新

查看暂存区的目录树

git ls-files -s

不要使用git commit -a

Git提供了一个简化命令,git commit -a 减少了add的步骤,可以直接将修改的文件进行commit,但是未被版本库跟踪的文件时不能提交的。

这样做确实简化了操作步骤,但是就会丢掉Git暂存区的最大好处:对提交的内容进行控制的能力

点击查看更多内容
1人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消