
目录一预备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 --prettyoneline②查看 .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 --prettyoneline --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