5.1 修改不能直接提交git
首先修改welcome.txt文件,在这个文件后面追加一行:svn
echo "Nice to meet you." >> welcome.txt
使用git diff命令查看修改后的文件与暂存区(并非版本库,后面会有相关讨论)中的文件的差别:3d
diff --git a/welcome.txt b/welcome.txt index a8f9fd8..b0e5c6e 100644 --- a/welcome.txt +++ b/welcome.txt @@ -1 +1,2 @@ Hello +Nice to meet you.
差别的输出格式:指针
此时使用git commit命令并不会提交修改,反而会报错:code
git commit -m "Append a nice line." On branch master Changes not staged for commit: modified: welcome.txt no changes added to commit
使用git status查看文件状态,加上-s参数显示精简格式的状态输出:对象
git status On branch master Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: welcome.txt no changes added to commit (use "git add" and/or "git commit -a"
git status -s M welcome.txt
welcome.txt文件处于修改状态。递归
根据git status输出的提示,须要对修改的文件执行git add命令,将修改的文件添加到“提交任务”中,而后才能提交。此处与svn差异很大,在svn中执行add操做是向版本库中添加新文件,修改的文件在下次提交时会直接提交。索引
按照提示将修改的文件添加到提交任务中:it
git add welcome.txt
在执行完添加操做,而没有执行提交操做时,查看一下Git工做区发生了什么变化:io
一、执行git diff没有输出,说明是本地文件与暂存区的比较;
二、执行git diff HEAD(当前版本库的头指针),会有差别输出,说明此时比较的是本地文件和版本库的最新版本;
三、执行git status,输出与添加前不同了:
On branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: welcome.txt
四、执行git status -s,以简洁方式显示状态:
git status -s M welcome.txt
乍一看貌似与添加前的输出同样,其实它们有细微的差异:
为了加深理解,暂不提交以前的添加任务,而继续修改文件:
echo "Bye-Bye." >> welcome.txt
查看一下状态:
git status On branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: welcome.txt Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: welcome.txt
这里同时出现了前文讨论的两种状态。再查看精简的状态:
git status -s MM welcome.txt
同时出现了两个M:不但版本库中最新提交的文件与处于暂存区中的文件相比有改动,并且工做区与暂存区中的文件相比也有改动。
即如今有三个不一样版本的welcome.txt:一个在工做区,一个在暂存区,一个是版本库中最新版本的welcome.txt。
使用不一样参数调用git diff命令能够看到不一样状态下welcome.txt文件的差别:
git diff diff --git a/welcome.txt b/welcome.txt index b0e5c6e..45cf837 100644 --- a/welcome.txt +++ b/welcome.txt @@ -1,2 +1,3 @@ Hello Nice to meet you. +Bye-Bye.
git diff HEAD diff --git a/welcome.txt b/welcome.txt index a8f9fd8..45cf837 100644 --- a/welcome.txt +++ b/welcome.txt @@ -1 +1,3 @@ Hello +Nice to meet you. +Bye-Bye.
git diff --staged diff --git a/welcome.txt b/welcome.txt index a8f9fd8..b0e5c6e 100644 --- a/welcome.txt +++ b/welcome.txt @@ -1 +1,2 @@ Hello +Nice to meet you.
执行提交操做:
git commit -m "which version checked in?" [master 326f237] which version checked in? 1 file changed, 1 insertion(+)
提交成功,使用git status -s查看状态:
git status -s M welcome.txt
文件名前少了第一个M,只剩下第二个M,说明暂存区的任务被提交到了版本库,如今只剩下工做区和暂存区的差别。
5.2 理解Git暂存区
在版本库.git目录下有一个index文件,看一下这个文件:
一、撤销工做区中welcome.txt文件还没有提交的修改(5.1中添加的Bye-Bye那一行)并查看工做区状态:
git checkout -- welcome.txt git status -s
git status -s无输出,说明未提交的修改已经被撤销了。
二、查看.git/index的时间戳:
ls --full-time .git/index -rw-r--r-- 1 x250 197121 145 2016-07-16 07:52:20.640437700 +0800 .git/index
时间戳是刚刚运行git status -s的时间。
三、再次查看工做区状态并查看.git/index的时间戳:
git status -s ls --full-time .git/index -rw-r--r-- 1 x250 197121 145 2016-07-16 07:52:20.640437700 +0800 .git/index
时间戳没有变化。
四、更改welcome.txt文件的时间戳,但并不改变它的内容(可使用touch命令,它用来修改文件时间戳,或者新建一个不存在的文件)。而后查看工做区状态并查看.git/index的时间戳:
touch welcome.txt git status -s ls --full-time .git/index -rw-r--r-- 1 x250 197121 145 2016-07-16 07:58:10.512449200 +0800 .git/index
发现git status -s依然无输出,说明工做区没有新的修改;可是.git/index时间戳改变了。
以上的实验说明当执行git status命令(或者git diff命令)扫描工做区改动的时候,先依据.git/index文件中记录的时间戳、长度等信息判断工做区文件是否改变。若是工做区文件的时间戳改变了,说明文件的内容可能被改变了,须要打开文件、读取文件内容,与更改前的原始文件相比较,判断文件内容是否被更改。若是文件内容没有改变,则将该文件新的时间戳记录到.git/index文件中。由于若是要判断文件是否更改,使用时间戳、文件长度等信息进行比较要比经过文件北荣比较快得多,因此Git这样的实现方式可让工做区状态扫描更快速的执行。
文件.git/index是包含文件索引的目录树,记录了文件名和文件的状态信息,文件的内容没有存储在其中,而是保存在Git对象库.git/objects目录中,文件索引创建了文件和对象库的对应关系。
下图展现了工做区、版本库中的暂存区和版本库之间的关系:
5.3 浏览暂存区和版本库的目录树、git diff
一、浏览暂存区和版本库的目录树
对于HEAD指向的目录树,可使用git ls-tree来查看,-l参数可现实文件的大小:
git ls-tree -l HEAD 100644 blob b0e5c6e24bc84d489773b2fda5accf005bc912f1 25 welcome.txt
输出中的信息从左到右:
下面的命令清除当前工做区中没有加入版本库的文件和目录:
git clean -fd
下面的命令用暂存区内容刷新工做区:
git checkout .
对工做区作一些修改:
$ echo "Bye-Bye." >> welcome.txt $ mkdir -p a/b/c $ echo "Hello." > a/b/c/hello.txt $ git add . x250@x250-PC MINGW64 ~/demo (master) $ echo "Bye-Bye." >> a/b/c/hello.txt $ git status -s AM a/b/c/hello.txt M welcome.txt
查看工做区文件的大小:
$ find . -path ./.git -prune -o -type f -printf "%-20p\t%s\n" ./a/b/c/hello.txt 16 ./welcome.txt 36
显示暂存区的目录树:
git ls-files -s 100644 18832d35117ef2f013c4009f5b2128dfaeff354f 0 a/b/c/hello.txt 100644 45cf8376b221e28cb9c5afb382cfe15ceb3dc520 0 welcome.txt
-s命令要去显示暂存区中Object的对象名。输出中的0不是文件大小而是暂存区编号。若是想针对暂存区的目录树使用git ls-tree命令,须要先将暂存区的目录树写入Git对象库(git write-tree):
$ git write-tree 1343285bb5205fe9eed661efebcc9d65bf0cea7e $ git ls-tree -l 1343285 040000 tree 53583ee687fbb2e913d18d508aefd512465b2092 - a 100644 blob 45cf8376b221e28cb9c5afb382cfe15ceb3dc520 34 welcome.txt
git write-tree的输出是写入Git对象库中的TreeID,这个ID将做为下一条命令的参数。
在git ls-tree命令中,没有把40位的ID写全,而是使用了前几位,实际上只要不与其余对象的ID冲突,就可使用缩写ID。
git ls-tree输出的第一条显示目录a是一个tree对象。
若是想要递归显示目录内容,则使用-r参数。使用参数-t能够把递归中遇到的每棵树都显示出来,而不是只显示最终文件。
二、git diff
经过调用git diff并添加不一样参数,能够对工做区、暂存区和HEAD中的内容进行两两比较。以下图所致(1)工做区和暂存区的比较:
$ git diff diff --git a/a/b/c/hello.txt b/a/b/c/hello.txt index 18832d3..e8577ea 100644 --- a/a/b/c/hello.txt +++ b/a/b/c/hello.txt @@ -1 +1,2 @@ Hello. +Bye-Bye.
(2)暂存区和HEAD比较
git diff --cached diff --git a/a/b/c/hello.txt b/a/b/c/hello.txt new file mode 100644 index 0000000..18832d3 --- /dev/null +++ b/a/b/c/hello.txt @@ -0,0 +1 @@ +Hello. diff --git a/welcome.txt b/welcome.txt index b0e5c6e..45cf837 100644 --- a/welcome.txt +++ b/welcome.txt @@ -1,2 +1,3 @@ Hello Nice to meet you. +Bye-Bye.
(3)工做区和HEAD比较
git diff HEAD diff --git a/a/b/c/hello.txt b/a/b/c/hello.txt new file mode 100644 index 0000000..e8577ea --- /dev/null +++ b/a/b/c/hello.txt @@ -0,0 +1,2 @@ +Hello. +Bye-Bye. diff --git a/welcome.txt b/welcome.txt index b0e5c6e..45cf837 100644 --- a/welcome.txt +++ b/welcome.txt @@ -1,2 +1,3 @@ Hello Nice to meet you. +Bye-Bye.
5.4 不要使用git commit -a
Git的提交命令(git commit)能够带上-a参数,对本地全部变动的文件执行提交操做,包括对本地修改的文件和删除的文件,但不包括未被版本库跟踪的文件。
这个命令的确能够简化一些操做,减小用git add命令表示变动文件的步骤,可是若是习惯了使用这种偷懒的提交命令,机会丢掉Git暂存区最大的好处:对提交内容进行控制的能力。做者推荐不要使用git commit -a。
5.5 保存当前的工做进度
git stash Saved working directory and index state WIP on master: 326f237 which version checked in? HEAD is now at 326f237 which version checked in? $ git status On branch master nothing to commit, working directory clean
git stash命令备份当前的工做区的内容,从最近的一次提交中读取相关内容,让工做区保证和上次提交的内容一致。同时,将当前的工做区内容保存到Git栈中。
运行完git stash后使用git status命令,发现工做区中还没有提交的改动都不见了。