本篇文章,是基于我自用Linux系统中的自定义文件夹“test_rep”,当做示例演示
具体Git仓库的目录在:/usr/local/git/test_rep
Git的管理修改与撤销修改
在讲这个之前,还是有必要再阐述一下“工作区和暂存区”。Git 和其它版本控制系统如 SVN 的一个不同之处就是有暂存区的概念。
工作区(Working Directory)
就是你在电脑里能看到的目录,比如我自己的测试 Git仓库目录/usr/local/git/test_rep
文件夹就是一个工作区:
以上,是我本机测试的 Git 工作区,有两个用于测试的文件。
版本库(Repository)
工作区有一个隐藏目录.git
,这个不算工作区,而是 Git 的版本库。Linux 系统下可以通过 ls -ah
命令就可以看见,其它操作系统想看见它就比较简单了。
Git 的版本库里存了很多东西,其中最重要的就是称为 stage(或者叫 index)的暂存区,还有 Git 为我们自动创建的第一个分支master
,以及指向master
的一个指针叫HEAD
。
分支和HEAD
的概念这里就先不去探讨了。
我们都知道,把文件往 Git 版本库里添加的时候,是分两步执行的:
- 第一步是用
git add
把文件添加进去,实际上就是把文件修改添加到暂存区; - 第二步是用
git commit
提交更改,实际上就是把暂存区的所有内容提交到当前分支。
因为我们创建 Git 版本库时,Git 自动为我们创建了唯一一个master
分支,所以,git commit
就是往master
分支上提交更改。可以粗浅的理解为,需要提交的文件修改都放到暂存区,然后一次性提交暂存区的所有修改。
我们可以通过操作演示一下:
#查看read.txt文件的内容
$ cat read.txt
Git is a version control system.
Git is free software.
#上述内容,read.txt文件一共有两行文本而已
#针对read.txt文件追加一行数据
$ vim read.txt
Git is a version control system.
Git is free software.
Git OK. #追加一行新的文本
#wq保存read.txt
#再在/usr/local/git/test_rep中创建追加一个新文件work
$ touch work
#此时查看一下查看仓库当前的状态
$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: read.txt
Untracked files:
(use "git add <file>..." to include in what will be committed)
work
no changes added to commit (use "git add" and/or "git commit -a")
Git 非常清楚地告诉我们,read.txt
被修改了,而work
还从来没有被添加过,所以它的状态是Untracked
。
现在,使用两次命令git add
,把read.txt
和work
都添加后,用git status
再查看一下:
$ git add read.txt
$ git add work
#没执行commit操作
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: work
modified: read.txt
通过上面可知,暂存区现在已经通过刚才git add
操作,增加了两个文件,分别是read.txt
和work
。所以,git add
命令实际上就是把要提交的所有修改放到暂存区(Stage),然后,执行git commit
就可以一次性把暂存区的所有修改提交到分支。
如果再提交:
#提交
$ git commit -m '测试操作'
[master fd63112] 测试操作
2 files changed, 1 insertion(+)
create mode 100644 work
#查看仓库状态
$ git status
On branch master
nothing to commit, working tree clean
一旦提交后,如果你又没有对工作区做任何修改,那么工作区就是“干净”的。因为此时,暂存区的修改已经提交到版本库中了。
所以,Git 的暂存区是一个区别与其它版本控制系统的不同的地方。
修改的管理
什么是修改?比如你新增了一行,这就是一个修改,删除了一行,也是一个修改,更改了某些字符,也是一个修改,删了一些又加了一些,也是一个修改,甚至创建一个新文件,也算一个修改。
所以我们说,Git 管理的是修改,并不是文件。下面我们再操作一下:
#先查看一下read.txt文件
$ cat read.txt
Git is a version control system.
Git is free software.
Git OK.
#追加一行内容
$ vim read.txt
Git is a version control system.
Git is free software.
Git OK.
Git very OK. #新追加的一行文本
#添加
$ git add read.txt
#查看仓库状态
$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: read.txt
#再对read.txt文件做个修改
$ vim read.txt
Git is a version control system.
Git is free software.
Git OK.
Git very OK,Good. #此处修改了一下
#wq保存read.txt
#此时我没有再次git add read.txt,而是直接git commit了
$ git commit -m '测试管理'
[master e8dba17] 测试管理
1 file changed, 1 insertion(+)
#提交后,再看看仓库状态
$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: read.txt
no changes added to commit (use "git add" and/or "git commit -a")
通过上面的操作,你会发现第二次的修改没有被提交。没错,按照 Git 的基本操作要求,只有执行了git add
命令才会把修改被放入暂存区,git commit
命令才会把暂存区的的修改提交到版本库中。很明显,刚才我们的操作,第二次并没有执行git add
命令,所以第二次修改并没有放入暂存区。
既然刚才我们已经最后提交了,用git diff HEAD -- read.txt
命令可以查看工作区和版本库里面最新版本的区别:
$ git diff HEAD -- read.txt
diff --git a/read.txt b/read.txt
index 4b9a082..1773e22 100644 #此处index您肯定和我不一样
--- a/read.txt
+++ b/read.txt
@@ -1,4 +1,4 @@
Git is a version control system.
Git is free software.
Git OK.
-Git very OK.
+Git very OK,Good.
可见,第二次修改确实没有被提交。
那怎么提交第二次修改呢?你可以继续git add
再git commit
,也可以别着急提交第一次修改,先git add
第二次修改,再git commit
,就相当于把两次修改合并后一块提交了:
第一次修改 -> git add
-> 第二次修改 -> git add
-> git commit
好,现在,把第二次修改提交了,以此类推。
通过上面可以看出,Git 管理的并不是什么文件的事,管理的是修改,不管是何种形式的修改。
撤销的修改
接着上面的继续聊,前提那两次修改都已经git add
并git commit
了。
#查看一下现在read.txt的内容,前提所有的修改都add并commit了
$ cat read.txt
Git is a version control system.
Git is free software.
Git OK.
Git very OK,Good.
#我们对read.txt进行修改操作
$ vim read.txt
Git is a version control system.
Git is free software.
Git OK.
Git very OK,Good.
Git is Cool. #这是新增加了一行文本
#wq保存read.txt
增加了那个文本合适不合适我们不去讨论,假设增加的这行文本并不太合适(此时还没有git add
文件),于是你完全可以恢复到之前那个版本状态,如下:
#之前并没有git add文件
#此时查看仓库状态
$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: read.txt
no changes added to commit (use "git add" and/or "git commit -a")
你可以发现,Git会告诉你,git restore <file>
可以放弃工作区的修改:
$ git restore read.txt #执行完并没有信息输出
#查看仓库状态
$ git status
On branch master
nothing to commit, working tree clean
#查看一下read.txt的内容
$ cat read.txt
Git is a version control system.
Git is free software.
Git OK.
Git very OK,Good.
文件内容果然复原了。
好,我们继续再尝试一下:
#查看一下read.txt的内容
$ cat read.txt
Git is a version control system.
Git is free software.
Git OK.
Git very OK,Good.
#继续对read.txt进行修改操作
$ vim read.txt
Git is a version control system.
Git is free software.
Git OK.
Git very OK,Good.
Git is very Cool. #这是新增加了一行文本
#wq保存read.txt
#此时修改完read.txt文件后,直接git add
$ git add
这次操作,在read.txt
文件中追加了一行新的文本Git is very Cool.
,然后就直接git add
提交到暂存区了。但是此时,我还是觉得不太合适(此时已经git add
文件了),于是:
#之前已经进行了git add文件
#此时查看仓库状态
$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: read.txt
Git 同样告诉我们,用命令git restore --staged <file>
可以把暂存区的修改撤销掉(unstage),重新放回工作区:
$ git restore --staged read.txt #执行完并没有信息输出
#查看仓库状态
$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: read.txt
no changes added to commit (use "git add" and/or "git commit -a")
你会发现,刚才执行了git restore --staged read.txt
之后,再查看仓库状态,这时和之前我们的操作一样了。其实就是通过执行git restore --staged read.txt
这个命令,我们把已经git add
到暂存区的修改撤销丢弃了,现在仅剩下工作区有修改,所以再次告诉我们通过执行git restore <file>
可以放弃工作区的修改:
$ git restore read.txt #执行完并没有信息输出
#查看仓库状态
$ git status
On branch master
nothing to commit, working tree clean
#查看一下read.txt的内容
$ cat read.txt
Git is a version control system.
Git is free software.
Git OK.
Git very OK,Good.
整个世界终于清静了!
所以,此时有必要总结一下:
git restore 用法
- git restore --staged <file_name> 将暂存区的修改重新放回工作区(包括对文件自身的操作,如添加文件、删除文件)。
- git restore <file_name> 丢弃工作区的修改(不包括对文件自身的操作,如添加文件、删除文件)。
restore 与 reset 的不同
- restore 是拥有撤销,撤销到原始HEAD版本库。
- reset 是回退到某个版本,如果执行
git reset HEAD 文件
操作,其效果和git restore --staged 文件
是一个效果。
删除的操作
在 Git 中,删除也是一个修改操作,我们实战一下。
还记得博文开始的时候,我曾经新增过一个文件work
,如下图:
我们就拿它开刀:
#通常直接在文件管理器中把没用的文件删了,或者用rm命令删了
$ rm work
#执行上面命令会提示你,是否要删除掉这个文件的提示“rm: remove regular file 'xxx'?
#输入 y 告诉git执行删除
此时,Git 已经知道了你删除了文件,因此,工作区和版本库就不一致了:
#查看仓库状态
$ git status
On branch master
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
deleted: work
no changes added to commit (use "git add" and/or "git commit -a")
通过上面的提示,你会有两个操作选择,一是确实要从版本库中删除该文件,那就用命令git rm
删掉,并且git commit
:
$ git rm work
rm 'work'
$ git commit -m '移除work文件'
[master aa5d2d0] 移除work文件
1 file changed, 0 insertions(+), 0 deletions(-)
delete mode 100644 work
友情提示:此处git rm work
和git add work
,此时效果是一样的。之前执行了rm work
,再执行一下git rm work
代表通知 Git 移除文件。或者是git add work
更合理,我们说过,Git 管理的是修改,我们把work
文件删除了,就是做了修改操作,把做了修改的文件提交git add work
,更符合我们之前学的操作:先git add
操作,再git commit
提交。
第二个操作就是,觉得这文件删错了还没提交呢,通过git restore <file>
撤销删除操作:
$ git restore work
#或者直接
$ git checkout -- work #这个命令很好了解,直接版本库里的版本替换工作区的版本
从某种意义上理解,删除操作不用太担心,即使已经被提交到版本库,我们完全可以从版本库“一键还原”回来,前提是只能恢复文件的最新版本,期间文件的修改会丢失。
重命名
文件的重命名,很好理解,在 Git 中我们使用git mv
命令用于移动或重命名一个文件、目录或软连接:
$ git mv [file] [newfile]
如果新文件名已经存在,但还是要重命名它,可以使用 -f 参数:
$ git mv -f [file] [newfile]
例如我们一下操作:
$ git add README
然后对其重命名:
$ git mv README README.md