上篇文章讲解了在Git中如何进行版本切换,一共介绍了三种切换方式,其中以基于索引值的方式使用最为方便,也推荐大家切换版本就用这种方式。
那么本篇文章将为大家讲解删除文件的找回、分支的概念及其操作等。
如何找回被删除的文件
在日常开发中难免会出现一些"手贱"的操作,当你不小心删除了一个文件后,该如何找回它呢?
我们先把Crawler项目的版本切换到最新状态:
切换完成后,我们在项目中新创建一个文件:delete.txt。
创建好后,我们先提交一次,执行指令:
git add delete.txt
git commit -m "第四次提交,添加了delete.txt文件" delete.txt
提交完成后,我们把delete.txt文件删除掉,然后查看一下状态:
rm delete.txt
git status
用什么方式删除都可以,这里我就采用了Linux的一个删除指令:rm。
当执行git status指令时,终端提示发现了一个删除了的文件,我们再将这次操作提交一下:
git add delete.txt
git commit -m "删除了delete.txt文件" delete.txt
这样当我们把删除文件的这一操作提交之后,Git便会记录这次提交,所以只要Git记录了,我们怎么删除其实都不要紧,那么如何找回文件相信大家已经懂了吧?只需退回到删除文件之前的一个版本就可以了,执行指令:
git reflog
查看一下版本的索引值:
我们要回退到红色框线标注的版本,执行指令:
git reset --hard 29b009f
回退完成后,我们查看一下工作区:
被删除的文件又回来了。
还有一种情况:你删除了一个文件,并已经将其添加到了缓存区,但并没有提交,这时候你可以执行如下指令找回文件:
git reset --hard HEAD
这行指令如何理解呢?
通过前面的学习我们知道,hard参数会修改版本区的HEAD指针,同时会重置索引和工作区内容,HEAD指针目前指向的是最新版本,也就是没有去删除文件的版本,此时使用hard参数刷新版本区、索引、工作区,就会让它们都回到HEAD指针所指也就是当前的版本,这样被删除的文件就恢复了。
综上所述:要想找回删除文件有一个前提,就是该文件存在时的状态一定是已经保存在了本地库,否则你就找不回来了。
找回删除文件分为两种情况:
- 删除文件已经提交到了本地库:此时使用
git reset --hard [版本索引值]
指令回退到删除文件前的版本即可 - 删除文件添加到了暂存区,但还未进行提交:此时使用
git reset --hard HEAD
刷新一下三大区即可
比较文件之间的差异
Git能够找出一个文件在修改前后的差异,举个例子,我们对Crawler项目中的test.txt做一个修改:
我在文件里新增了一段文本,执行指令:
git status
终端提示有文件被修改了,那么我如何得知该文件到底修改了什么内容呢?
它需要用到这条指令:
git diff
执行指令,结果如下:
注意红色框线的内容,其中绿色部分表示新增的内容,可以看到,我确实在文件中新增了一个空行和一段文本;而红色部分表示删除的内容,我明明没有删除内容,怎么还提示我删除了一行文本呢?
其实这跟Git的内部机制有关,Git是以行为单位进行文件的管理的,所以它相当于做了这样一个操作:它先将文本aaaaaaaaaaaaaaa
进行删除,然后再新增后面的文本,就出现了终端上显示的效果。
当我们将对文件进行修改的操作添加到暂存区后,再去比较:
git add test.txt
git diff test.txt
此时终端没有任何反应,说明没有产生文件差异,这也证明了git diff指令其实比较的是工作区与暂存区的文件差异。
当我们让工作区与本地库进行文件比较时,差异又显现出来了,执行指令:
git diff HEAD test.txt
这是因为暂存区的修改还没有提交到版本库。
它还可以与历史提交版本进行比较,只需要改变指针指向即可:
git diff HEAD^^ test.txt
也可以根据索引值进行比较:
git diff 05f2f17
需要注意的是,git diff指令可以不带文件名,若该指令不带文件名则比较的是项目下的所有文件;若带文件名,则指定文件进行比较。
Git分支概念
这是官网上的一段解释:
几乎所有的版本控制系统都以某种形式支持分支。 使用分支意味着你可以把你的工作从开发主线上分离开来,以免影响开发主线。 在很多版本控制系统中,这是一个略微低效的过程——常常需要完全创建一个源代码目录的副本。对于大项目来说,这样的过程会耗费很多时间。
既然很耗费时间,那分支的作用岂不是很小?
在大部分的版本控制系统中,想创建分支,对于一个大项目来说确实是非常困难的,但这些问题在Git中将不复存在,这也是Git为何能够制霸版本控制系统领域的一个重要原因。
Git 处理分支的方式可谓是难以置信的轻量,创建新分支这一操作几乎能在瞬间完成,并且在不同分支之间的切换操作也是一样便捷。 与许多其它版本控制系统不同,Git 鼓励在工作流程中频繁地使用分支与合并,哪怕一天之内进行许多次。
分支操作可谓是Git的灵魂,理解和精通这一特性,你便会意识到 Git 是如此的强大而又独特,并且从此真正改变你的开发方式。
举个很简单的例子,某开发团队准备开发一个项目,在开发之前,肯定要先对项目进行分析,比如他们要开发的是一款社交软件,那社交软件就涉及到界面、聊天、支付等等功能,这时候首先由团队里技术最好的开发人员搭建出项目结构,并将其作为远程库供其它人员下载。
其它开发人员下载好后,一般不会在原来的程序上进行开发,因为后面的开发是未知的,难免会出现一些问题,我们应该保证让这些问题不要搞到之前写好的代码上去,这样每个开发人员对应着自己的工作内容创建一个分支,如图:
然后每个开发人员都专心做着自己的事情,他们之间互不影响,经过不断的开发测试后,若分支上的功能已经完善并没有问题,我们就可以将其合并到主干上:
通过图解,大家应该也能感受到分支开发的高效性和安全性。
分支操作
理解了分支以后,我们来看看在Git中如何操作分支。
可以通过该指令查看项目中的所有分支:
git branch -v
目前项目中只有一个master分支,master分支称为主干、主分支,是在初始化仓库的时候自动创建的。
我们可以通过该指令创建一条分支:
git branch ui
创建好再查看一下分支情况:
现在项目中就有两条分支了,其中*
符表示目前所在的分支。
有了分支,该如何切换到新分支呢?执行指令:
git checkout ui
切换成功后,再看一下分支情况:
此时*
符指向了ui分支。
下面就可以在ui分支进行相关的开发了,比如我在项目中创建一个ui.txt文件:
然后把该操作提交一下,提交操作我相信大家已经很熟练了,这些比较基本的指令我就不写出来了,直接贴出执行结果:
假设这个时候ui分支的开发已经完成了,现在我想将它合并到主分支上,该如何实现呢?
要想将该分支合并到主分支上,我们首先要回到主分支,执行指令:
git checkout master
回到主分支后,我们查看一下工作区:
刚刚创建的ui.txt文件不见了,当然了,该文件是在ui分支创建的,前面已经说了,分支之间互不影响,但若想合并ui分支的内容,我们只需执行如下指令:
git merge ui
再次查看工作区:
合并就成功了。
解决合并冲突
刚刚学习了如何合并分支,但合并分支并没有想象的那么简单,有时候合并分支会产生一些冲突,为什么会出现冲突,原因很简单。
当两个开发人员在两个不同的分支修改了同一个文件中的同一个地方,此时Git无法选择到底应该用谁的,它就会以冲突的形式将问题抛给我们,让我们自己去解决。
举个例子,我们先把分支切换到ui分支:
git checkout ui
然后我们修改一下工作区的ui.txt文件:
把操作提交一下:
再切换到master分支,在同一个文件的同一个地方进行修改:
git ckeckout master
同样提交一下:
下面开始合并,执行指令:
git merge ui
注意几个地方,提示信息是说自动合并失败,需要手动解决冲突然后提交。
然后看红色框线标注的地方,master|MERGING
,英语中的ing表示进行时,意思是master分支目前正在合并中。
我们打开工作区的ui.txt文件:
可以看到,文件中显示了两个分支修改的内容,并以一些特殊标记进行分隔,其中的<<<<<<<HEAD
表示当前分支修改的内容;而>>>>>>>ui
表示ui分支修改的内容,中间用=======
分隔。
此时你可以进行取舍,想要哪一段就删除另外一段即可,当然你也可以全留下,这里我就留下当前分支修改的内容吧:
记得把分隔符号也删掉。
查看一下状态:
git status
终端提示你有未合并的路径,可以使用git add将指定文件标记为冲突已解决。
下面我们就尝试一下,执行指令:
git add ui.txt
再次查看状态:
此时终端提示所有的冲突已经被解决了,但你仍然处于合并的状态,你可以使用git commit来完成合并,执行指令:
git commit -m "ui.txt冲突已解决"
这里注意了,git commit指令后面千万不要加文件名,否则就会出错,执行该指令后:
合并就完成了。