一、版本控制
1.1 版本控制概念
在代码开发过程中,往往需要对源码进行多次的修改操作,这样一来同一份代码就产生了多个版本,在开发过程中通常需要对这些多个版本代码进行管理,以便于在需要时进行 代码回滚、多版本间比较、多人协作开发、代码分支、分支合并 等操作。
这样的需求大量的存在,而随着软件越来越复杂、代码越来越多、参与开发者越来越多,版本管理也变的越来越有难度,此时就需要专业的软件来对版本进行管理,这个过程就称之为版本控制,实现版本控制的软件就称之为版本控制软件。
1.2 版本控制软件分类
1.2.1 集中式版本控制
在集中式版本控制中,版本库是集中存放在中央服务器的,开发者在开发之前要先从中央服务器取得最新的版本,然后开始工作,工作完成后,再把自己的代码推送给中央服务器。中央服务器就好比是一个图书馆,你要改一本书,必须先从图书馆借出来,然后回到家自己改,改完了,再放回图书馆。 优点: 便于集中式的代码管理 便于进行权限控制
缺点: 需要联网才可以工作,而且项目庞大的情况下对带宽的要求比较高 中心服务器存在单节点故障风险
常见的集中式版本控制软件:CVS、SVN
1.2.2 分布式版本控制
在分布式版本控制系统中,没有“中央服务器”的概念,每个人的电脑上都是一个完整的版本库。而在多人协同工作时,通过推送各自的修改,保证多人间的版本一致。
但其实,在实际开发中,很少真的在两个电脑间进行修改的推送,而是选择一台充当“中央服务器”,但这个服务器仅仅是为了使用便利,本质上和其他机器没有任何区别,即使宕机,整个分布式版本控制仍然可以工作。
优点: 不需要联网也可以工作 不存在单节点故障风险
缺点: 无法实现严格的权限控制
常见的分布式版本控制软件:Git
二、git历史
Linus在1991年创建了开源的Linux,从此,Linux系统不断发展,已经成为最大的服务器系统软件了。
Linus虽然创建了Linux,但Linux的壮大是靠全世界热心的志愿者参与的,这么多人在世界各地为Linux编写代码,那Linux的代码是如何管理的呢?
在2002年以前,世界各地的志愿者把源代码文件通过diff的方式发给Linus,然后由Linus本人通过手工方式合并代码!
你也许会想,为什么Linus不把Linux代码放到版本控制系统里呢?不是有CVS、SVN这些免费的版本控制系统吗?因为Linus坚定地反对CVS和SVN,这些集中式的版本控制系统不但速度慢,而且必须联网才能使用。有一些商用的版本控制系统,虽然比CVS、SVN好用,但那是付费的,和Linux的开源精神不符。
不过,到了2002年,Linux系统已经发展了十年了,代码库之大让Linus很难继续通过手工方式管理了,社区的弟兄们也对这种方式表达了强烈不满,于是Linus选择了一个商业的版本控制系统BitKeeper,BitKeeper的东家BitMover公司出于人道主义精神,授权Linux社区免费使用这个版本控制系统。
安定团结的大好局面在2005年就被打破了,原因是Linux社区牛人聚集,不免沾染了一些梁山好汉的江湖习气。开发Samba的Andrew试图破解BitKeeper的协议(这么干的其实也不只他一个),被BitMover公司发现了(监控工作做得不错!),于是BitMover公司怒了,要收回Linux社区的免费使用权。
Linus可以向BitMover公司道个歉,保证以后严格管教弟兄们,嗯,这是不可能的。实际情况是这样的:
Linus花了两周时间自己用C写了一个分布式版本控制系统,这就是!一个月之内,Linux系统的源码已经由Git管理了!牛是怎么定义的呢?大家可以体会一下。
Git迅速成为最流行的分布式版本控制系统,尤其是2008年,GitHub网站上线了,它为开源项目免费提供Git存储,无数开源项目开始迁移至GitHub,包括jQuery,PHP,Ruby等等。
历史就是这么偶然,如果不是当年BitMover公司威胁Linux社区,可能现在我们就没有免费而超级好用的Git了。
三、GIT基本概念
3.1 GIT原理
3.1.1 GIT基于版本快照工作
Git 更像是把数据看作是对小型文件系统的一组快照。 每次你提交更新,或在 Git 中保存项目状态时,它主要对当时的全部文件制作一个快照并保存这个快照的索引。 为了高效,如果文件没有修改,Git 不再重新存储该文件,而是只保留一个链接指向之前存储的文件。 Git 对待数据更像是一个快照流。
3.1.2 GIT保证数据完整性
Git 中所有数据在存储前都计算校验和,然后以校验和来引用。这个功能建构在 Git 底层,是构成 Git 哲学不可或缺的部分。 若你在传送过程中丢失信息或损坏文件,Git 就能发现。
Git 用以计算校验和的机制叫做 SHA-1 散列(hash,哈希)。 这是一个由 40 个十六进制字符(0-9 和 a-f)组成字符串,基于 Git 中文件的内容或目录结构计算出来。 SHA-1 哈希看起来是这样: 24b9da6552252987aa493b52f8696cd6d3b00373 Git 中使用这种哈希值的情况很多,你将经常看到这种哈希值。 实际上,Git 数据库中保存的信息都是以文件内容的哈希值来索引,而不是文件名。
3.1.3 GIT一般只添加数据,因此不用担心版本丢失
你执行的 Git 操作,几乎只往 Git 数据库中增加数据。 很难让 Git 执行任何不可逆操作,或者让它以任何方式清除数据。 同别的 版本控制工具一样,未提交更新时有可能丢失或弄乱修改的内容;但是一旦你提交快照到 Git 中,就难以再丢失数据,特别是如果你定期的推送数据库到其它仓库的话。
这使得我们使用 Git 成为一个安心愉悦的过程,因为我们深知可以尽情做各种尝试,而没有把事情弄糟的危险。
3.2 版本库(仓库) 工作区 暂存区 分支区
3.2.1 版本库(仓库)
版本库又名仓库,英文名repository,你可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。
3.2.2 工作区
存放要管理的文件的位置
3.2.3 暂存区
版本库中 包含暂存区 git add 命令 或 git rm 命令加入的操作 被记录在暂存区内
3.2.4 分支区
版本库中 包含分支区 是最终版本信息保存的位置 git commit命令将暂存区内记录的操作 提交到分支中 可以配置多个分支,如果不指定则默认为master分支,并有一个head指针指向master分支的最新位置
四、GIT的安装配置
4.1 下载Git
Git最早只支持Linux平台,目前已经能够支持Linux、Unix、Windows、OS系统之上。 下载地址:https://git-scm.com
4.2 安装Git与Git配置
Linux上安装Git 解压Linux版源码包 依次执行
./config
make
sudo make install
Windows上安装Git 下载安装包 双击执行默认安装 双击 Git Bush 即可启动Git
初始配置Git 因为Git是一款分布式的版本控制软件,多用户之间的互相通信需要确定身份,所以安装Git后需要先配置当前用户的名称和邮箱,才可以使用 $ git config --global user.name "Your Name" $ git config --global user.email "email@example.com" git config --list 查看配置信息
五、GIT版本管理
5.1 GIT本地版本管理
5.1.1 创建版本库
通过cd命令进入目标文件夹 或 如果目标文件夹不存在可以通过mkdir命令创建文件夹
$cd e:
$pwd
$mkdir gitdemo01
$cd gitdemo01
通过git init 命令将该目录变为git所管理的仓库 $ git init 命令执行后,该目录下会多出一个.git的目录,这个目录是Git用来跟踪管理版本库的,请勿手动修改。
5.1.2 向仓库提交新文件
-
在工作区中创建一个文本文件,并在文件中保存一些内容 test01.txt Git is a version control system. Git is free software. -
查看版本库状态 git status -
将工作内容记录到暂存区 git add [files..]
e.g. 将文件 file1 ,file2 记录到暂存区
git add file1 file2
e.g. 将所有文件(不包含隐藏文件)记录到暂存区
git add *
-
取消文件暂存记录 git rm --cached [file] -
查看版本库状态 git status -
将文件同步到本地仓库
git commit [file] -m [message]
说明: -m表示添加一些同步信息,表达同步内容,不加file表示同步所有暂存记录的文件
e.g. 将暂存区所有记录同步到仓库区
git commit -m 'add files'
- 查看版本库状态
git status 本例中只经历了一个修改就提交了,其实完全可以 多个修改后一次提交
5.1.3 提交修改
-
修改test01.txt git is a version control system. git is free software. -
查看版本库状态 git status -
查看文件具体修改 git diff test01.txt -
提交文件到暂存区 git add test01.txt -
查看状态 git status -
将工作内容同步到仓库 git commit -m "change Git to git" -
再次查看状态 git status
5.1.4 提交修改 查看历史版本
-
修改test01.txt git is a version control system. git is free software. git is good. -
将工作内容记录到暂存区 git add test01.txt -
将工作内容同步到本地仓库 git commit -m "...some msg..." -
重复以上步骤保存文件的多个版本… 略 -
查看历史版本 git log 或git log --pretty=oneline
5.1.5 删除文件
5.1.6 细节:Git跟踪并管理的是修改,而非文件。
-
修改test.txt git is a version control system. git is free software. git is good git is easy to use -
增加文件到暂存区 git add test01.txt -
修改test.txt git is a version control system. git is free software. git is good git is easy to use git is very useful -
提交版本到分支 git commit -m "change test01.txt" -
查看状态: git status 发现git is very useful并没有被提交
5.1.7 回滚版本(版本控制)
5.1.7.1 回滚邻近版本:基于当前版本回滚若干版本
退回到上一个commit节点
git reset --hard HEAD^
说明: 一个^表示回退1个版本,依次类推。当版本回退之后工作区会自动和当前commit版本保持一致
退回到指定的commit_id节点
git reset --hard [commit_id]
查看所有操作记录
git reflog
注意:最上面的为最新记录,可以利用commit_id去往任何操作位置
-
基于当前版本回滚若干版本 git reset --hard HEAD^ 在Git中,用HEAD 表示当前版本,上一个版本就是HEAD^ ,上上一个版本就是HEAD^^ ,当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100 。 -
基于指定版本号回滚版本 git reset --hard 5527510751b4303390bb4f321bfa8b7f997cbfd0 这种方式的好处是可以任意跳转到指定版本,而不必参考当前版本位置。 -
查看历史命令及对应执行后的版本号: git reflog 此命令将会列出所有执行过的导致git版本变化的命令及其对应的版本号,可以配合git reset方便回滚到任意版本
5.1.7.2 回滚久远版本:通过tag指定版本标签名
标签: 在项目的重要commit位置添加快照,保存当时的工作状态,一般用于版本的迭代。 创建标签
git tag [tag_name] [commit_id] -m [message]
说明: commit_id可以不写则默认标签表示最新的commit_id位置,message也可以不写,但是最好添加。
e.g. 在最新的commit处添加标签v1.0
git tag v1.0 -m '版本1'
查看标签
git tag 查看标签列表
git show [tag_name] 查看标签详细信息
去往某个标签节点
git reset --hard [tag]
删除标签
git tag -d [tag]
git中的版本都有版本编号,对代码的提交和回滚都是基于版本编号进行的,但是git中的版本编号是一串随机串,不好记忆,此时可以使用标签机制为某个提交增加标签,方便以后查找。打了标签之后所有需要用到版本编号的位置都可以用对应的标签替代。
-
在当前分支当前提交上打标签: git tag v1.0 -
查看所有标签,默认标签是打在最新提交的commit上的: git tag -
如果想要打标签在某个指定历史commit上: git tag v0.9 f52c633 -
还可以创建带有说明的标签,用-a指定标签名,-m指定说明文字: git tag -a v0.1 -m "version 0.1 released" 1094adb -
可以通过如下命令查看一个tag信息: git show v0.1 -
如果标签打错了,也可以删除: git tag -d v0.1 -
如果要推送某个标签到远程,使用命令git push origin : git push origin v1.0 -
或者,一次性推送全部尚未推送到远程的本地标签: git push origin --tags -
如果标签已经推送到远程,要删除远程标签就麻烦一点,先从本地删除: git tag -d v0.9 -
然后,从远程删除。删除命令也是push,但是格式如下: git push origin :refs/tags/v0.9
5.1.8 撤销修改
-
在工作区中进行了修改,但尚未加入到暂存区: 撤销修改 – 将工作区中的文件恢复到最近一次add 或 commit之前的状态 git checkout [commit] -- [file] e.g. 将 test01.txt恢复,不写commit表示恢复最新保存的文件内容 git checkout -- test01.txt -
在工作区中进行了修改,并已经增加文件到暂存区,但尚未提交到分支区: 撤销修改 – 将暂存区中对这个文件的记录删除掉 git reset HEAD test01.txt -
在工作区中进行了修改,并且已经增加文件到暂存区,且已提交到分支: 可以通过之前所学的版本回退技术完成撤销操作。 但这仅仅是将版本进行了回滚,git并没有真正的忘记这次被回滚的提交,后续仍然可以再通过回滚操作回到这个版本上,这就是之前所说的git一旦提交就无法删除。
5.1.9 命令总结
5.1.10 指定git忽略指定内容
可以在仓库中配置.gitIgnore文件,在其中配置哪些文件是不需要git管理,则git在处理此仓库时,会自动自动忽略声明的内容。
1)空格不匹配任意文件,可作为分隔符,可用反斜杠转义
2)以“#”开头的行都会被 Git 忽略。即#开头的文件标识注释,可以使用反斜杠进行转义。
3)可以使用标准的glob模式匹配。所谓的glob模式是指shell所使用的简化了的正则表达式。
4)以斜杠"/"开头表示目录;
"/"结束的模式只匹配文件夹以及在该文件夹路径下的内容,但是不匹配该文件;
"/"开始的模式匹配项目跟目录;
如果一个模式不包含斜杠,则它匹配相对于当前 .gitignore 文件路径的内容,
如果该模式不在 .gitignore 文件中,则相对于项目根目录。
5)以星号"*"通配多个字符,即匹配多个任意字符;
使用两个星号"**" 表示匹配任意中间目录,比如`a/**/z`可以匹配 a/z, a/b/z 或 a/b/c/z等。
6)以问号"?"通配单个字符,即匹配一个任意字符;
7)以方括号"[]"包含单个字符的匹配列表,即匹配任何一个列在方括号中的字符。
比如[abc]表示要么匹配一个a,要么匹配一个b,要么匹配一个c;
如果在方括号中使用短划线分隔两个字符,表示所有在这两个字符范围内的都可以匹配。
比如[0-9]表示匹配所有0到9的数字,[a-z]表示匹配任意的小写字母)。
8)以叹号"!"表示不忽略(跟踪)匹配到的文件或目录,即要忽略指定模式以外的文件或目录,
可以在模式前加上惊叹号(!)取反。
需要特别注意的是:如果文件的父目录已经被前面的规则排除掉了,那么对这个文件用"!"规则是不起作用的。
也就是说"!"开头的模式表示否定,该文件将会再次被包含,
如果排除了该文件的父级目录,则使用"!"也不会再次被包含。可以使用反斜杠进行转义。
需要谨记:git对于.ignore配置文件是按行从上到下进行规则匹配的,意味着如果前面的规则匹配的范围更大,则后面的规则将不会生效;
# 表示此为注释,将被Git忽略
*.a 表示忽略所有 .a 结尾的文件
!lib.a 表示但lib.a除外
/TODO 表示仅仅忽略项目根目录下的 TODO 文件,不包括 subdir/TODO
build/ 表示忽略 build/目录下的所有文件,过滤整个build文件夹;
doc/*.txt 表示会忽略doc/notes.txt但不包括 doc/server/arch.txt
bin/: 表示忽略当前路径下的bin文件夹,该文件夹下的所有内容都会被忽略,不忽略 bin 文件
/bin: 表示忽略根目录下的bin文件
/*.c: 表示忽略cat.c,不忽略 build/cat.c
debug/*.obj: 表示忽略debug/io.obj,不忽略 debug/common/io.obj和tools/debug/io.obj
**/foo: 表示忽略/foo,a/foo,a/b/foo等
a/**/b: 表示忽略a/b, a/x/b,a/x/y/b等
!/bin/run.sh 表示不忽略bin目录下的run.sh文件
*.log: 表示忽略所有 .log 文件
config.php: 表示忽略当前路径的 config.php 文件
/mtk/ 表示过滤整个文件夹
*.zip 表示过滤所有.zip文件
/mtk/do.c 表示过滤某个具体文件,
被过滤掉的文件就不会出现在git仓库中(gitlab或github)了,
当然本地库中还有,只是push的时候不会上传。
需要注意的是,gitignore还可以指定要将哪些文件添加到版本管理中,如下:
!*.zip
!/mtk/one.txt
唯一的区别就是规则开头多了一个感叹号,Git会将满足这类规则的文件添加到版本管理中。为什么要有两种规则呢?
想象一个场景:假如我们只需要管理/mtk/目录中的one.txt文件,这个目录中的其他文件都不需要管理,
那么.gitignore规则应写为::
/mtk/*
!/mtk/one.txt
假设我们只有过滤规则,而没有添加规则,那么我们就需要把/mtk/目录下除了one.txt以外的所有文件都写出来!
注意上面的/mtk/*不能写为/mtk/,否则父目录被前面的规则排除掉了,one.txt文件虽然加了!过滤规则,也不会生效!
还有一些规则如下:
fd1/*
说明:忽略目录 fd1 下的全部内容;注意,不管是根目录下的 /fd1/ 目录,还是某个子目录 /child/fd1/ 目录,
都会被忽略;
/fd1/*
说明:忽略根目录下的 /fd1/ 目录的全部内容;
/*
!.gitignore
!/fw/
/fw/*
!/fw/bin/
!/fw/sf/
说明:忽略全部内容,但是不忽略 .gitignore 文件、根目录下的 /fw/bin/ 和 /fw/sf/ 目录;注意要先对bin/的父目录使用!规则,使其不被排除。
5.2 GIT远程版本管理
5.2.1 GitHub使用
-
远程仓库 远程主机上的GIT仓库。实际上git是分布式结构,每台主机的git仓库结构类似,只是把别人主机上的git仓库称为远程仓库。GitHub可以帮助我们建立一个远程仓库。 -
GitHub介绍 GitHub是一个开源的项目社区网站,拥有全球最多的开源项目。开发者通过可以注册网站账户,在GitHub建立自己的项目仓库(我们可以视作一个远程仓库),GitHub规定GIT为它的唯一代码管理工具。 -
GitHub网址:github.com
5.2.1.1 获取项目
5.2.1.2 创建自己的项目仓库
-
填写相应的项目信息即可 -
github仓库相对本地主机就是一个远程仓库通过remote连接 -
在本地使用ssh连接仓库 # 后续操作每次上传内容都需要输入密码,比较麻烦,一般用于临时计算机的连接使用
git remote add origin git@github.com:/tarena/aid.git
注意:
如果连接远程时 git remote add origin 后用https地址,那么以后每次上传内容都需要输入用户名密码
-
查看连接的远程仓库名称 git remote
-
断开远程仓库连接 git remote rm [origin]
-
如果是自己的仓库需要删除,则选择自己的仓库选择settings,在最后可以选择删除仓库。
5.2.1.3 远程仓库操作命令
-
如果要推送某个标签到远程,使用命令git push origin : git push origin v1.0 -
或者,一次性推送全部尚未推送到远程的本地标签: git push origin --tags -
如果标签已经推送到远程,要删除远程标签就麻烦一点,先从本地删除: git tag -d v0.9 -
然后,从远程删除。删除命令也是push,但是格式如下: git push origin :refs/tags/v0.9
5.2.2 远程仓库连接
由于GitHub是境外的网站,连接不稳定,我们使用GitEE码云替代 注册GitEE账号,并配置仓库,会分配到仓库的地址 地址有两种形式,分别是HTTPS和SSH两种方式,用哪个都可以,区别是HTTPS需要输入用户名密码,而SSH可以实现免密登录
5.2.3 将本地仓库关联到远程仓库
本地关联到远程仓库: git remote add <服务器名称><远程仓库地址> git remote add origin https://gitee.com/pcj2619/big1807_test01.git
5.2.4 将本地仓库推送到远程仓库
把本地库的内容推送到远程: git push -u <服务器名称> <本地分支名称> $ git push -u origin master
当使用HTTPS连接时,会弹出框要求输入用户名密码,输入码云的用户名和密码即可
第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。
5.2.5 从远程仓库克隆
将远程仓库克隆到本地 git clone <远程仓库地址> <本地目录名> git clone https://gitee.com/pcj2619/big1807_test01.git E:\gitdemo02
5.2.6 拉取远程仓库中的更改到本地仓库
拉取远程仓库中的更改到本地仓库 git pull <远程仓库地址> <远程分支名>:<本地分支名> git pull https://gitee.com/pcj2619/big1807_test01.git master:master
5.2.7 删除本地仓库到远程仓库关联
将本地仓库和远程仓库的关联关系删除 git remote rm <服务器名称> git remote rm origin
5.2.8 使用SSH连接
使用SSH连接相对于HTTPS连接的优势在于,是通过非对称加密保护的,更加安全,且可以实现免密登录.推荐大家使用SSH连接.
- 客户端生成公钥私钥
ssh-keygen -t rsa -C "youremail@example.com" 此命令会在用户主目录下生成.ssh目录,里面有id_rsa和id_rsa.pub两个文件,其中id_rsa是私钥,不能泄露出去,id_rsa.pub是公钥,可以放心的传播。 - 在码云中配置公钥
在码云的 [配置] - [SSH公钥] 中 将本机中生成的公钥内容粘贴配置进去。之后就可以使用ssh连接免密访问码云了。
六、GIT的协作开发 - 分支管理
6.1 分支概念
所谓的分支就是从当前的开发线中分割出的一条新的开发线。
利用新开出的开发现在不影响原来开发线的过程中,开发并提交代码,等到新的开发线开发完成,可以一次性加入原开发线,即进行分支合并操作。
分支在实际中有什么用呢?假设你准备开发一个新功能,但是需要两周才能完成,第一周你写了50%的代码,如果立刻提交,由于代码还没写完,不完整的代码库会导致别人不能干活了。如果等代码全部写完再一次提交,又存在丢失每天进度的巨大风险。
现在有了分支,就不用怕了。你创建了一个属于你自己的分支,别人看不到,还继续在原来的分支上正常工作,而你在自己的分支上干活,想提交就提交,直到开发完毕后,再一次性合并到原来的分支上,这样,既安全,又不影响别人工作。
6.2 分支的使用 - 基本使用
6.2.1 查看分支
git branch
6.2.2 HEAD指针
在git中存在一个名为HEAD的指针,这个指针指向的位置就是当前操作位,这个指针指向哪里,之后的指令操作的就是哪里。
6.2.3 创建新的分支
当我们创建新的分支,例如dev时,Git新建了一个指针叫dev,指向master相同的提交位 git branch <分支名> git branch dev
6.2.4 切换分支
可以通过命令切换分支,切换分支的本质就是将head指针指向了目标分支,由于只是切换一个指针指向,所以切换分支的操作效率非常的高 git checkout <分支名> git checkout dev
6.2.5 快速创建和切换分支
也可以通过如下命令创建分支并直接切换到该分支,等价于如上的两个命令 git checkout -b <分支名> git checkout -b dev
6.2.6 提交新版本到分支中
6.2.7 将dev分支合并到master分支中
想要将dev分支合并到master分支,只要将head重新指向master分支,并命令head指向的master分支合并到dev的指针位即可 - 本质上就是将master的指针指向dev的指针,最后删除dev分支。
-
切换回主分支 git checkout <分支名> git checkout master -
合并分支 git merge <要被合并的分支名> git merge dev -
删除dev分支 git branch -d <删除没有被合并的分支> git branch -d dev git branch -D 强行删除分支 · -
查看分支【所有分支】 git branch [-a] -
在合并分支时可以增加一个–no-ff参数,此参数将会在合并分支时禁用Fast forward模式,效果上回自动在merge时增加一个提交,方便后续管理 git merge --no-ff -m "som commit msg.." dev2
6.3 分支的使用 - 冲突处理
6.3.1 冲突的产生
当多个分支之间的进行合并时,如果多个分支对同一个文件进行过不同处理,则在合并时GIT不知道要保留哪个处理结果,就会产生冲突。
定义: 当分支合并时,原来的父分支发生了变化,在合并过程中就会产生冲突问题,这是合并分支过程中最为棘手的问题。
冲突情形1—— 原来的分支增加了新文件或者原有文件发生了变化 此时合并可能会出现: 此时只要先摁 ctrl-o 写入,然后回车,再摁ctrl-x 离开就可以了。 也可能出现提示让直行commit合并,那么此时只需要直行commit操作就可以了。这种冲突比较好解决。
冲突情形2—— 子分支和父分支修改了相同的文件 此时会出现: 这种冲突不太好解决需要自己进入文件进行修改后,再直行add ,commit操作提交
-
在master分支上创建demo01.txt demo01.txt aaa -
在master分支上提交demo01.txt git add demo01.txt git commit -m "add demo01.txt" -
创建新的分支dev并切分支换到dev git checkout -b dev -
修改文件demo01.txt,内容为bbb demo01.txt bbb -
在dev分支上提交: git add demo01.txt git commit -m "modify demo01.txt to bbb" -
切换到master分支: git checkout master -
修改demo01.txt,内容为ccc: demo01.txt ccc -
在master分支上提交: git add demo01.txt git commit -m "modify demo01.txt to ccc" -
尝试通过merge操作在master分支上合并dev分支,由于master分支和dev分支对demo01.txt文件的状态不一致,造成合并时冲突 git merge dev
6.3.2 解决冲突
- 手动修改
- 给文件添加权限
- 总结
尽量在项目中降低耦合度,不同的分支只编写自己的模块。 如果必须修改原来父级分支的文件内容,那么做好分工,不要让多个分支都修改同一个文件。
6.4 保存工作区
当某一分支工作到一半,突然需要切换到其他分支时,可以通过stash机制将当前分支状态暂存起来,再在需要的时候恢复。
-
新建并提交demo01.txt demo01.txt aaba -
创建并切换到dev分支 git checkout -b dev -
创建文件demo02.txt: demo02.txt xxx -
将文件加入暂存区: git add demo02.txt -
临时需要切换到其他分支,暂存当前分支: git stash -
查看状态: git status -
切换到debug分支 git checkout -b debug -
调试bug,修改文件: demo01.txt aaba --> aaaa -
提交文件: git add demo01.txt git commit -m "debug fix demo01.txt" -
切换到master分支 git checkout master -
合并debug分支 git merge "merge debug" debug -
切换回dev分支: git checkout dev git status -
发现工作区是干净的,需要恢复暂存分支: git stash list -
恢复到之前暂存的状态 有两个办法: 一是用git stash apply 恢复,但是恢复后,stash内容并不删除,你需要用git stash drop来手动删除暂存状态 另一种方式是用git stash pop ,恢复的同时把stash内容同时删除 git stash pop
企业级开发中分支使用策略 master分支应该是非常稳定的,也就是仅用来发布新版本
干活都在dev分支上,也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本
在企业级开发中,不同小组同时开发不同功能模块也是非常常见的,此时可以开辟分之下更多个子分支进行并行开发。
灵活的利用分支机制,可以实现高效的并行开发下的版本管理。
|