增删查改

但我们每次修改文件的时候,我们可以使用 git add 加上文件的名字,将文件加入版本库,然后再使用 git commit 提交修改。假设我们在版本库中创建了三个新的文件file1.txt,file2.txt,file3.txt,那我们我们可以使用以下的命令更新版本库:

$ git add file1.txt file2.txt file3.txt
$ git commit -m "Added three new files"

除了使用第一行的方式添加多个文件,我们可以使用git add .(英文句号)将当前所有有变化的文件加入版本库:

$ git add .

Git记录 (log)

在git中,每一次提交修改(commit),这条记录都会被保存起来。好比建大楼的时候,每个commit记录了盖楼需要添加和拿走的材料,这个施工过程都被记录下来了。而在git中,使用git log就能查看代码改动信息。

基于我们之前对版本库的改动,我们使用git log就能看的以下的信息,其中包含了commit ID、作者(修改者)、日期和修改备注:

commit 2443b8c95bd2f426447b76b77ad5385a3d79a4ea (HEAD -> master)
Author: Enoch <[email protected]>
Date:   Thu Oct 17 08:06:30 2019 -0700

    Added three new files

commit f76e81f3c8e7c54dd917e9616da64ff3fde4fab9
Author: Enoch <[email protected]>
Date:   Mon Oct 14 09:44:19 2019 -0700

    Modified the first two lines of new file

commit 2bbcd42eb3441375ae8f3c0b15d3f776302ad4fe
Author: Enoch <[email protected]>
Date:   Mon Oct 14 09:32:28 2019 -0700

    Added a new file

如果这个时候我们在file1.txt的内部添加以下内容:

new content

然后我们再使用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:   file1.txt

no changes added to commit (use "git add" and/or "git commit -a")

那我们就先将此改动添加(add)并提交(commit)到版本库:

$ git add file1.txt
$ git commit -m "Modified file1"
[master 0e84b3e] Modified file1
 1 file changed, 1 insertion(+)

这个时候我们再查看log,则会发现我们多了一条commit:

commit 0e84b3e405630f1fc6ca9beb82cf5ca9ed38ea5a (HEAD -> master)
Author: Enoch <[email protected]>
Date:   Thu Oct 17 08:21:19 2019 -0700

    Modified file1

commit 2443b8c95bd2f426447b76b77ad5385a3d79a4ea
Author: Enoch <[email protected]>
Date:   Thu Oct 17 08:06:30 2019 -0700

    Added three new files
...

Working directory, Staging area, Repository

Image result for git stages image

为了帮助大家更好的理解工作区(working directory)、暂存区(staging directory)、和版本库(repository),我们可以对各个区域进行修改,然后通过git diff来查看他们之间的区别。

比如我们先给file2.txt添加以下的内容:

new content in file2

入行我们使用git diff来对比当前的工作区和上一次commit的版本库的区别:

$ git diff
diff --git a/file2.txt b/file2.txt
index e69de29..de59346 100644
--- a/file2.txt
+++ b/file2.txt
@@ -0,0 +1 @@
+new content in file2

如果这个时候我们使用add file2的修改,将当前的改动添加到暂存区,那么我们使用git diff后,会发现没有任何信息,这是因为我们的改动被转移到暂且区了。所以我们可以使用diff加上–cached来对比当前的暂存区和上一个commit的区别:

$ git diff --cached
diff --git a/file2.txt b/file2.txt
index e69de29..de59346 100644
--- a/file2.txt
+++ b/file2.txt
@@ -0,0 +1 @@
+new content in file2

我们可以再改动一下file3.txt,在其中添加以下内容:

new content in file3

我们可以使用git diff HEAD来对比当前暂且区和工作区的区别:

diff --git a/file2.txt b/file2.txt
index e69de29..de59346 100644
--- a/file2.txt
+++ b/file2.txt
@@ -0,0 +1 @@
+new content in file2
diff --git a/file3.txt b/file3.txt
index e69de29..944ef83 100644
--- a/file3.txt
+++ b/file3.txt
@@ -0,0 +1 @@
+new content in file3

这个时候我们将三个区间的内容进行对比,大家就能理解三个区间的关系了:

$ git diff
diff --git a/file3.txt b/file3.txt
index e69de29..944ef83 100644
--- a/file3.txt
+++ b/file3.txt
@@ -0,0 +1 @@
+new content in file3

$ git diff --cached
diff --git a/file2.txt b/file2.txt
index e69de29..de59346 100644
--- a/file2.txt
+++ b/file2.txt
@@ -0,0 +1 @@
+new content in file2

$ git diff HEAD
diff --git a/file2.txt b/file2.txt
index e69de29..de59346 100644
--- a/file2.txt
+++ b/file2.txt
@@ -0,0 +1 @@
+new content in file2
diff --git a/file3.txt b/file3.txt
index e69de29..944ef83 100644
--- a/file3.txt
+++ b/file3.txt
@@ -0,0 +1 @@
+new content in file3

但我们确定要修改的内容后,我们可以直接add并commit,将所有的修改加到暂存区后并提交到版本库:

$ git add .
$ git commit -m "Modified file2 and file3"
[master 0aef827] Modified file2 and file3
 2 files changed, 2 insertions(+)

时光穿越机 (checkout & reset)

有时候我们对一些文件做了改动,并加到暂存区,但是又后悔了,这些操作在 git 中也能实现。比如,我们继续改动file1.txt,在其中添加一行的内容:

new content
more content

然后我们把file1.txt加入暂存区,如果我们想要反悔,可以直接使用 git reset 把 file1.txt 从暂存区拉回到工作区,然后对文件做相应的修改后再add:

$ git add file1.txt
$ git status -s 
M  file1.txt # working directory
$ git reset file1.txt
Unstaged changes after reset:
M	file1.txt
$ git status -s 
 M file1.txt # staging area

然后我们把file1.txt中第一行new content删除,只剩下more content之后,直接add然后commit:

$ git add file1.txt
$ git commit -m "Added more content in file1"

接下来我们来了解git中的checkout,checkout可以帮助我们让当前的工作区回到特定的某个commit,比如我们使用git log查看过去的一些commit:

$ git log --oneline
5c10f81 (HEAD -> master) Added more content in file1
0aef827 Modified file2 and file3
0e84b3e Modified file1
2443b8c Added three new files
f76e81f Modified the first two lines of new file
2bbcd42 Added a new file

然后我们使用checkout回到 0aef827 这个commit,可以发现 file1.txt 的内容也变回了,因为在那个时候 file1 的内容并没有被改动,所以我们用了git log之后并没有 Added more content in file1 这个commit:

$ git checkout 0aef827
Note: checking out '0aef827'.
....
$ cat file1.txt
new content
$ git log --oneline
0aef827 (HEAD) Modified file2 and file3
0e84b3e Modified file1
2443b8c Added three new files
f76e81f Modified the first two lines of new file
2bbcd42 Added a new file

若想要在从过去回到现在,我们可以使用 git checkout master:

$ git checkout master
$ cat file1.txt
more content

我们可以通过下面的图片对checkout进行理解:

回到从前 (reset)
回到从前 (reset)
回到从前 (reset)
回到从前 (reset)

这里的HEAD其实是一个指针,可以让我们知道当前处于哪一个commit。如果我们想要让HEAD彻底回到某一个commit,我们可以使用在reset后面加上–hard参数:

$ git reset --hard HEAD # 当前add的工作全部消失,回到上一次commit 
HEAD is now at 5c10f81 Added more content in file1
$ git log --oneline
5c10f81 (HEAD -> master) Added more content in file1
0aef827 Modified file2 and file3
0e84b3e Modified file1
...
$ git reset --hard HEAD^ # 回到当前master的上一个commit:c0aef827
$ git reset --hard 0e84b3e # 回到具体的某一个commit
$ git log --oneline 
0e84b3e (HEAD -> master) Modified file1
2443b8c Added three new files
f76e81f Modified the first two lines of new file
2bbcd42 Added a new file

我们的 Modified file2 and file3 彻底消失了!如果我们想要重新挽回改动,可以使用 git reflog 查看最近做的所有的 HEAD 的改动,并使用 reset 重回到想要退回的 commit:

$ git reflog
0e84b3e (HEAD -> master) HEAD@{0}: reset: moving to 0e84b3e
0aef827 HEAD@{1}: reset: moving to HEAD^
5c10f81 HEAD@{2}: reset: moving to HEAD
5c10f81 HEAD@{3}: checkout: moving from 0aef8274ff89375120cbd38be7e4a494aa19f0e7 to master
0aef827 HEAD@{4}: checkout: moving from master to 0aef827
5c10f81 HEAD@{5}: commit: Added more content in file1
...
$ git reset --hard 5c10f81

通过查看 file1.txt 的内容,确定一下我们时空穿越成功:

$ git cat file1.txt
more content

实践练习

在第一个实践练习创建的版本库new_dir中,为file.txt添加一行内容 new random information,然后添加并提交新的commit。然后使用git reset将当前版本库退回至上一个commit,完成操作后,请确定file.txt又变成了空文件夹。