序言
hello,大家好,好久不见,前段时间学习了一下git,于是乎有了今天这篇文章,可能对于学生来说git所占的分量没有编码那么足,但对于即将工作的我来说,git还是很重要的,在今后的工作中是离不开git的,下面我们就一起来学习一下吧。
git是什么
git是一款分布式的版本管理工具
-
那什么是版本管理工具呢?
顾名思义版本管理工具,就是用来管理我们的版本的,每个学生都会经历论文答辩这么一个环节,当然百分之99的学生的论文都是需要经过一次次的修改最终才能定型的,那么这一次次的修改对应的论文,就可以看作是一次次的版本迭代,git可以很方便的对版本进行一个管理。 -
那么什么是分布式呢?
我们都知道版本管理工具除了git外,还有svn,svn是集中式的版本管理工具,它统一有一个中心仓库,所有的计算机都会连接这个中心仓库进行文件的交互。
svn架构如下图所示
我们可以看到在svn中所有的计算机都是和一个中心仓库做交互的,一旦中心仓库发生了意外宕机,所有的工作可能需要等待中心仓库恢复好之后再继续了。
于是乎有了git,git的分布式体现在,除远程仓库外,每台计算机也都配备了本地仓库,可以说我们是先和本地仓库交互,再由本地仓库和远程仓库做交互,就算远程仓库发生了意外宕机,我们也可以现将文件存放到本地仓库,等远程仓库恢复后再将内容同步
git架构如下图所示
git本地仓库和远程仓库
刚才提到了git有本地仓库和远程仓库的概念,那么我们先来看一下什么是本地仓库和远程仓库吧。
- 本地仓库:
本地仓库就是存放在本机中的仓库,每台计算机都有本地仓库,本地仓库又可以细分为三个概念,分别是工作区,暂存区和本地库。
①:工作区,带.git文件的文件夹就可以看做是一个工作区,也可以将写代码的地方看成工作区。
②:暂存区,它是一个隐式的概念,工作区中的文件会添加到暂存区。
③:本地库,本地库就是本地仓库中用于存放文件和版本管理的地方,暂存区会将文件提交到本地库当中。
- 远程仓库:
对于一个团队来说,他们每个成员都有自己的本地库,那他们之间怎么进行通信交互呢?就是通过我们的远程仓库来通信交互的(A将文件推送到远程仓库,B可以从远程仓库上将A推送的文件拉取下来),大名鼎鼎的github就是一个远程仓库,我们中国的gitee码云也是一个远程仓库,企业中用的更多的其实是一个被称为gitlab的远程仓库。
本地仓库的常见操作
①:我们需要先初始化工作区,执行git init命令将当前所在目录初始化为git的工作区。
②:设置签名(我们需要先设置好我们的签名,用于标识操作人)
- 项目签名的设置:git config user.name <用户名>:设置用户名, git config user.email<邮箱>:设置邮箱号
- 系统签名的设置:git config --global user.name <用户名>:设置用户名,git config --global user.email<邮箱>:设置邮箱号
系统签名的作用域是整台电脑,设置一次处处生效,项目签名的作用域为当前的工作区,仅在当前工作区有效。(项目签名优先级大于系统签名,如果两者都存在则以项目签名为准)
③:添加文件,执行git add <文件名>将文件添加到暂存区当中。
添加到暂存区的文件,是可以进行撤回的,git restore --staged <文件名>即可撤回
④:提交文件,执行git commit -m “备注信息” <文件名>将文件从暂存区中提交到本地库。
本地仓库中版本的前进/后退
对于本地仓库而言,每一次提交的成功执行,就意味着一个新版本的生成,git会将这些版本给保存起来。
首先我们需要查看版本详细信息,通过git reflog 命令可以查看到所有版本的信息。第一列它会显示一个索引号,这个索引号其实是一个hash值,每个版本都会对应一个hash值,我们可以通过这个hash来进行版本的切换。
- git reset --hard 索引号:来切换到指定的版本
删除文件的恢复
windows中我们可以把删除掉的文件从回收站中恢复,同样的git也可以支持文件的恢复操作,不过有个前提是想要恢复的文件必须之前已经提交到了本地库当中。
-
git reset --hard 索引号:跳转到文件删除前的版本
-
git restore 文件名:撤销这次删除操作
分支
分支也是十分重要的一个概念,我们可以看到在git的命令窗格中默认会显示master,master就是我们的主分支,当然我们可以创建其它分支,创建出的分支和主分支是一模一样的,可以看做是克隆了一份出来,但分支有很多好处。
多个分支之间相互独立,互不影响,特别有利于团队开发,每个成员开发一个分支,开发完成后合并到主分支即可。
- git branch <分支名>:创建分支
- git branch -v:查看所有的分支
- git checkout <分支名>:切换分支
- git checkout -b <分支名>:创建并切换到新的分支
- git branch -D <分支名>:删除分支
- git merge <分支名>:合并目标分支
分支冲突
- 产生原因:
现在有AB两个分支,他俩同时对同一个文件进行了修改,这时A分支要将B分支给合并起来,这就产生了冲突
- 解决方式:
解决方式很简单,我们只需要到冲突文件中,对内容做修改,然后将冲突文件add到暂存区,最后提交到本地库就可以了。(注意:提交时无需指定文件名)
本地仓库和远程仓库的交互
团队内合作
我们就拿github来当做远程仓库吧!
①:A先在github上创建好仓库,然后在自己本地创建好本地库
②:A将本地库中的文件根据https的形式推送到github上(推送一般有两种方式,一种是https的还有一种是ssh的,先拿https举例子,后续再说ssh的)
一般会创建两个分支,一个是存放线上版本的master分支,一个就是dev分支
- git push <https的地址> <本地库分支名>:推送本地库的文件到指定地址的远程库
一般而言https的url地址挺长的,不方便记忆,我们其实可以为这个url设置一个别名,今后操作别名就可以了。
- git remote add <别名> <原地址名>:创建别名
③:此时B就可以将github上A上传的文件克隆到本地了
- git clone <https的地址/别名>
④:B在本地基于dev分支,创建guo分支,可以对文件做修改/添加操作,然后commit到本地库
注意:此时,B是没有push到github的权限的,需要让A先将B添加到团队内才可以
⑤:A在github上将B添加到团队内,B就可以push新内容啦
⑥:这时A对于B新提交的guo分支,有两种合并方式
一:B在github上向A发出pullRequest请求指定将guo分支合并到dev分支,A同意后将guo分支合并到dev分支,最后在本地库拉取最新的代码
- git pull <别名> <远程库的分支>:拉取并覆盖新内容
pull命令=fetch+merge命令,fetch是将修改信息拉取到本地但不覆盖,merge是将旧内容与新内容进行合并,pull的话就是直接拉取新内容到本地并且直接合并覆盖掉。(ps:对于一些不确定的信息我们可以先fetch下来查看完毕没问题后,再merge起来)
二:A在本地创建并切换到guo分支,然后将远程库的guo分支pull下来,切换到dev合并guo分支,再推送到远程仓库。
针对于pull操作,pull下来的内容会覆盖掉本地库当前所在分支,因此对于A而言,他需要先创建出guo分支,然后执行pull操作。
⑦:此时新功能已经提交到dev分支了,但一般而言还是需要测试团队C,再对新功能进行测试,所以测试团队可以clone到本地。基于dev分支创建release分支,对内容进行测试。
测试通过后,就可以像之前一样,A pull release到本地,手动进行合并,将master最新内容push到远程,或者是C在github上发出pullRequest请求指定将release合并到master,合并成功后在本地pull最新的master。
⑧:此时算是一个新版本开发完毕,我们可以在本地创建Tag标签,然后提交到github形成新版本。
工作流程:
push推送冲突
- 产生原因:
A和B在协同开发时,同时对一个文件做了修改,在push到远程库的时候产生了冲突(类似于分支冲突) - 解决方式:
①:产生了冲突,先将github上的被修改文件给pull下来
②:还是在本地进行修改,然后add到暂存区,commit到本地库(不加文件名)
③:最后再push上去即可
跨团队合作
这个跨团队的意思就是,B不是A团队的员工,但是B也来协助A完成任务
①:A创建远程仓库,创建本地库,将文件都push到远程库上
②:由于B不是A团队内成员,他也就无法直接clone下来然后push了,因此B可以将github上的仓库fork一份出来
③:根据fork出来仓库的地址,clone到本地
④:在本地对文件进行操作,push到远程库
⑤:B在github向A发出PullRequests
⑥:A审核B发出的请求内容,同意后合并请求
⑦:A的本地库就可以将B请求的内容拉取下来了
工作流程:
本地库和远程库交互的方式
本地库和远程库一般有两种交互方式,分别是https和ssh。
- 两者的区别:
通过https和远程库交互,我们每次都需要输入远程仓库的账号密码。
通过ssh方式交互,我们不需要输入账号密码。
ps:不过现在我们用的windows系统中有一个记录凭证的功能,因此使用https的方式只需要输入一次账号密码即可。
https的使用方式较为简单,只要知道https对应的url即可,下面我们说一下ssh的使用方式。
SSH的使用方式
①:进入到~根目录
②:rm -rf.ssh
③:ssh -keygen -t rsa -C <github账号>:根据rsa非对称算法生成公钥,私钥
④:将公钥配置到github上,Settings->SSH and GPAKeys
⑤:使用方式和https的一样,只需要记住ssh对应的url即可和远程库做交互了。
进阶
rebase
rebase的功能就是让提交记录变简洁,它有三个功能
功能一:合并提交记录
通过git log我们可以查看近期提交记录,但有时这些提交记录对应的并不是一个完整的版本,我们可以把多个提交记录看成一个大版本,这时候rebase就可以合并提交记录了。
- 命令:git rebase -i HEAD~N(合并当前所在版本及其前N-1个版本)
功能二:让分支合并后的记录更简洁
在合并分支后,提交记录不够简洁,这时可以使用rebase来解决这个问题,在切换到主分支合并前,在从分支执行以下命令。
- 命令:git rebase <主分支名>
功能三:避免拉取时出现分叉记录
在从远程库pull代码下来时,有可能会在本地库的提交记录中出现分叉情况,可以使用rebase替代pull命令解决
- 命令:git fetch <远程库地址/别名> 远程分支名,git rebase <远程库地址/远程分支名>
beyond compare
beyondCompare是一个软件,它可以用来解决冲突,当文件出现冲突时,手动修改可能不方便,这时候就可以使用beyondCompare来解决这些冲突了
使用方法:
①: 下载bc
②: 到根目录的.gitconfig下添加对bc的配置
③: 在发生冲突后执行 git mergetool 命令,它会弹出bc的窗口
④: 将冲突解决,然后commit一下
tag
tag的作用是添加标签以及发送版本,我们可以在git log 中看到提交记录,但是不是很清晰,因此我们其实可以为这些提交记录添加一个标签,用于标识一下。
- 命令:git tag -a <标签名> -m “标签描述”:为当前所在版本添加一个标签
对于发送版本的功能而言,我们可以将tag推送到github上面,推送到github上后,可以在Tags当中查看所有的tag,每一个tag都对应了它所在版本的数据。
- 命令:git push 远程库地址/别名 --tags:将标签提交到github
场景
修复线上BUG
线上系统出现了BUG,这时候需要基于master分支拉取出新分支,修复成功后,master分支合并新分支即可。
git工作流规范
master分支用来存放线上稳定版本,项目组长一般会创建一个dev分支,组员基于dev分支创建分支来开发新功能,开发完毕后组长检查如果没问题就会合并到dev分支,release分支用来测试dev分支的代码,如果没问题就会合并到master分支来发布新版本。
本地仓库和远程仓库的推送问题
本地仓库所选择的分支推送到远程仓库后,远程仓库也会创建一个对应分支
克隆远程仓库后,所有的分支也都克隆下来了
在pull时,会将pull下来的内容合并到当前所在分支
如何在不影响本地文件的情况下,删除远程仓库上的文件
git rm -r --cached <文件名>
git commit -m “信息”
git push -u <远程仓库地址> <本地分支名>
如何给开源项目做贡献
①:fork一份到自己仓库
②:clone到本地进行修改
③:push到自己仓库
④:向原仓库发出pullRequests,指定从哪个分支合并到原仓库的哪个分支
git忽略文件
①:在本地仓库创建.gitignore文件并编辑
②:*.xx:表示忽略以文件名以xx结尾的文件
!*.xx:表示git只管理以xx结尾的文件
/files:表示忽略files文件夹下的所有文件
文件名:表示忽略指定的文件
配置文件
git的配置文件总共有三种,常用的就两种,一种是本地的,一种是全局的
-
本地:命令中带–local或者什么都不带的,是配置本地文件,它的位置存放在.git目录下的config当中
-
全局:命令中带global的就是配置全局文件,它的位置一般存放在C盘/用户/用户名/.gitconfig当中
常见命令
本地库的命令
git init:初始化本地库
git config user.name<用户名>,git config user.email<邮箱>:设置项目签名
git config --global user.name<用户名>,git config --global user.email<邮箱>:设置系统签名
git add <文件名>:添加文件到暂存区
git commit -m “提交信息” <文件名>:提交文件到工作区
分支命令
git branch <分支名>:创建分支
git branch -v:查看已创建的分支
git branch -D <分支名>:删除分支
git checkout <分支名>:切换分支
git merge <分支名>:合并分支
git checkout -b <分支名>:创建并切换到分支
查看git工作区,暂存区的变更情况
git status
提交记录
git log,git reflog ,git log --pretty=online
版本的前进/回退
git reset --hard <索引值>
为远程库url设置别名
git remote add <别名> <原地址名>
远程库的命令
git push <别名/远程库地址名> <本地分支名>:推送本地库到远程库
git clone <别名/远程库地址名>:将远程库文件克隆到本地库
git pull <别名/远程库地址名> <远程库分支名>:将远程库新增/修改内容拉取到本地库并合并
git fetch <别名/远程库地址名> <远程库分支名>:将远程库新增/修改内容拉取到本地库
git merge <别名/远程分支名>:将fetch下来的内容合并起来
rebase
git rebase <主分支名>
git rebase -i HEAD~N
git rebase 远程库地址/远程库分支名
tag
git tag -a <标签名> -m “标签描述”:为当前所在版本添加一个标签
git push 远程库地址名/别名 --tags
bc
git mergetool
总结
git在工作中经常使用,所以我们务必要掌握好git的基本命令和思想,也欢迎大家和我交流,共同进步!