# Git时光穿梭机
此为学习笔记,教学文档请移步廖雪峰的官方网站 (opens new window),本篇文章主要记录版本会退和恢复文件命令。
在git基础里面我们已经成功添加并提交了readme.txt
文件,现在我们对文件进行修改:
现在使用git status
查看结果
$ 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: readme.txt
no changes added to commit (use "git add" and/or "git commit -a")
2
3
4
5
6
7
8
9
git status命令用来查看仓库当前的状态,上面命令的输出告诉我们,readme.txt
文件被修改过了,但还没有准备提交的修改。
git status
只是告诉我们有修改,我们可以通过git diff
来查看具体的修改内容:
git diff (file name)显示工作区该文件与版本库中当前分支下该文件的差异。
$ git diff
diff --git a/readme.txt b/readme.txt
index c3295f1..a440e5c 100644
--- a/readme.txt
+++ b/readme.txt
@@ -1,2 +1,2 @@
-git is a version controller system.
+git is a distributed controller system.
git is free software
2
3
4
5
6
7
8
9
详解:
diff --git a/readme.txt b/readme.txt
——对比两个文件,其中a改动前,b是改动后,以git的diff格式显示;index c3295f1..a440e5c 100644
——两个版本的git哈希值,index区域(add之后)的c3295f1对象和工作区域的a440e5c对象,100表示普通文件,644表示权限控制;--- a/readme.txt +++ b/readme.txt
——其中减号表示变动前,加好表示变动后。@@ -1,2 +1,2 @@
——@@表示文件变动描述合并显示的开始和结束,其中-+表示变动前后,逗号前是起始行位置,逗号后为从起始行往后几行。合起来就是变动前后都是从第1行开始,变动前文件往后数2行对应变动后文件往后数2行。-git is a version controller system. +git is a distributed controller system.
——+表示增加了这一行,-表示删除了这一行,没符号表示此行没有变动。
知道对齐做了什么修改之后,我们就可以提交修改了,步骤与提交新文件一样,都是两个步骤,第一步git add
$ git add readme.txt
添加成功后,我们可以使用git status
查看当前仓库的状态
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: readme.txt
2
3
4
5
6
上面的信息告诉我们将要被提交的修改为readme.txt
,然后我们可以使用git commit
进行提交。
$ git commit -m 'version replaced by distributed in line 1'
[master 2e0bdc4] version replaced by distributed in line 1
1 file changed, 1 insertion(+), 1 deletion(-)
2
3
提交后,再次使用git status
查看状态,
$ git status
On branch master
nothing to commit, working tree clean
2
3
git告诉我们,没有文件需要被提交,且工作目录是干净的。
# 版本回退
我们先再次修改一下readme.txt
,并进行提交,修改内容如下:
Git is a distributed version control system.
Git is free software distributed under the GPL.
2
提交如下:
$ git add readme.txt
$ git commit -m 'appened GPL'
[master af61833] appened GPL
1 file changed, 2 insertions(+), 2 deletions(-)
2
3
4
# 查看提交历史
在git中我们可以通过git log
命令来查看提交的历史记录
commit af6183376d218e36978735de48e9db0790fcb743 (HEAD -> master)
Author: lf <781723804@qq.com>
Date: Sun Jul 7 15:03:24 2019 +0800
appened GPL
commit 2e0bdc40e2c63128b955fd0e6c3c3cadc895c684
Author: lf <781723804@qq.com>
Date: Sun Jul 7 14:45:14 2019 +0800
version replaced by distributed in line 1
commit 1210adbed7497662a6a0c88bd53adb69e497df69
Author: lf <781723804@qq.com>
Date: Sun Jul 7 01:44:27 2019 +0800
write a readme file
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
git log
显示从近到远的提交日志,我们可以看到总共有3次提交,最近的一次是appened GPL
,上一次是version replaced by distributed in line 1
,最早的一次是write a readme file
也可以使用git log --pretty=oneline而使一条记录显示一行
这里黄色的部分是commit id
(版本号)是一个SHA1计算出来的一个非常大的数字,用十六进制表示。
每提交一个新版本,git会将它们自动串成一条时间线。
# 回退到历史版本
如果我们想要把readme.txt
回退到上一版本,也就是 version replaced by distributed in line 1
那个版本,需要以下的步骤:
首先,必须知道当前版本,在Git中HEAD表示当前版本,也就是appened GPL
版本,想要到上一个版本,就是HEAD ^
,上上个版本是HEAD ^^
,如果是前10个版本,则可以用HEAD~10
,
我们需要使用git reset进行版本回退
$ git reset --hard HEAD^
HEAD is now at 2e0bdc4 version replaced by distributed in line 1
2
--hard
参数有啥意义?这个后面再讲,现在你先放心使用。
我们可以看看 readme.txt
的内容是不是version replaced by distributed in line 1
版本
$ cat readme.txt
git is a distributed controller system.
git is free software
2
3
我们可以看到已经还原到了上一个版本,这时我们使用git log
查看版本库的状态
最新版本的append GPL
已经不见了,如果想要回到这个版本,则需要以下方法
# 返回未来的版本
想要恢复到append GPL
的版本,则需要首先找到其commit id(版本号),这时就需要git reflog来查看git记录每一次的命令。
这时我们可以看到,appened GPL
的版本号为af61833
,然后我们使用git reset --hard (commit id)就可回到未来的某个版本号。
$ git reset --hard af61833
HEAD is now at af61833 appened GPL
2
这是我们使用cat
命令查看文件内容:
$ cat readme.txt
git is a distributed version controller system.
git is free software distributed under GPL
2
3
说明已经将版本转换回来,Git的版本回退速度非常快,因为Git在内部有个指向当前版本的HEAD指针,当你回退版本的时候,Git仅仅是把HEAD从指向version replaced by distributed in line 1
:
┌────┐
│HEAD│
└────┘
│
│ ○ append GPL
│ │
└──> ○ version replaced by distributed in line 1
│
○ wrote a readme file
2
3
4
5
6
7
8
9
改为指向append GPL
┌────┐
│HEAD│
└────┘
│
└──> ○ append GPL
│
○ version replaced by distributed in line 1
│
○ wrote a readme file
2
3
4
5
6
7
8
9
# 工作区和暂存区
Git与SVN等其他版本库的一个不同之处就是存在一个暂存区的概念。
# 工作区(Working Directory)
即电脑里能够看到的目录,如之前建立的learngit
文件夹就是一个工作区。
# 版本库(Repository)
工作区里面的隐藏目录.git就是Git版本库。
Git版本库里面最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及的指针HEAD指向master
分支
我们将文件提交到Git版本库时,是分两步进行的:
git add
进行添加文件,实际上是将文件添加早暂存区;git commit
进行文件提交,实际是将 暂存区中的所有文件提交到当前分支。
因为我们使用的是Git为我们自动创建的master
分支,所以提交到的也是master
分支
我们先对readme.txt
文件进行修改,在最后一行添加如下内容:
git is a distributed version controller system.
git is free software distributed under GPL.
git has a mutable index called stage.
2
3
然后在工作区新建一个license
文本文件,里面内容随便填写。 先用git status
查看版本库的状态
$ 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: readme.txt
Untracked files:
(use "git add <file>..." to include in what will be committed)
license.txt
no changes added to commit (use "git add" and/or "git commit -a")
2
3
4
5
6
7
8
9
10
11
12
13
14
Git 告诉我们readme.txt
文件被修改了,而license.txt
文件还从来没有被提交过,所以其状态为Untracked
。
现在使用两次命令git add
之后,将readme.txt
和lincese.txt
文件都添加到暂存区后,使用git status
查看状态
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: license.txt
modified: readme.txt
2
3
4
5
6
7
这时,暂存区变为如图所示:
所以git add相当于将要提交的修改添加到暂存区(stage),然后通过git commit将暂存区的所有修改提交到分支。
$ git commit -m 'how stage works'
[master 35561ed] how stage works
2 files changed, 3 insertions(+), 1 deletion(-)
create mode 100644 license.txt
2
3
4
一旦提交之后,如果没有对工作区进行修改,则工作区就是“干净”的,类似于清空了购物车。
$ git status
On branch master
nothing to commit, working tree clean
2
3
这时暂存区中则没有任何内容:
# 管理修改
Git跟踪管理的是修改,而不是文件。这是Git比其他版本控制系统优秀的原因。
例如,我们在readme.txt
文件中天剑一行内容:
$ cat readme.txt
git is a distributed version controller system.
git is free software distributed under GPL.
git has a mutable index called stage.
git tracks change
2
3
4
5
然后添加:
然后再次修改readme.txt
文件
$ cat readme.txt
git is a distributed version controller system.
git is free software distributed under GPL.
git has a mutable index called stage.
git tracks changes of files
2
3
4
5
提交:
$ git commit -m 'git tracks changes'
[master fada47f] git tracks changes
1 file changed, 1 insertion(+)
2
3
查看状态
$ 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: readme.txt
no changes added to commit (use "git add" and/or "git commit -a")
2
3
4
5
6
7
8
9
这表明第二次修改并没有提交,当时的操作过程如下:
第一次修改 -> git add -> 第二次修改 -> git commit
由于Git管理的是修改,当第一次git add
之后,第一次修改被添加到暂存区,准备提交,第二次修改并没有进行git add
将修改添加到暂存区,因此git commit
只是把暂存区的文件进行提交,也就是第一次修改文件。
提交后,可以使用git diff HEAD -- readme.txt查看工作区和版本库里面最新版本的区别。
可见第二次修改并没有被提交。
可以在第二次修改完成后统一进行提交,也可以修改一次,进行一次git add
。
# 撤销修改
当地随便在readme.txt
文件下随便写了一行文字,
$ cat readme.txt
git is a distributed version controller system.
git is free software distributed under GPL.
git has a mutable index called stage.
git tracks changes of files
my lalla
2
3
4
5
6
在提交之前,你发现这行有错误,你可以删除掉最后一行,然后手动将文件恢复到上一个版本的状态,如果使用git status
查看
$ 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: readme.txt
no changes added to commit (use "git add" and/or "git commit -a")
2
3
4
5
6
7
8
9
git会提示你git checkout -- file可以丢弃工作区的修改
$ git checkout -- readme.txt
命令git checkout -- readme.txt文件的意思就是把,readme.txt
文件在工作区的修该全部撤销,其中包括两种情况:
readme.txt
文件修改后,还没有添加到暂存区,则撤销修改回与版本库一样的状态readme.txt
文件已经添加到暂存区,之后又进行了修改,则撤销修改回添加到暂存区之后的状态。
总之,就是让这个文件回到最近一次git commit
或git add
时的状态。
现在查看文件的状态:
$ cat readme.txt
git is a distributed version controller system.
git is free software distributed under GPL.
git has a mutable index called stage.
git tracks change
2
3
4
5
可以发现文件内容复原了。
如果添加了错误内容,并git add
将其添加到暂存区域了,这是我们在使用git status
查看状态
Git告诉我们使用git reset HEAD file可以把暂存区的修改撤销掉(unstage),重新放回到工作区
$ git reset HEAD readme.txt
Unstaged changes after reset:
M readme.txt
2
3
git reset
命令既可以回退版本,也可以把暂存区的修改回退到工作区。当我们用HEAD
时,表示最新的版本。
再次使用git status
查看,可以看到暂存区是干净的,工作区有修改
$ 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: readme.txt
no changes added to commit (use "git add" and/or "git commit -a")
2
3
4
5
6
7
8
9
这时我们可以使用git checkout -- file丢弃工作区的修改
如果已经提交到了版本库中,则需要使用版本回退来撤销修改。前提是还没推送到远程库
# 删除文件
在Git中,删除也是一种操作,我们先添加一个test.txt
文件并提交:
一般我们会在工作区中删除文件,或者在命令行使用rm
命令删除文件
这个时候Git知道删除了文件,所以工作区和版本库中文件不一致,可以使用git status
来查看那些文件被删除了
$ git status
On branch master
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
deleted: test.txt
no changes added to commit (use "git add" and/or "git commit -a")
2
3
4
5
6
7
8
9
如果确实要删除此文件,根据提示可以使用
git add/rm file
删除,并使用git commit
进行提交
这时,文件就从版本库中删除了。
小提示:先手动删除文件,然后使用git rm file和git add file效果是一样的。都将文件修改信息添加到了暂存区。
2.不小心错误的删除了文件,因为版本库中还存在,所以我们可以很轻松的把文件回复到最新版本。
$ git checkout -- file
注意:从来没有被添加到版本库就被删除的文件,是无法恢复的!