Git分布式版本控制系统
目录
1.Git简介
1.1什么是GIt?
Git是目前世界上最先进的分布式版本控制系统。
1.2什么是分布式版本控制系统?
就是分布式版本控制系统,对应的是集中式的版本控制如SVN。简单的说,分布式的版本控制就是每个人都可以创建一个独立的代码仓库用于管理,各种版本控制的操作都可以在本地完成。每个人修改的代码都可以推送合并到另外一个代码仓库中。而像SVN这样,只有一个中央控制,所有的开发人员都必须依赖于这个代码仓库。每次版本控制的操作也必须链接到服务器才能完成。很多公司喜欢用集中式的版本控制是为了更好的控制代码。如果个人开发,就可以选择Git这种分布式的。git分布系统可以记录你每次修改文件的信息。
1.3Git的诞生?
【转】很多人都知道,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写了一个分布式版本控制系统,这就是Git!一个月之内,Linux系统的源码已经由Git管理了!牛是怎么定义的呢?大家可以体会一下。
Git迅速成为最流行的分布式版本控制系统,尤其是2008年,GitHub网站上线了,它为开源项目免费提供Git存储,无数开源项目开始迁移至GitHub,包括jQuery,PHP,Ruby等等。
历史就是这么偶然,如果不是当年BitMover公司威胁Linux社区,可能现在我们就没有免费而超级好用的Git了。
1.4Git的安装?
从官网直接下载即可,正常安装,但是不要有中文路径,地址:官方安装地址
安装完成会在桌面的菜单键看到 git Bask 字样。
因为git是分布式版本系统,每个机器都得有自己的认证识别号,输入下面的命令设置。
注意:把 "Your name" 换成自己的名字,把 "[email protected]"换成自己的邮箱!
$ git config --global user.name "Your Name"
$ git config --global user.email "[email protected]"
至此,安装完成。
2.创建版本库(repository)
2.1什么是版本库?
简单一点可以看作一个目录,创建这个目录可以被GIt管理,在里面的文件,你可以看到他的修改内容和历史修改痕迹,以及数据还原恢复。
2.2创建一个版本库
第一步:创建一个目录
指令:创建一个目录: mkdir 目录名
跳转到当前目录:cd 目录名
显示当前目录: pwd
第二步:把目录编程git可以管理的目录
指令:初始化: git init
.git文件的作用:这个目录是Git来跟踪管理版本库,不要去动。
2.3创建文件添加到版本库
新建一个Txt文本文件,存放于刚刚新建的GItfile文件夹下。
编辑文本
命令:把文件添加到仓库:git add 文件名
把文件提交到仓库:git commit -m "备注信息"
git commit 命令执行成功后,git会告诉你
$ git commit -m "first edit"
[master (root-commit) fb594f1] first edit
1 file changed, 2 insertions(+)
create mode 100644 textfile.txt
1 file changed 一个文件被改变,2 insertion(+) 插入两行信息。
所以git文件提交需要两步,先git add 然后 git commit .
3.修改文件,体会Git的强大之处
上面已经完成在git创建一个textfile.txt 文件,并且Git已经可以管理。
3.1修改textfile.txt文件
既然,git可以管理我们这个文件,那么他肯定已经知道我们已经修改了文件里面的信息了。
我们使用命令 ,查看文件状态:git status
$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: textfile.txt
no changes added to commit (use "git add" and/or "git commit -a")
git status
命令可以让我们时刻掌握仓库当前的状态,上面的命令输出告诉我们,textfile.txt
被修改过了,但还没有准备提交的修改。
我们可以使用命令:git diff 文件名
去查看文件发生的变化。
然后把它提交到Git上去,如上所述需要两步:1.git add 2.git commit -m
注意:备注信息,“second edit ,add two”。
3.2再次修改txtfile.txt 的文件,如下图所示
然后提交文件给Git.
3.3GIt如何从上一次提交后的文件退回到上一次的文件编辑,(就像你打单机游戏一样,你过关斩将,等游戏结束了之后,你需要存盘,但是如果新的一关成绩不理想,你可以重新退出到上一次的游戏重新开始玩,回到上一次存盘的地方)。
从开始到现在我们一共在名为:Gitfile的版本库中git commit 了三个文件,如下图所示:
第一次:备注信息:“first edit”
第二次:备注信息:“second edit , add two”
第三次:备注信息:“third edit ,add three”
如何退回上一次编辑的位置 ?
可能我们改了很多次了,已经不记得改过什么了,版本控制系统肯定会有你修改文本的日志的,使用命令:git log
可以查看在GItfile这个版本库中,你的修改日志。
注意:在commit一行上看到一大串的 93753...... 的数字commit id(版本号)用处后面讲解,是十六进制的表示方法,这是因为Git是分布式的版本控制系统,所以每一个人的ID 肯定不一样,就像身份一样。
在修改日志中,我们可以看到我们修改的次数是三次,也就是提交的次数,最近一次是"third edit ,add three",我们可以看到修改的次数,作者,和修改日期。
注意:加上 --pretty=oneline 可以简化参数。
现在我们不 textfile.txt 的文本内容退回到上一个版本。也就是 “second edit ,add two”.
GIt 用 HEAD 表示当前版本,也就是 “third edit ,add three”
那上一个版本的表示方法是:HEAD^ (也就是 “second edit , add two”)
再上一个版本就是 :HEAD^^ (也就是 “first edit”)
以此类推,前1000次的应该有1000个 “^”,放心,GIt绝对是人性化的,它可以表示为:HEAD~1000
使用命令:版本返回:git reset
提示当前版本号为:3cdee72
可以看到这个3cdee72的来源,显示的就是这个版本号。
那我们再看看textfile.txt 有什么改变没有
果然退回了上一个版本。
然后我们在看看我们的日志有没有什么变化?
我们已经从未来穿越回来,如果像回到未来可能吗?答案肯定是可以的,你需要知道你的版本号(commit id) ,但是我们在上面的日志中已经找不到,最近的一个 commit id 了怎么办?
第一个办法:上一次的窗口还有commit id ,但是如果窗口被清除过一次怎么办?Git提供了一个命令git reflog
用来记录你的每一次命令。我们试试看
我们顺利的把commit id 找了回来,现在我们可以试试能不能从过去回到现在。
在git reset --hard 中一个 --hard ,是什么意思呢?
可以用命令: git reset --hard 版本号,回到指定版本号
顺利撤回到版本。
再看看textfile.txt 的内容:
例子:回到前两次后再次,撤销到,“second edit ,add two ”的版本?
查看日志:
此时已经只能看到第一次的版本号了,如何回到 “second edit ,add two ”版本呢?我们有操作日志:
命令:git reflog
找到我们想回去的那个版本号,使用命令: git reset --hard 版本号 。
再次查看textfile.txt 的文本信息。
成功回到我们需要回到的版本号。
4.工作区和暂存区
4.1.何为工作区(Working Directory)?
在GIt中,工作区就是一个目录,能在本地缓存数据的地方。
4.2.何为版本库(Repository) ?
在初始化,版本库时,我们输入一个命令去初始化git:git init,生成了一个(.git)文件夹,如上图所示,那是Git的版本库 。
Git的版本库里面存放了很多东西,不一一剖析,最终要的就是 stage (或者成为index索引)的暂存区,还有一个初始化时GIt为我们创建的第一个分支 maser,以及指向master的指针HEAD
前面我们把文件添加到Git版本库,分两步:
第一步:git add,把文件添加进去,实际上是把文件修改,添加到缓存区。
第二步:git commit ,提交更改,实际上把暂存去的内容,全部提交到master上,此时暂存器变空。
我们做个例子,看这个版本库到底是如何运作的?
我们修改前面的textfile.txt 里面的内容。
然后再工作区新添加一个文本文件 NEW.txt .
我们使用命令:git status ,看看Git的版本库有没有变化
提示我们,textfile.txt 被修改,而NEW.txt 没有被添加过,状态显示是 Untracked.
接下来把,textfile.txt 和NEW.txt 全部都 add 到版本库 ,然手再看一下状态,命令:git status
显示:添加一个新文件:NEW.txt。
textfile.txt 文件被修改。
看一下现在暂存区的状态:
所以,git add
命令实际上就是把要提交的所有修改放到暂存区(Stage),然后,执行git commit
就可以一次性把暂存区的所有修改提交到分支。
提交了以后,工作区就会变空,命令:git status 查看一下
那么此时版本库就是这样子:
5.Git的管理和修改
5.1. 为什么Git版本控制系统要比别的版本控制系统好用?
因为GIt跟踪和管理的是GIt的修改,而不是文件
5.2.什么是修改?
修改(modiify),在原有文本新加一行、需改一个字符、新建一个文件在Git都是修改。
5.3.为什么说GIt管理的是修改而不是文件呢?做个实验,修改textfile.txt文件,新添加一行文字。
添加到GIt.然后看一下状态:git status
再次修改textfile.txt 文件:
这次没有git add,直接提交我们看看:
看看当前状态:git status
可以看见第二第的修改并没有被提价上去,为什么?
回顾一下,我们刚刚的步骤,我们修改一个文件 然后git add,再次修改文件后没有git add,直接git commit 上去,前面我们说过了工作区和版本库的概念, git add
命令实际上就是把要提交的所有修改放到暂存区(Stage),而git commit 命令则是一次性把暂存区里面的东西一次性提交到分支(master),所以 git commit 只是负责把暂存区里面的东西提交,而第二次修改没有git add,也就没有把工作区的修改给添加到暂存区(Stage),因此就不会被提交。
提交后,用git diff HEAD -- readme.txt
命令可以查看工作区和版本库里面最新版本的区别:
所以确实第二次的修改没有被提交。
总结:每次修改后没有被git add 到暂存区,在 git add 之后就不会添加到分支(master)去。
5.4.撤销修改
是人就是难免会犯错误,在GIt中还有补救的方法,撤销修改。
你现在修改textfile.txt 文件后,你突然不想修改了怎么办?
使用命令:git status 看一看
在你看status 的时候,Git提示你可以用 git checkout --file 可以丢弃工作区的修改 。我们试试:
果然回到了原来的状态
git checkout -- file
命令中的--
很重要,没有--
,就变成了“切换到另一个分支”的命令,我们在后面的分支管理中会再次遇到git checkout
命令。
注意:git checkout -- textfile.txt 的意思是吧textfile.txt 文件的修改全部撤销,有两种情况:
第一种:从textfile.txt编辑后就没有被git add(添加到暂存区) 过,现在撤销就和版本库一模一样。
第二种:textfile.txt 修改后被添加到暂存区,又做了修改,现在撤销修改就回到添加到暂存区后的状态。
总之,就是让这个文件回到最近一次git commit
或git add
时的状态。
上面那个是在textfile.txt 修改后,没有添加到暂存区,但是如果修改完还添加到(git add)暂存区怎么办,按照上面的思路我们在看看:
Git同样告诉我们,用命令git reset HEAD <file>
可以把暂存区的修改撤销掉(unstage),重新放回工作区:
注意:git reset
命令既可以回退版本,也可以把暂存区的修改回退到工作区。当我们用HEAD
时,表示最新的版本。
我们在看看状态:git status
现在暂存器(stage)是干净的,但是工作区有修改,和我们预想的一样,也确实如此。
还记得我们如何把工作区还原到最近一次吗? 使用命令:git checkout -- file
再看看textfile.txt的内容。又回到最近一次状态
再次看看状态:git status
现在工作区没有被修改,暂存区也是空的。
5.5.删除文件
我们说过Git 检测是修改,而不是文件。删除也是一种修改。
我们试一试,新建一个文件 project.txt ,并提交到GIt
你想删除在Git的project.txt 文件,一般情况下,你通常直接在文件管理器中把没用的文件删了,或者用rm
命令删了:
那么,Git马上就回知道,你把project.txt 删除了,检测出版本库和工作区不一致。
现在你有两个选择,一是确实要从版本库中删除该文件,那就用命令git rm
删掉,并且git commit
:
现在文件就从版本库删除了。工作区同样也删除了。
另一种情况是删错了,因为版本库里还有呢,所以可以很轻松地把误删的文件恢复到最新版本:
使用命令:git checkout -- file
注意:git checkout
其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。
总结:命令git rm
用于删除一个文件。如果一个文件已经被提交到版本库,那么你永远不用担心误删,但是要小心,你只能恢复文件到最新版本,你会丢失最近一次提交后你修改的内容。
6.远程仓库(Github)
引出GIthub远程仓库
到目前为止,我们已经基本掌握了文件删除,恢复,提交,和Git版本控制系统的运作流程。
Git是分布式版本控制系统,同一个Git仓库,可以分布到不同的机器上。怎么分布呢?最早,肯定只有一台机器有一个原始版本库,此后,别的机器可以“克隆”这个原始版本库,而且每台机器的版本库其实都是一样的,并没有主次之分。
你肯定会想,至少需要两台机器才能玩远程库不是?但是我只有一台电脑,怎么玩?
其实一台电脑上也是可以克隆多个版本库的,只要不在同一个目录下。不过,现实生活中是不会有人这么傻的在一台电脑上搞几个远程库玩,因为一台电脑上搞几个远程库完全没有意义,而且硬盘挂了会导致所有库都挂掉,所以我也不告诉你在一台电脑上怎么克隆多个仓库。
实际情况往往是这样,找一台电脑充当服务器的角色,每天24小时开机,其他每个人都从这个“服务器”仓库克隆一份到自己的电脑上,并且各自把各自的提交推送到服务器仓库里,也从服务器仓库中拉取别人的提交。
完全可以自己搭建一台运行Git的服务器,不过现阶段,为了学Git先搭个服务器绝对是小题大作。好在这个世界上有个叫GitHub的神奇的网站,从名字就可以看出,这个网站就是提供Git仓库托管服务的,所以,只要注册一个GitHub账号,就可以免费获得Git远程仓库。
6.1新建远程仓库
由于你的本地Git仓库和GitHub仓库之间的传输是通过SSH加密的,所以在Github官网进行设置
第1步:创建SSH Key。在用户主目录下,看看有没有.ssh目录,如果有,再看看这个目录下有没有id_rsa
和id_rsa.pub
这两个文件,如果已经有了,可直接跳到下一步。如果没有,打开Git Bash,创建SSH Key:
使用命令:
ssh-keygen -t rsa -C "[email protected]"
你需要把邮件地址换成你自己的邮件地址,然后一路回车,使用默认值即可 ,然后也有提示先创建 .ssh目录的位置,以及其他一些信息。
如果一切顺利的话,可以在用户主目录里找到.ssh
目录,里面有id_rsa
和id_rsa.pub
两个文件,这两个就是SSH Key的秘钥对,id_rsa
是私钥,不能泄露出去,id_rsa.pub
是公钥,可以放心地告诉任何人。
第2步:登陆GitHub,打开“Account settings”,“SSH Keys”页面:
然后,点“Add SSH Key”,填上任意Title,在Key文本框里粘贴id_rsa.pub
文件的内容:
为什么GitHub需要SSH Key呢?因为GitHub需要识别出你推送的提交确实是你推送的,而不是别人冒充的,而Git支持SSH协议,所以,GitHub只要知道了你的公钥,就可以确认只有你自己才能推送。
当然,GitHub允许你添加多个Key。假定你有若干电脑,你一会儿在公司提交,一会儿在家里提交,只要把每台电脑的Key都添加到GitHub,就可以在每台电脑上往GitHub推送了。
最后友情提示,在GitHub上免费托管的Git仓库,任何人都可以看到喔(但只有你自己才能改)。所以,不要把敏感信息放进去。
如果你不想让别人看到Git库,有两个办法,一个是交点保护费,让GitHub把公开的仓库变成私有的,这样别人就看不见了(不可读更不可写)。另一个办法是自己动手,搭一个Git服务器,因为是你自己的Git服务器,所以别人也是看不见的。这个方法我们后面会讲到的,相当简单,公司内部开发必备。
确保你拥有一个GitHub账号后,我们就即将开始远程仓库的学习。
6.2.添加远程库
远程库其实和本地库的实质是一样的,而在GitHub创建一个Git仓库 ,并且让这两个仓库进行远程同步,这样,GitHub上的仓库既可以作为备份,又可以让其他人通过该仓库来协作。
首先,登陆GitHub,然后,在右上角找到“Create a new repo”按钮,创建一个新的仓库:
在仓库名中填入 Gitfile 然后点击“Create repository”按钮,就成功地创建了一个新的Git仓库:
创建成功后,Gitfile仓库是空的,GitHub告诉我们,可以从这个仓库克隆出新的仓库,也可以把一个已有的本地仓库与之关联,然后,把本地仓库的内容推送到GitHub仓库:
现在,我们根据GitHub的提示,在本地的Github仓库下运行命令 :
git remote add origin https://github.com/xxxx/Gitfile.git
把红色部分换成自己库的地址
添加后,远程库的名字就是origin
,这是Git默认的叫法,也可以改成别的,但是origin
这个名字一看就知道是远程库。
下一步,就可以把本地库的所有内容推送到远程库上:
使用命令: git push -u origin master
实际上是把当前分支master
推送到远程Github。
由于远程库是空的,我们第一次推送master
分支时,加上了-u
参数,Git不但会把本地的master
分支内容推送的远程新的master
分支,还会把本地的master
分支和远程的master
分支关联起来,在以后的推送或者拉取时就可以简化命令。
推送成功后就可以在github 新建的仓库中看到,和本地一样的文件。
从现在起,只要本地做了提交(git commit ) 就可以通过命令:
git push origin master. 推送到远程github的仓库(把本地master
分支的最新修改推送至GitHub,现在,你就拥有了真正的分布式版本库!)。
例子:现在我们新建一个text1.txt文件,提交到本地的版本库,并添加到分支master,通过推送看是否同步?
我们在本地做了了这些工作后。在Github 的仓库看一下,是否同步?
成功同步。
6.3克隆远程库
我们前面所讲的是。我们在本地先建立一个本地库,然后在GIthub建立一个远程库,然后把本地库的分支master 和远程库的分支master关联起来,以后如果想同步两个库只需要通过命令:git push origin master ,即可完成同步 。
现在假设我们是从头开始,我们先创建远程库,然后从远程库(Github)中同步到本地,完成同步。
第一步:登陆GIthub ,建立一个新的库命名为:Githubfile
我们勾选Initialize this repository with a README
,这样GitHub会自动为我们创建一个README.md
文件。创建完毕后,可以看到README.md
文件
注意Git仓库地址:
你也许还注意到,GitHub给出的地址不止一个,还可以用[email protected]:zGuangYuan/Githubfile.git
这样的地址。实际上,Git支持多种协议,默认的git://
使用ssh,但也可以使用https
等其他协议。
使用https
除了速度慢以外,还有个最大的麻烦是每次推送都必须输入口令,但是在某些只开放http端口的公司内部就无法使用ssh
协议而只能用https
。
现在我们已经把远程库创建好了,我们准备把它克隆到本地:
使用命令:git clone
进入本地看一下,已经能看到README.md 文件了
如果有多个人协作开发,那么每个人各自从远程克隆一份就可以了。
例子:把 工程 《1_LightControl》上传到Github
第一步:复制工程到克隆的到本地的文件夹内 GIthubfile。
第二步:把工程添加到暂存区
使用命令:git add <file>
第三步:添加到本地master分支上(提交)
使用命令:git commit -m "描述"
第四步:推送到远程库(不成功,看前面的密钥是否建立)
使用命令:git push origin master
成功,我们去Github官网看一看是否同步数据:
看看内容是否一致:
同步成功。
分支管理
7.1何为分支?
分支就像通道一样,不用的通道都能到达同一个终点,如果多人占用了一个通道,工作速度就会很慢,但是如果每个人都有一个分支(通道),他们就不会互相影响,高效率的完成自己的工作。
7.2.创建与合并分支
通过学习我们已经知道,我们每次提交(commit)了文件之后就会连成一条线,都会添加到一个分支(master),这个成为主分支,到目前为止,我们只有一个分支。HEAD
严格来说不是指向提交,而是指向master
,master
才是指向提交的,所以,HEAD
指向的就是当前分支。
一开始master分支是一条线,Git用master指向最新的提交,再用HEAD指向master,
就能知道当前所在分支和当前的提交。
例如:原本如下所示
每次提交master分支会向前移动一步:
就会变成如下:
再次提交一次 :git commit -m "D",就会如下所示
当我们新建了一个分支,link,Git就会新建一个指针link,指向和master 相同的提交,然后再把HEAD指向link,表示当前在link这条分支上。
注意,现在HEAD指向了link ,现在的提交和修改就是操作 link这个分支了。
比如现在我们提交一个新文件,link指针向前移动一步,而master指针不变。
那如果我把我的分支工作完成了,如何合并分支呢?
最简单的方法,就是直接把master
指向dev
的当前提交,就完成了合并:
合并完成后我们甚至可以删除分支link ,这样我们就剩下一条master分支了。
理论永远需要实践验证,我们实验看一看:
先介绍几条命令:
查看分支:git branch
创建分支:git branch <name>
切换分支:git checkout <name>
创建+切换分支:git checkout -b <name>
合并某分支到当前分支:git merge <name>
删除分支:git branch -d <name>
第一步:我们先创建分支link,然后切换到link(让HEAD指向link)分支上
git checkout
命令加上-b
参数表示创建并切换,相当于以下两条命令:
git branch link + git branck link.
第二步:使用:git branch 查看当前分支
git branch
命令会列出所有分支,当前分支前面会标一个*
号 。
我们在本地Githubfile文件夹,新建一个text1.txt 的文件,提交到link的分支上。
提交到link 分支上
现在link 的工作完成,切回到master分支上:
使用命令:git checkout master
切换回master
分支后,再查看一个text1.txt文件,刚才添加的内容不见了!因为那个提交是在dev
分支上,而master
分支此刻的提交点并没有变:
我们把link
分支的工作成果合并到master
分支上:
使用命令:git merge <name>
注意到上面的Fast-forward
信息,Git告诉我们,这次合并是“快进模式”,也就是直接把master
指向link
的当前提交,所以合并速度非常快。
当然,也不是每次合并都能Fast-forward
,我们后面会讲其他方式的合并。
合并完成后就可删除link了,其实就是删除一个指针,指针master 和 link 指的是同一个地方,所以可以删除一个。
7.3.分支合并冲突解决
合并分支不是什么情况下都能成功。我们用例子说明:
建立一个新分支 名为: link1,并切换到 link1 分支上。
接下来修改text1.txt的文本
在分支 link1 上提交 text1.txt 文件
切换到master分支上:
注意,切换到master分支上后,如果没有合并分支,看到的text1.txt就是以前的:
Git提示我们当前master 比远程的master 要超前一个提交,建议我们用 git push,把当地的提交同步到远程(检测到当地master 和Git仓库的master 不一致)。
再次修改text1.tex ,在master分支上提交:
提交text1.txt:
那么现在,在master 分支和 link1分支都有新的提交,如下所示:
这种情况下,就无法像上面一样使用 git merge 命令使用快速合并,只能试图把自己的修改合并起来,但这种合并就可能会有冲突,试试看:
Git 告诉我们,text1.txt 合并冲突,必须解决这个问题之后再次提交文件。
使用命令:git status 也可以告诉我们冲突文件:
此时我们直接查看 text1.txt 的内容:
Git用<<<<<<<
,=======
,>>>>>>>
标记出不同分支的内容,我们修改如下后保存:
修改text1.tex文本为:
再次提交:
现在 master 分支和 link1 分支,变成如下所示:
用带参数的git log
也可以看到分支的合并情况:
命令:git log --graph --pretty=oneline --abbrev-commit
删除 link1分支:
总结:
当Git无法自动合并分支时,就必须首先解决冲突(例如本例就是修改text1.txt的文本内容改成我们想要的,由此冲突解决)。解决冲突后,再提交(git add file),然后再次(git commit )提交,合并完成,完成之后就可以删除你不想要的分支(如link1)。
解决冲突就是把Git合并失败的文件手动编辑为我们希望的内容,再提交。
用git log --graph
命令可以看到分支合并图。
7.4分支管理策略
Git 在合并时通常都会选择 快进模式(Fast Forward),但是这种模式下,删除分支了以后就会丢失分支的信息,那如何保持删除的分支的信息呢?
做一个新的 提交(commit )就可以了。
在Git 中如果禁用快进模式(Fast Forward),Git 就会在合并(merge)时生成一个新的提交(commit),这样就可以在历史分支记录上看到分支信息。
采用 --no -ff 的方式合并分支(git merge):
接下来创建分支link,切换到分支link。
修改text1.tex文本,并在link分支做一个提交。
切回到master 分支:
准备合并link 分支,禁用 快进模式,使用 --no-ff 参数, 进行 git merge
合并后,我们用git log
看看分支历史:
命令:git log --graph --pretty=oneline --abbrev-commit
如果不用 Fast Forward 模式进行合并,合并后就如下:
分支策略:
在实际开发中,我们应该按照几个基本原则进行分支管理:
1.master
分支应该是稳定不变的,仅用于分支的合并,不要再上面做修改,在上面做修改,不仅导合并冲突,而且导致不稳定。
2.那在哪干活呢?干活都在link主分支上,也就是说,link分支是不稳定的,等到你想更新的时候再合并到master.
3.你的团队成员都可以在link分支上编辑,编辑完成提交到link就可以,一下简图简单描述团队关系:
7.5.Bug分支
在软件调试中,bug的修复非常常见和重要, 在Git中,由于分支是如此的强大,所以,每个bug都可以通过一个新的临时分支来修复,修复后,合并分支,然后将临时分支删除。
7.6 .多人协作
当你从远程仓库克隆时,实际上Git自动把本地的master
分支和远程的master
分支对应起来了,并且,远程仓库的默认名称是origin
。
要查看远程库的信息,用git remote
:
或者,用git remote -v
显示更详细的信息:
上面显示了可以抓取和推送的origin
的地址。如果没有推送权限,就看不到push的地址。
推送分支
master 也是一个分支,推送分支,就是把该分支上的所有本地提交推送到远程库。推送时,要指定本地分支,这样,Git就会把该分支推送到远程库对应的远程分支上 。
推送主分支:git push origin master.
推送link分支:git push origin link.
8.标签管理
发布一个版本时,我们通常先在版本库中打一个标签(tag),这样,就唯一确定了打标签时刻的版本。将来无论什么时候,取某个标签的版本,就是把那个打标签的时刻的历史版本取出来。所以,标签也是版本库的一个快照。
Git的标签虽然是版本库的快照,但其实它就是指向某个commit的指针(跟分支很像对不对?但是分支可以移动,标签不能移动),所以,创建和删除标签都是瞬间完成的。
在Git中打标签非常简单,首先,切换到需要打标签的分支上:
在master分支上使用命令:git tag <mane>
查看所有标签用命令:git tag
默认标签是打在最新提交的commit上的。
使用命令看历史记录:git log --pretty=oneline --abbrev-commit
如果上次应该打的标签忘了打怎么办?比如打"ready to merge" 这次版本为v0.9
只需要找到需要打标签的commit id ,id号为:227311a。
使用命令:git tag v0.9 227311a.
注意:标签不是按顺序排序的,而是按照字母排序。
使用命令:git show <tagname> 看详细信息
如何创建带说明的标签?
使用命令:git tag -a <name> -m <描述> <commit id>
例子:打包commit id 为 0ad0b67 也就是 “fix confilicts”为v0.8版本。
使用命令:git show <tagname> 看详细信息
打错标签怎么办?
当然也是也删除的
使用命令:git tag -d <tagname>
创建的标签不会自动推送到远程,存储在本地(当然也可以推送)。
需要推送标签到远程。
使用命令:git push origin <tagname>
一次性把未推送的全部推送到远程:
使用命令:git push origin --tag
此时如果还想删除标签,相对来说就麻烦一点,想要从本地删除,
使用命令:git tag -d <tagname>