赞
踩
上篇文章带大家了解了Git的原理,仓库的创建和初始化等…
本篇继续带来Git的基本操作
正文开始!!!
.git
目录下的index文件(.git/index)中,我们把暂存区有时也叫作索引(index).repository
.工作区有一个隐藏目录.git
,他不算工作区,而是Git的版本库.这个版本库里面的所有文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以"还原";下面这个图展示了工作区、暂存区和版本库之间的关系:
git add
命令时,暂存区目录树的文件索引会被更新.git commit
时,master分支会做相应的更新,可以简单理解为暂存区的目录树才会被真正写到版本库中.由上述描述我们便能得知 : 通过新建或粘贴进目录的文件,并不能称之为想仓库中新增文件,而只是在工作区新增了文件.必须要通过使用git add
和git commit
命令才能将文件添加到仓库中进行管理!!!
在包含.git的目录下新建一个ReadMe文件,我们可以使用git add
命令可以将文件添加到暂存区:
git add [file1] [file2] ...
git add [dir]
git add .
git commit
命令将暂存区内容添加到本地仓库中:git commit -m 'message'
git commit [file1] [file2] ... -m 'message'
git commit
后面的-m
选项,要跟上描述本次提交的message,由用户自己完成,这部分内容绝对不能省略,并要好好描述,是用来记录你的提交细节,是给我们人看的.git commit
命令执行成功后会告诉我们,1个文件被改动(就是我们新添加的ReadMe文件),插入了两行内容(ReadMe有两行内容).我们还可以多次add不同的文件,而只commit一次便可以提交所有文件,是因为需要提交的文件时统统被add到暂存区中,然后一次性commit暂存区的所有修改.如:
截止目前为止,我们已经将代码直接提交至本地仓库了.我们可以使用git log
命令,来查看下历史提交记录:
该命令显示从最近到最远的提交日志,并且可以看到我们commit时的日志消息.
如果嫌输出信息太多,看的眼花缭乱的,可以试试加上--pretty=oneline
参数:
需要说明的是,我们看到的⼀⼤串类似1520a...5090
的是每次提交commit id (版本号),Git 的 commit id 不是1,2,3……递增的数字,⽽是⼀个 SHA1 计算出来的⼀个⾮常⼤的数字,⽤⼗六进制表⽰(你看到的 commit id 和我的肯定不⼀样)。
先来看看我的.git
的目录结构:
index
就是我们的暂存区,add后的内容都是添加到这里的.HEAD
就是我们的默认指向master分支的指针:
而默认的master分支,其实就是
打印的1520a7c0c770f2cbc8b6b2cbf2c92ca3061d5090
是什么东西呢?保存的就是当前最新的commit id
.
objcects
为Git的对象库,里面包含了创建的各种版本库对象及内容.当执行git add
命令时,暂存区的目录树被更新,同时工作区修改(或新增).git/objects
目录下,让我们来看看这些对象有何用处:commit id
分成2部分,其中前2位是文件夹名称,后38位是文件名称.找到这个文件之后,一般不能直接看到里面是什么,该文件是经过sha(安全哈希算法)
加密过的文件,好在我们可以使用git cat-file
命令来查看版本库对象的内容:
其中,还有一行f8031228be309590b053a6c5793724077977701d
,我们使用同样的方法,看看结果:
在看ReadMe对应的f54bdb11e712c170c3e8929858fa05f8aa33e9bb
:
这是我对ReadMe做的修改!!! 被git记录了下来!!!
总结一下,在本地的git仓库中,会有几个文件或者目录很特殊
git add
后会更新该内容.master
分支的最新commit id
.后面学习过程中,最好能将常见的git
操作与.git
目录当中的结构内容变化对应起来,这样有利于我们理解git细节流程.我们后面还会学习什么分支,标签什么的.
看到这里,我们已经清楚了如何向仓库中添加文件,并且对于工作区、暂存区、版本库也有了一定的认识.再展示一种添加文件的场景,继续加深对工作区、暂存区、版本库的理解,示例如下:
[huluwa@centos7 gitcode]$ touch file4 #1.新增file4文件
[huluwa@centos7 gitcode]$ git add file4 #2.将file4添加到暂存区
[huluwa@centos7 gitcode]$ touch file5 #3.新增file5文件
[huluwa@centos7 gitcode]$ git commit -m 'add file' #4.提交修改
[master a03d689] add file
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 file4
提交发现打印了 1 file changed, 0 insertions(+), 0 deletions(-)
,意思是只有一个文件改变了,这时提出了疑问,不是新增了两个文件吗?
再来回忆一下,git add
是将文件添加到暂存区,git commit
是将暂存区的内容添加到本地仓库中.由于我们并没有使用git add file5
,file5就不在暂存区中维护,所以我们commit的时候,其实只是把已经在暂存区的file4提交了,而遗漏了工作区的file5.如何提价file5呢?很简单,再次add
,commit
即可.
[huluwa@centos7 gitcode]$ git add file5 #5.将file5添加到暂存区
[huluwa@centos7 gitcode]$ git commit -m 'add file' #6.提交修改
[master d65d20b] add file
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 file5
Git比其他版本控制系统设计的优秀,因为Git跟踪并管理的是修改,而非文件.
什么是修改?比如你新增了一行,这就是一个修改,删除了一行,也是一个修改,更改了某些字符,也是一个修改,删除了一些,又加了一些,也是一个修改,甚至创建一个新文件,也算一个修改.
让我们将ReadMe文件进行一次修改:
此时,仓库中的ReadMe和我们工作区的ReadMe是不同的,如何查看当前仓库的状态呢?git status
命令用于查看在你上次提交之后是否对文件进行再次修改.
上面的结果告诉我们,ReadMe被修改过了,但是还没有完成添加与提交.
目前,我们只知道文件被修改了,如果能知道具体哪些地方被修改了,就更好了.
git diff [file]
命令用来显示暂存区和工作区文件的差异,显示的格式正式Unix通用的diff格式.也可以使用git diff HEAD -- [file]
命令来查看版本库和工作区文件的区别.
知道了对ReadMe做了什么修改后,再把它提交到本地仓库就放心多了.
git add
之后,就没有看到上面no changes added to commit (use "git add" and/or "git commmit -a")
的消息了.接下来让我们继续git commit
即可:
之前也提到过,Git能够管理文件的历史版本,这也是版本控制器重要的能力.如果有一天你发现之前的工作出现了很大的问题,需要在某个特定的版本重新开始,这个时候,就需要版本回退的功能了.
执行git reset
命令用于回退版本,可以指定退回某一次提交的版本.要解释一下"回退"本质是要将版本库中的内容进行回退,工作区或暂存区是否回退由命令参数决定:
git reset
命令语法格式为 : git reset [--soft | --mixed | --hard] [HEAD]
-mixed
为默认选项,使用时可以不用带该参数.该参数将暂存区的内容退回为指定提交版本内容,工作区文件保持不变.--soft
参数对于工作区和暂存区的内容都不变,只是将版本库回退到某个指定的版本.--hard
参数将暂存区与工作区都退回到指定版本.切记工作区有未提交的代码时不要用这个命令,因为工作区会回滚,你没提交的代码就再也找不回了,所以使用该参数之前一定要慎重.HEAD
说明:
add first file
的时候,应该怎么办呢?--hard
参数,实例如下ReadMe
文件的内容,已经回退到第一次提交的版本了!当前,我们再次用git log
查看一下提交日志,发现HEAD
只想了第一个版本,如上图所示.到这里一般的回退功能就演示完了,但现在如果我后悔了,想再回到最后一次版本怎么办呢?
我们可以继续使用git reset
命令,回退到最后一次的版本,但我们必须要拿到最后一次版本的commit id
去指定回退的版本.
但我们看到了git log
并不能打印出最后一次版本的commit id
,运气好的话我们可以从终端上去找找之前的记录,运气不好的话commit id
已经被我们搞丢了…
Git还提供了一个git reflog
命令能补救一下,该命令用来记录本地的每一次命令.
这样,你就可以很方便的找到你的所有操作记录了,但70e3e6e
是什么呢?这个是最后一次版本的commit id
的部分.没错,Git版本回退的时候,也可以使用部分commit id
来代表目标版本.示例如下:
可是往往理性很美丽,显示很残酷.在实际开发中,由于开发的时间长了,导致commit id
早就找不到了,可突然某一天,我又想回退到最后一次的版本,那该如何操作呢? 貌似现在是不可能了…
值得说的是,Git的版本回退速度非常快,因为Git在内部有个指向当前分支(此处是master)的HEAD指针,refs/heads/master
文件里保存当前master
分支的最新commit id
.当我们在回退版本的时候,Git仅仅是refs/heads/master
中存储一个特定的版本,可以简单理解成如下示意图:
如果我们在我们工作区谢了很长时间代码,越写越下不下去,觉得自己写的实在是垃圾,想回复大上一个版本.
你当然可以直接删掉你在工作区新增的代码,在这里我就不做演示了.
要是自己写了3天代码,一直都没有提交,该怎么删掉呢?你自己都忘了新增过那些?有人会说,我可以git diff xxx
一下,看看区别在哪里,那你肯定又要花时间去删除代码了,并且很大的概率还会改出bug.一周过去了,你怎么向你的老板交代呢?
Git其实还为我们提供了更好的方式,我们可以使用git checkout -- [filename]
命令让工作区的文件回到最近的一次add
或者commit
时的状态.要注意git checkout -- [filename]
命令中的--
很重要,切记不要省略,一旦省略,该命令就变为其他的意思了,后面我们再说.示例如下:
add后还是保存到了暂存区呢?如何撤销呢?
让我们来回忆一下学过的git reset
回退命令,该命令如果使用--mixed
参数,可以将暂存区的内容退回为指定的版本内容,但工作区的文件保持不变.那我们就可以退下暂存区的内容了!!!
示例如下 :
– mixed 是默认参数,使用时可以忽略
不要担心,我们可以git reset --hard HEAD^
回退到上一个版本!不过,这是有条件的,就是你还没有吧自己本地版本库推送到远程.还记得Git是分布式版本控制系统吗?我们后面会讲到远程版本库,一旦推送到远程版本库,就真的惨了…
在Git中,删除也是一个修改操作,我们实战一下,如果要删除file5
文件,怎么搞呢?如果你这样做了:
但是这样直接删除是没有用的,反而徒增烦恼,git status
会立刻告诉你哪些文件被删除了:
此时,工作区和版本库就不一致了,要删文件,目前除了要删工作区的文件,还要清除版本库的文件.
一般走到这里,有两种可能:
git
进行恢复,很简单,我们刚学过(删除也是修改) :git checkout -- [filename]
对于第一种情况,很明显是没有删除完,我们只删除了工作区的文件.这时就需要使用git rm
将文件从暂存区和工作区删除,并且commit
:
现在文件就从版本库中被删除了.
(本章完!)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。