目录
一,预备
1.1 Git 介绍
1.2 Git 下载安装
二,Git基本操作
2.1 创建并配置本地仓库
2.2 工作区、暂存区、版本库
2.3 添加文件
2.4 修改文件
2.5 版本回退
2.6 撤销修改
2.7 删除文件
三,分支管理
3.1 关于分支
3.2 分支操作
3.3 删除分支
3.4 合并冲突
3.5 分支模式
3.6 分支策略
3.7 bug分支
3.8 强制删除分支
一,预备
1.1 Git 介绍
相信各位都有了解这个场景:老板要你写一个技术文档,你提交了第一版,老板说有瑕疵需要修改,然后提交了第二版,接着是第三版、第四版等等,之后当你提交到第十版时,老板突然说“还是用第一版吧!”。
这种时候我们如果是针对第一版的本身进行后面版本的修改,这种时候我们就没办法把第十版恢复成第一版了,所以我们一般会将前置版本进行一个复制,直接修改复制后的文档作为最新的版本。
但是一个公司不止一个员工,每个员工也不止一个老板,所以当版本一多,维护这些版本也就变的相当困难,比如每个版本修改的具体内容、时间等等,所以版本控制器就诞生了。
版本控制器:作用是记录每次版本的修改以及版本迭代的一个管理系统。Git 就是目前最主流的版本控制器。对于开发人员来说,Git控制的就是项目中的源代码文档。
注意事项:对于Git记录每次修改的内容,只针对 .txt、网页html以及各种源程序代码这种文本形式的文件,但对于图片,音频视频这种抽象的二进制文件,无法准确追踪具体的修改内容。
1.2 Git 下载安装
①Centos安装
很简单,执行下面命令即可:
sudo yum -y install git //下载安装Gitgit --version //查看Git版本②Ubuntu安装(以 Release 22.04为参考)
部分云服务器有时候会内置Git,可以先直接在命令行输入git看输出结果,下面是有Git 的结果:
如果没有git则输入下面指令安装:
sudo apt-get install git -ygit --version顺便一提,下面的命令可以快速查看Ubuntu版本号:
lsb_release -a③Windows安装
可以参考视频:3.安装git和图形化界面工具_哔哩哔哩_bilibili
建议:可以先参考视频在Windows本地完成Git的安装,然后和视频里一样至少完成一次代码的add、commit和push提交,对Git的理解和学习有很大帮助!
二,Git基本操作
2.1 创建并配置本地仓库
只要有权限,Git是可以控制电脑上的额所有格式的文件的,但是如果Git直接对电脑上的文件进行管理,肯定不行,所以我们必须要把需要管理的文件放在Git的仓库中进行管理
首先是创建本地仓库:
git init一个本地仓库创建出来还不能直接用,需要先新增两个配置项:用户名称name、用户email地址:
git config user.name "名称填在这里" git config user.email "同上" git config -l如果需要删除配置项需要使用命令:
git config --unset user.name git config --unset user.email添加或删除配置还有一个--global可选选项,这表示这台机器上所有的Git仓库都会用这个配置:
git config [--global] user.name "" git config [--global] user.email "" git config [--global] --unset user.name git config [--global] --unset user.email2.2 工作区、暂存区、版本库
我们先在这个目录下touch 一个 ReadMe.txt 文件作为被管理文件让git来管理,但是仅仅在该目录下touch一个文件,这个文件还不能被Git管理,因为这个目录还不是本地仓库,真正的本地仓库其实是 .git 文件,也叫做版本库。(当然也不能直接进入 .git 目录进行操作)
①工作区
我们把 ReadMe.txt 写在我们这个目录下,这个目录就称为“工作区”。
对工作区的操作有三种:
- 添加文件,也就是touch也算是对工作区的修改
- 修改文件,文件数量名称不变,文件内容改变也算修改了工作区
- 删除文件
当完成上面的操作之后,我们就将工作区 add 进暂存区(stage)中
②暂存区
暂存区也可以叫索引,存在于 .git 目录里,但是放进暂存区里还不算将工作区内容真正写入版本库里,还需要通过一个 commit 操作将暂存区操作提交到 master 分支下,这个后面再详细介绍
③版本库
前面已经介绍过, .git 文件就是版本库,不过这个版本库不单单只是一个“ 库 ”,里面还有很多用于git操作的可执行文件等等,使用 tree 命令可以查看
④附加:object 对象库
对象库也存在于版本库中,作用是用于保存对工作区的修改内容,比如我添加了一个文件、修改了一个文件,这些操作都会额外维护到这个对象库里,里面有很多git对象,每个对象都存储着对工作区的修改。每当工作区 add 一次,都会额外添加一个 git 对象放到这个对象库里。
所以前面说暂存区也可以叫做索引,也是因为暂存区存的也不是工作区文件的一比一复制,而是一个个的指针,指向对象库中每次add对应的git对象
2.3 添加文件
①一次完整的提交
使用命令如下:
git add file //支持多个文件,文件名之间用空格分开 git add . //一次提交所有文件 git commit -m "输入自定义提交备注" //将暂存区文件全部提交进版本库然后可以通过下面命令打印提交记录:
git log不过如果提交次数过多,也可以加个参数让时间由早到晚顺序不变打印记录:
git log --pretty=oneline②查看 .git 文件
当进行一次提交后,再 tree .git 可以发现确实多了很多东西(由于很大就不截图了,只展示部分)
其中多了add前没有的index文件:
并且如果打印HEAD文件,可以发现确实是指向了master文件:
前面也说了,index和master里面也并不是存的原原本本的文件,而是针对这些文件修改内容的索引,为当前最近一次提交的提交ID,然后我们可以用下面命令来查看详细信息:
git cat-file -p 对象库id①观察这个id,可以发现这个id的前2个字符对应 .git 目录里objects目录的一个子目录,然后后面的字符对应文件名,通过命令查看这个id可以查找到最近一次提交的信息
②与上面一样,里面的id也可以找到对应的文件,比如图片里查找绿色标记id就找到了我们提交的三个文件
③每个提交的文件也有对应的id,查找这个id就可以查看该文件内容,如图
2.4 修改文件
Git可以追踪管理文件,但Git管理的并不是文件本身,而是对文件的修改操作,下面命令可以查看目前仓库的状态,也就查看上一次提交到该命令执行时,是否对文件进行过修改:
git status由于代码不断增多,我们是没办法自己准确记得针对哪些文件的哪些修改的,所以git也提供了部分命令,让我们可以查看暂存区和工作区的差异,或者版本库和工作区的差异:
git diff 文件名 //查看工作区与暂存区差异 git diff READ -- 文件名 //查看工作区与版本库差异当修改后,也需要通过添加文件的add和commit命令分别添加进暂存区和版本库才能完成修改同步
2.5 版本回退
Git可以控制版本,当前版本出现问题需要回退到以前版本,Git肯定也能回退版本,本质是回退版本库的内容
git reset [--soft | --mixed | --hard] [HEAD]- --soft:这个参数表示该回退操作不影响工作区和暂存区内容,只修改版本库内容
- --mixed:为默认项,表示不影响工作区内容,对暂存区和版本库内容进行回退,常用于需要重写修改备注情况
- --hard:将三个区的内容全部回退,不过由于会覆盖掉工作区内容导致未add的代码消失,所以该参数需要慎用
- HEAD:指定需要回退的commit id
下面是hard的演示:
如果我后悔了,想回退回退怎么办呢?同样也可以通过commit id 回退回退:
但是我们屏幕是有限的,commit id又很长,一旦显示的内容过多可能我们就没法找到以前查看的commit id了,所以我们可以通过下面命令查看历史的git命令,效果类似命令行的history命令:
git reflog由于我们的回退操作只是更改了HEAD指针指向的commit对象内容,所以回退操作的执行速度很快
2.6 撤销修改
有下面三种情况,我们一一讲解:
①我在工作区写了代码还没add
- 也就是想让代码恢复到上一个版本,我们可以直接手动删除新加的代码,但是这样肯定不现实,一来浪费时间,二来可能会误删正确代码导致bug
- 虽然我们可以通过git diff 区对比差异然后删,但是也非常浪费时间
- 同时不建议使用 git reset --hard 强制回退,因为我们也可能多次add进了暂存区但是还没有commit,也会导致代码丢失
所以我们可以使用下面命令让工作区文件回到最近一次add 或 commit 的状态:
git checkout -- [file]②已经add了但还没有commit
这种情况下是工作区内容和暂存区内容同步了,所以不能再使用 git checkout 回退,所以我们得:
- 先使用git reset --mixed 让暂存区和版本库同步,由于 --mixed 是默认项可以省略
- 然后再使用 checkou 回退,同第一种情况
③已经add了,并且也 commit 了
这种情况我们只能通过 2.5 版本回退介绍的使用 git reset --hard HEAD 回退到上一个版本了,不过只限于把我们本地的版本库同步到远程,后面章节会介绍
附加:关于git reset 的HEAD参数,再回退情况下,这个参数可以不原原本本复制前面版本的那一大串字符串,比如:
- HEAD 表示当前版本
- HEAD^:上一个版本
- HEAD^^:上上一个版本
也可以用 ~数字 表示:
- HEAD~0:表示当前版本
- HEAD~1:表示上一个版本
- HEAD~2:上上一个版本
2.7 删除文件
我们有两种方法
方法一
方法二:可以将上面三步缩短为两步
git rm filename三,分支管理
3.1 关于分支
前面我们说过,./git 目录里面有一个 HEAD 文件,里面保存了master,而这个master里面保存的是对于最近一次提交的git对象指针
- 我们每一次提交都可以看作一个分支,有了master指针,我们就可以通过它找到我们的每一次提交
- 不是说master指针指向的是最新的提交吗,前面的提交怎么拿到呢?如下图
3.2 分支操作
①创建分支
首先是查看我们本地的分支:
git branch我们前面说HEAD指向的是master指针,现在可以改正说法了,HEAD 指向的是master分支,这也代表着其实HEAD也可以指向其它的分支,HEAD指向的分支就是我们目前的工作分支
创建分支就是在查看分支命令基础上在后面加上名字即可:
git branch dyk可以看到我们创建的 dyk 分支里面也存了一个提交id,和master一样,因为创建分支时,默认会也会填充最近的一次提交id
②切换分支
前面我们撤销修改命令里面有两个横杠,现在把两个横杠去掉,就变成了切换分支命令啦:
git checkout dyk此时 * 位置改变了,并且颜色也改变了,谁是目前的工作分支一目了然
③查看分支差异
我们先在dyk分支上提交修改:
然后切换回master分支:
这是因为:
④合并分支
最后就是将我们的master分支和dyk分支合并,让其它分支的修改同步到master分支上
git merge dyk此时master的指针也指向了dyk指向的提交id了
3.3 删除分支
删除分支用到的命令为:
git branch -d dyk注意:如果处于某个分支下再删除这个分支会报错
3.4 合并冲突
问题:什么是合并冲突?
解答:简单来说就是在master分支对ReadMe文件做了修改,然后同时在dyk分支上也对ReadMe文件做了修改,这时我们再去尝试合并的话,git 就不知道应该保留哪一个分支的结果了,这个问题和多线程安全问题很类似
我们先创建切换一个分支:
然后在dyk上对ReadMe进行修改:
然后切换回master分支,再进行修改:
此时再尝试合并会报错,并会修改ReadMe文件显示冲突内容:
此时我们需要我们开发人员自己来解决,觉得需要保留哪个代码,此时我们在master分支下删掉冲突内容,并再次commit提交(一定要重新提交)即可:
附加,如何更直观看到分支合并的情况呢?使用git log 命令的参数即可:
git log --graph --pretty=oneline --abbrev-commit可以看到完整的分支线内容,包括历史提交
3.5 分支模式
我们再创建一个分支然后对ReadM文件修改并提交:
然后我们再切回master并合并:
再打印日志:
这时候可以发现,我们打印的日志显示,此次提交不显示具体的提交信息,就是无法知道这次提交是正常commit提交的还是用merge合并出来的,会丢失部分分支信息
而在上面的合并冲突场景下,我们明显能看到屏幕坐标有两条岔开后又合并的线,这是因为那种场景下就不是 Fast-forward 模式了,所以能看到合并的信息
所以 Git 鼓励我们禁用 Fast-forward 模式,在 merge 命令添加参数即可:
git merge --no-ff -m "日志写这里" dyk1然后切换回master分支,不使用 Fast-forward 模式进行合并:
此时再打印日志就会显示合并信息了:
通过日志可以看到,禁用 Fast-forward 模式就是在master分支上重新生成了一次commit提交,然后一并将 dyk 分支也同步到这个master提交上来了
3.6 分支策略
在实际开发场景中,我们写的代码肯定是要经过层层测试和验证,最终达到要求才能放生产环境里去的,而对于Git来说,我们上面的master分支就是生产环境,其它的分支就是开发和测试环境。
所以分支策略就是指现在其它分支上写代码,最后经过层层测试,再把分支 上的代码合并到master分支上作为发布版本。
注意:我们的分支不一定只能和master分支合并,分支与分支之间也可以进行合并,就好比一家公司下有很多部门,每个部门下也有很多小组一样,类似多叉树。
3.7 bug分支
我们使用程序或者app时,或多或少都会遇到过闪退卡死等等情况,因为我们的生产环境线上环境也不是100%稳定的,也就是master分支也可能会有bug;这种情况的解决办法一般是临时创建一个新的分支专门来修复bug。然后合并分支最后删除或备份临时分支。
不过这样合并分支的操作我们前面已经做过很多次了,这个小章节主要是了解一下另一种场景,下面我们就来模拟一下简单场景
我们在一个分支进行了部分代码开发,还没有提交,这时候master中有了bug
先创建dyk2分支:
此时还未提交,切回master的话会发现:
这时候我们不想让dyk2的修改影响master,需要使用另一个命令:
git stash //表示将工作区内容进行保存保存到哪里了呢?保存在了.git 目录下:
不过需要注意的是,只有被Git管理追踪的文件才能进行保存操作,比如我直接在目录下touch一个file3文件,不进行任何操作直接git stash的话不会被存储
然后我们新建一个专门修复bug的分支:
然后就是正常的合并操作了,我们在这个分支里完成对ReadMe文件的修改,然后和master合并,然后删除这个分支:
bug搞定之后我们还得接着回dyk2分支去开发:
开发完成之后我们提交:
不过此时因为对master分支bug的修改没有同步到dyk2上,同时dyk2上新开发的代码也没有同步到master分支上,这个时候如果master分支和dyk2合并很大可能会出现冲突,但如果我们去手动解决冲突的话也有很大可能产生新的bug。
但是我们的目的是保证master的稳定性,所以我们可以反过来先让master和我们的分支去合并,直接在我们自己的分支上做出修改,让合并冲突的问题在dyk2分支上进行修改,确认无误后再与主master合并即可。
然后就是在dyk2上完成修改并提交:
最后切回master合并就可以了
最后可以选择删除 fix_bug分支,不过有些公司可能会要求备份:
3.8 强制删除分支
开发过程中有很多新功能会被加入进来,同样的也肯定会有新功能被移除,那么假如我正在开发一个新功能,然后这个功能被砍了,我不得已只能删除这个分支
但如果我们在这个分支开发了一些内容,并且也commit提交了,使用git branch -d 命令删除的话会报错:
然后切回master分支然后删除dyk2分支:
然后后面还给了我们一个提示说如果我们确认要删除这个,需要运行这个命令,其实就是把小写d改成了大写D: