一:版本控制
一说到版本的控制我们就会浮现出大学写毕业论文时候的痛苦的场景,有过基础版,修改版,修改版1,修改版2,完整版,完整版1,完整版2,最后一个版本,打死也不改的版本,最终版本,真的是最终版本,等等:以上就是我们以最原始的方式对我们的版本进行控制,但是很明显这种版本的控制有以下几个显著的缺点:
- 多个文件,保留所有版本时,需要为每个版本保存一个文件,这样就会导致版本的冗余
- 协同操作,多人协同操作时,需要将文件打包发来发去,这样会浪费很多时间在传输以及沟通上
- 容易丢失,被删除意味着永远失去,一旦失去就很难找回来了,当然了我们可以选择网盘存储
因此为了解决这个问题一大堆的版本控制的工具就应运而生:VSS、CVS、SVN、Git等,其中Git属于绝对霸主地位。
注意:一般的版本控制工具包括两个部分
- 客户端(本地):本地编写内容以及版本记录
- 服务端(网盘):将内容和版本记录同时保存在远程(可有可无)
二:Git的介绍
Git 是一个开源的分布式版本控制软件,用以有效、高速的处理从很小到非常大的项目版本管理。 Git 最初是由Linus Torvalds设计开发的,用于管理Linux内核开发,是一个帮助用户实现版本控制的软件。
GitHub是一个基于Git的远程文件托管平台(同GitCafe、BitBucket和GitLab等)。
Git本身完全可以做到版本控制,但其所有内容以及版本记录只能保存在本机,如果想要将文件内容以及版本记录同时保存在远程,则需要结合GitHub来使用。使用场景:
- 无GitHub:在本地 .git 文件夹内维护历时文件
- 有GitHub:在本地 .git 文件夹内维护历时文件,同时也将历时文件托管在远程仓库
三:Git基础功能学习
第一阶段:小陈是一个年轻有为的青年,决定开始进行创业,于是自己下定决心独自封闭的花了一个月的时间去进行开发,经过一段时间之后,最基础的版本终于开发完毕,正准备上线的时候,回顾整个的开发过程中,其中的艰辛只有小陈一个人知道,打开自己的开发目录一看,其中里面错综复杂,如果哪天出现了一个bug的话那么需要回滚到上一个版本,这时候自己都找不到对应的版本在哪里,如果以后要是维护这个系统的话需要找很多人来维护,这样就会使得整个系统的维护非常困难,这种形式做版本控制真的很差。通过与其他大神交流发现了一个神奇的东西,这个东西就是git,听说这个东西特别的牛逼,小陈就决定开始用这个进行版本控制,亲自体验一把。
首先去官网下载git的安装包:https://git-scm.com/找到自己电脑的版本,在此下面的我通过windows来进行演示与讲解:
假设这个项目是个金庸电视剧的播放软件,我们首先在本地pycharm里面建一个简单的django项目进行演示:创建好了之后关闭pycharm,我们就会得到这样的一个文件夹:
在这个文件夹里面有一个index.html的文件,这个里面有几部电视剧已经开发完毕
安装git完毕之后我们进入项目所在的文件夹右键查看,里面会有Git GUI Here与Git Bash Here这两个标识,Git GUI Here这个用户界面启动,Git Bash Here这个是命令行启动,一般情况下的时候我们都会使用Git Bash Here来进行操作。接来来进入Git Bash Here:
1.首先先执行git init这个命令,这个命令是将文件夹管理起来,初始化之后就会在本地创建一个透明的.git文件夹,但是这个文件夹里面的文件还没有被管理起来,说白了就是建立一个小仓库将我们的文件放在这个文件夹里面。
Initialized empty Git repository in C:/Users/chenjunkan/Desktop/test_git/.git/
就是在本地C:/Users/chenjunkan/Desktop/test_git/.git/这个目录下面创建一个空的git管理仓库用来管理对应的文件夹
2.执行git status:查看文件夹里面文件的状态,里面的文件全部为红色的,因为如果有新的文件或者原来的文件修改了都会变成红色,这些变为红色的文件说明这些文件还没有被我管理起来
3.执行git add manage.py:我们发现manage.py变绿了,除了这个之外其他的还是红的,这就代表通过manage.py这个命令把这个文件给管理上了,只是简单的管理上了但是还没有保存起来
4.执行git add .:表示一次性把所有的文件都给管理起来,所以文件都会变绿,也就是表示所有的文件都被管理了,但是还没有保存起来
5.执行git commit -m '创建第一个版本':在这里出现了报错,也就是告诉是谁,按照命令去执行一下,因为要找到是谁管理是谁生成的,先配置一下
git config --global user.email "[email protected]"
git config --global user.name "Your Name"
如果我修改了一个文件:修改过之后就会变成红色,我们现将其管理起来,然后重新提交
6.执行git log:能够查看提交记录,这个里面的加密字符串就是版本号,也就是唯一标识
7.假设现在我当前的版本出现了问题我想回滚到之前的版本那么我们需要执行:git reset --hard 对应的版本号:回滚到对应的版本,这样在我们刚刚添加的雪山飞狐就自动的消失了,也就是回到了第一个版本
8.如果现在我又有一个需求,想回到之前的雪山飞狐的版本,这时我们使用git log查看一下,是没有效果的,那该怎么办呢?
那么我们可以使用下面的这个命令:执行git reflog:查看历史所有的版本以及操作记录
然后再执行git reset --hard 对应的版本信息
9.执行git checkout 对应的文件:如果我修改一个文件修改到一半,假设将雪山飞狐改为了雪山飞狐1,突然不想修改了,那么就可以用这个命令回到原始的状态
好了,到此为止现在第一阶段结束了,第一阶段我们代码会经过几个步骤
那么接下来要开始第二阶段的开发了
第二阶段:
如果现在继续想开发新的电视剧播放,假设我们开发的是倚天屠龙记,但是这个功能开发到一半的时候,突然另外一个射雕英雄传要求下线了,那怎么办?
方式一:
1.执行git stash:找到当前文件夹下面管理的文件是红色的文件,红色的文件就是被修改过的文件,把他拿走拿到一个神奇的地方,只存我们红色的文件,没有被管理没有提交,帮助我们暂时存储已经开发的代码(倚天屠龙记)
此时我们新加的功能倚天屠龙记就被拿到一个神奇的地方去了,剩下的就是当前线上的雪山飞狐这个版本,此时我们将线上的射雕英雄传删除下架
再执行git commit -m '删除了射雕英雄传'
2.此时线上的bug已经修复了,我们还能继续的开发新的功能倚天屠龙记,但是我们之前开发的功能已经到了一个神奇的地方去了,怎么样把他拿下来呢?
执行git stash pop:从那个神奇的地方把刚才放进去的倚天屠龙记拿回来,其实就是做了一个合并的动作,将神奇的地方与我们当前的代码合并,返回第一个
因为此时我还没有提交,如果这个时候我又执行git stash这个命令,将倚天屠龙记拿走,并且新增一个叫做碧血剑的功能,先提交
此时提交之后我还想继续开发之前的那个倚天屠龙记的功能:这就会有部分冲突,执行git stash pop
那么什么时候会合并,什么时候会冲突呢?
第一种情况就是:当我删除某个文件的时候,我在回滚时会合并最后删除之后的文件
第二种情况就是:当我新增的文件的时候,我本地的比神奇的地方的文件要多,会出现文件的冲突,如果我要修改的那行跟我拿走的那行有冲突,就会吧两个全部都显现出来,让我们手动去解决冲突
总结:如果在已经上线的功能的代码里面继续开发新的功能(碧血剑),此时如果老板来说,先把之前的某个功能修改一下上线或者临时需要改bug或者有新功能上线,那么我们就需要停下手里的任务,将代码先保存用git stash(只存我们红色的文件,没有被管理没有提交),等到修改好了之后然后再重新拉取代码操作git stash pop。
stash相关常用命令:
- git stash 将当前工作区所有修改过的内容存储到“某个地方”,将工作区还原到当前版本未修改过的状态
- git stash list 查看“某个地方”存储的所有记录
- git stash clear 清空“某个地方”
- git stash pop 将第一个记录从“某个地方”重新拿到工作区(可能有冲突)
- git stash apply 编号, 将指定编号记录从“某个地方”重新拿到工作区(可能有冲突)
- git stash drop 编号,删除指定编号的记录
方式二:
接下来继续开发在线播放电视剧的功能;开发到一半的时候,我现在需要吧碧血剑功能继续上去,这个时候其实stash也可以,但是我们不用这种方式,我们用分支的方式:
1.执行git branch dev:表示新创建一个分支,复制当期分支的所有代码到dev分支里面去
后面的括号里面代表的是当前所在的分支也就是master
2.如果此时我想跳到dev分支去开发的话那么执行:git checkout dev
现在我们在dev分支上继续增加新的功能比如增加一个连城诀
这样就会创建出两个分支,我们只需要在master分支上提交代码,dev里面是正在开发的功能
3.如果此时出现了一个比较严重的bug我们需要及时去修改,虽然我们已经有了一个dev分支,但是这个分支只是给我们用来开发新的功能用的,对于出现的bug原则上是不允许直接在master上直接修改的,因此我们就需要单独的再创建出一个分支修改bug
假设是天龙八部这个功能出现bug了,那么我们就需要创建一个新的分支来处理:git branch tlbb
4.好了现在假设所有的bug都修复,我们需要合并我们的代码了,这时候我们需要把tlbb的修复过的问题合并到我们的线上也就是master
首先切换到master分支上面在进行合并;执行:git merge tlbb:将增加的信息的的代码合并到master
我们执行git log查看一下合并的日志
5.接下来我们的tlbb这个分支就没有必要存在了:执行git branch -d tlbb
面试题:如果出现bug了怎么办?
首先先创建一个bug的分支,然后修改好了bug之后将修改好的bug与master分支合并,并且删除bug分支回到原来的dev分支上去继续操作
注意:git merge 时也可能会出现冲突,解决冲突的方式上述stash相同,即:找到冲突文件,手动修改冲突并提交,此处不再敖述。
第三阶段:
如果现在公司变大了,我们需要白天加班晚上也加班的去弄,那么我们总不能天天用U盘等一些工具复制并且随身的携带代码吧,这样会导致很不安全,Git有没有类似于云盘似得东西可以进行数据同步呢?答案肯定是有。GitHub,一个基于Git实现的代码托管的平台,可以将内容以及版本记录在远程也保存一份,这样就不用U盘咯(类似于云盘)。PS: 类似GitHub的产品还有许多,如:GitLab、Bitbucket、码云等。
1.首先我们要先注册gitbhub账号:https://github.com/
2.创建仓库:
3.执行git remote add origin https://github.com/cjk139511/test_git.git # 为地址起一个别名origin
4.执行git push origin master:# 将本地master分支内容以及版本信息推送到GitHub
Username
for
'https://github.com'
:
# 输入GitHub用户名
Password
for
'https://[email protected]'
:
# 输入GitHub密码
5.如果我想把dev的代码也推送上去怎么办:执行git checkout dev; git push origin dev
6.虽然我将代码已经给github托管了,那么回到家里我要是想继续开发的话,那么如何下载呢?
执行:git clone https://github.com/cjk139511/test_git.git;默认的情况下只是下载下来master版本
这样是因为,git文件在里面
7.如果我想拉到dev版本的代码执行git pull origin dev
8.现在我们有两个地方一个是在公司的代码,一个是在家里写的代码
假设我们白天是在公司上班,在公司的时候我们开发一个新的功能叫做vip会员,然后推送到github上之后就回家了
到家之后有是写代码,这时候公司的代码较多,家里的代码较少,这时候就需要拉代码了
接下来我们又要继续开发了,这个时候vip会员的功能我们开发完成了
第二天又来公司拉取代码
9.之前我们所说的都是正产的功能,现在我们来点不是很正常的功能,比如我们在公司的时候新建了一个文件touch 1.py,但是此时忘记提交了
但是回家之后想拉取代码,但是此时什么代码也拉取不下来,但是此时我可以先开发一个其他的功能假设为2.py,此时我一定要将代码提交了
第二天到了公司之后我继续写,但是我们此时我们的本地有1.py的代码,但是仓库里面有一个2.py,如果此时我去提交了有可能2.py这个文件会被覆盖,如果此时我提交的话会一直不成功,所以此时我们需要先拉取一下代码,但是拉取代码的话有可能会出现冲突
接下来我需要继续再去开发,假如我开发了一个3.py的功能,但是这个时候我一定要推送
此时我回到家继续拉取代码,其实我们在之前的操作中一直都是通过git pull origin dev这样的方式来拉取代码的,但是我们还有另外的一种方式拉取
10.上文执行过程中执行 【git pull origin 分支】命令等同于【git fetch origin 分支】+ 【git merge origin/分支】,并且在执行过程中可能会出现冲突,原因是由于本地代码和获取的最新代码有重合部分,那么就需要自己手动解决冲突然后再继续开发。
其实这个时候还没有直接到达本地的,而是先到版本仓库,然后再去执行git merge origin/dev
11.rebase的使用:我们在正常的提交通过图形界面的时候能够看得见分叉:如果把git merge origin/dev 改成git rebase origin/dev那么就不会分叉了
第四阶段:
随着公司的逐步增大,需要招人多人一起协同开发;itHub中多人协同开发和单人开发还是有点差别,协同开发一般有两种方式:
合作者,将其他用户添加到仓库合作者中之后,该用户就具有向当前仓库提交代码。
1.在setting里面设置合作者
组织,创建一个组织,然后再该组织下可以创建多个项目,组内成员可以向组内所有项目提交代码。PS:也可以对某个项目指定合作者
- 创建程序
- 用户A创建程序,提交到GitHub
- 用户B克隆项目
- 用户C克隆项目
- 开发功能
- 用户A开发功能1
- 用户B开发功能2
- 用户C开发功能3
- 提交
- 用户A提交功能1,并push(A用户手速快,先提交。)
- 用户B提交功能2,无法push,因为GitHub上已经有其他人提交的新代码。
解决方法:从GitHub上获取最新代码并合并到本地,提交自己开发的功能2。 - 用户C提交功能3,无法push,无法提交,因为GitHub上已经有其他人提交的新代码。
解决方法:从GitHub上获取最新代码并合并到本地,提交自己开发的功能3。
- 获取最新代码
- 用户A获取最新代码
- 用户B获取最新代码
- 用户C获取最新代码
在上面红色标注的解决方法位置可以有三种方式操作,三者都可以完成合并并提交新功能,但是日志记录会有差异,如:前两者版本记录中会出现合并,而第三种可以保证版本记录干净整洁。
-
- 先 git pull origin master 然后 git push origin master
- 先 git fetch origin master 然后 git merge origin/master 再 git push origin master
举例说明:首先有两个分支:
然后分别跳到自己的分支上去开发自己对应的功能,分别将自己的功能提交,但是我们的功能只完成了一半,接下来我们回去继续提交,全部提交完成之后再次提交
那么接下来我们就要去合并代码了:
首先cjk1先合并代码:切换到dev分支
然后推送到远程:然后cjk1就回家了
那么接下来就是cjk2来推送的合并了,这个时候cjk2是可以合并的但是不能推送,会报错;因此先得拉下来,再推
第五阶段:
终于终于等到了公司上市实现财务自由,但作为一个技术屌还是脱离不了屌丝的本质,所以每天都是逛逛github,看看别人有什么好的项目,自己可以给他挑挑bug装装逼,但是别人不可能给搞成合作者什么的,那怎么才能给别人贡献代码呢?那就是fork了。。。。
找到想搞的项目,fork一下,然后这个项目就在自己仓库出现了
- 从自己仓库获取代码并进行编辑提交
- 创建并提交一个pull request,然后等待原作者是否同意这个pull request,如果同意那么在作者的源代码中就推出现我提交的功能
其他:
1. 配置文件
Git的配置文件有三个:
- 系统配置: /private/etc/gitconfig
- 用户配置: ~/.gitconfig
- 项目配置:.git/config
2. 用户凭证
由于Git和Github交互操作可能会很频繁,那么一定少了用户授权的操作,为了防止每次操作重复输入用户名和密码,Git提供了两种解决方法:
-
- 秘钥
首先创建一对秘钥 ssh-keygen -t rsa,然后将 id_rsa.pub (公钥)内容拷贝到github中,日后操作无需再输入用户名和密码。
注意:这种方式需要使用GIt中 [email protected]:WuPeiqi/xxxxx.git 格式地址。 - 密码
Https访问git时,避免每次操作需要输入用户名和密码,可以在配置文件中添加如下配置项:
[credential]
helper = store/cache/第三方store:
表示将用户名和密码保存在硬盘上
第一次输入过用户名和密码之后,用户名和密码就会保存在当前用户根目录的 .git-credentials 文件中,内容格式为:https://用户名:密码@github.com自动添加配置命令:git config credential.helper store
cache:
表示将用户名和密码保存在缓存中
第一次输入过用户名和密码之后,用户名和密码就会保存在缓存中,默认超时时间是 900 秒,缓存相关文件保存在当前用户根目录的 git-credential-cache 中
自动添加配置命令:
git config credential.helper cache
git config credential.helper 'cache --timeout=300'相关操作:
清除缓存:git credential-cache exit
指定超时:
[credential]
helper = cache --timeout=300
注意:
这种方式需要使用GIt中 https://github.com/WuPeiqi/xxxx.git 格式地址。
指定用户名和密码: https://用户名:密码@github.com/wupeiqi/xxx.git
- 秘钥
版本:
git tag -a v1.0 -m '版本介绍' 本地创建Tag git show v1.0 查看 git tags -n 查看本地Tag git tag -l 'v1.4.2.*' 查看本地Tag,模糊匹配 git tag -d v1.0 删除Tag git push origin :refs/tags/v0.2 更新远程tag git checkout v.10 切换tag git fetch origin tag V1.2 git push origin --tags git pull origin --tags git clone -b v0.1