分支的用处:
就是你与你的同事一起完成一个项目时,你可以自己创建一个分支,这个分支你可以什么时候写代码或者提交都可以,处理完成后你可以将这个分支汇到大的分支上
个人理解,创建一个分支后,其实就是将工作区的内容复制一封到了另一个区域,比如之前存在主分支叫master,现在复制了一份内容后,存在另一个分支,叫dev,这个分支的内容和主分支一样,可以在dev分支上改动自己想做的内容,然后改动完成后,将其合并到主分支master上
一、创建与合并分支:
首先我们创建一个名字叫dev的分支,然后切换到dev分支(cd进入当前learngit文件夹内):
git checkout命令加上-b参数表示创建并切换,相当于以下两条命令:
git branch dev
git checkout dev
然后,用git branch命令查看当前分支:
git branch命令会列出所有分支,当前分支前面会标一个*号,目前的分支就是dev。
然后,我们就可以在dev分支上正常提交,比如对readme.txt做个修改,加上一行:
Creating a new branch is quick.
然后提交:
现在,dev分支的工作完成,我们就可以切换回master分支:
切换回master分支后,我们再去查看下readme.txt文件,刚才添加的内容不见了!
因为那个提交是在dev分支上,而master分支此刻的提交点并没有变
现在,我们把dev分支的工作成果合并到master分支上:
git merge命令用于合并指定分支到当前分支。合并后,再查看readme.txt的内容,就可以看到,和dev分支的最新提交是完全一样的。
合并完成后,就可以放心地删除dev分支了:
删除后,查看branch,就只剩下master分支了:
因为创建、合并和删除分支非常快,所以Git鼓励你使用分支完成某个任务,合并后再删掉分支,这和直接在master分支上工作效果是一样的,但过程更安全。
小结
Git鼓励大量使用分支:
查看分支:git branch
创建分支:git branch <name>
切换分支:git checkout <name>
创建+切换分支:git checkout -b <name>
合并某分支到当前分支:git merge <name>
删除分支:git branch -d <name>
二、解决冲突
我认为的冲突就是:新创建分支后,对两个分支的同一个内容修改保存后,用git add 和 gitcommit提交后,当融合一个分支的时候,会出现冲突,因为两个分支的同一个内容都改了。
上一个实例:
准备新的feature1分支,继续我们的新分支开发:
修改readme.txt最后一行,改为:
Creating a new branch is quick AND simple.
这样readme.txt的内容就变为了:
然后在feature1分支上提交:
然后切换到master分支:
在master分支上把readme.txt文件的最后一行改为:
Creating a new branch is quick & simple.
这样master分支上的readme.txt文件就变成了:
提交:
现在,master分支和feature1分支各自都分别有新的提交,变成了这样:
这种情况下,Git无法执行“快速合并”,只能试图把各自的修改合并起来,但这种合并就可能会有冲突,我们试试看:
果然冲突了!Git告诉我们,readme.txt文件存在冲突,必须手动解决冲突后再提交。git status也可以告诉我们冲突的文件:
我们可以打开readme.txt文件来看下现在是什么内容:
Git用<<<<<<<,=======,>>>>>>>标记出不同分支的内容,我们修改如下后保存:
再提交:
用带参数的git log也可以看到分支的合并情况:
最后,删除feature1分支:
工作完成。
小结
当Git无法自动合并分支时,就必须首先解决冲突。解决冲突后,再提交,合并完成。
解决冲突就是把Git合并失败的文件手动编辑为我们希望的内容,再提交。
用git log --graph命令可以看到分支合并图。
三、分支管理策略
通常,合并分支时,如果可能,Git会用Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。
如果要强制禁用Fast forward模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息。
下面我们实战一下--no-ff方式的git merge:
首先,仍然创建并切换dev分支:
修改readme.txt文件,并提交一个新的commit:
以上是我们在dev分支上的操作;下面我们切换回master分支:
准备合并dev分支,请注意--no-ff参数,表示禁用Fast forward:
因为本次合并要创建一个新的commit,所以加上-m参数,把commit描述写进去。
合并后,我们用git log看看分支历史:
可以看到,不使用Fast forward模式,merge后就像这样:
分支策略
在实际开发中,我们应该按照几个基本原则进行分支管理:
首先,master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;
那在哪干活呢?干活都在dev分支上,也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本;
你和你的小伙伴们每个人都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了。
小结
Git分支十分强大,在团队开发中应该充分应用。
合并分支时,加上--no-ff参数就可以用普通模式合并,合并后的历史有分支,能看出来曾经做过合并,而fast forward合并就看不出来曾经做过合并。
四、Bug分支
假如你现在正在dev分支上干活,但是接到通知在master分支上有一个bug需要处理。因为dev分支上的活还没有干完,无法提交,但是master分支上的bug需要马上处理。
这个就是这节所需要掌握的内容:隐藏现有工作区还未提交的内容,然后去其他分支处理bug:创建新的分支,在新的分支上解决内容,然后融合到master分支上。
举一个实例:
比如,我们在dev分支上修改readme.txt,添加保存了最后一句话:
这个时候因为还没有干完活,没有git add作提交,
这个时候我们git status,可以看到readme.txt属于未提交的状态;我们用git stash将这个工作区的内容隐藏起来:
这个时候再来用git status来查看下:
可以看到工作区是干净的,因为我用git stash隐藏了起来
现在来修复bug。我们知道了bug在分支master上,那么我们就在master分支上修复,就从master分支上创建临时分支:
现在修复bug,需要把“Git is free software ...”改为“Git is a free software ...”,然后提交:
修复完成后,切换到master分支,并完成合并:
这样的话bug就处理好了,分支issue-101融合到master上了,
接着我们去dev分支上干完剩下的活。我们转到dev分支上,然后git status查看下情况:
这个是和我们一开始隐藏后查看的情况一样,工作区还是干净的,我们用git stash list来查看下是什么情况:
工作现场还在,Git把stash内容存在某个地方了,但是需要恢复一下,有两个办法:
一是用git stash apply恢复,但是恢复后,stash内容并不删除,你需要用git stash drop来删除;
另一种方式是用git stash pop,恢复的同时把stash内容也删了。
我们使用 git stash pop 来试下:
我们再来用git stash list来查看下是否有隐藏的内容:
可以看到已经没有隐藏的内容了。
我们再来打开readme.txt来看下内容:
这个就是一开始干活自己编辑的内容,现在看到这个,就说明隐藏的内容已经回来了。
小结
修复bug时,我们会通过创建新的bug分支进行修复,然后合并,最后删除;
当手头工作没有完成时,先把工作现场git stash一下,然后去修复bug,修复后,再git stash pop,回到工作现场。
五、Feature分支
假如你创建一个Feature分支,在上面开发了一个功能,完了以后等到想合并Feature分支到dev分支上的时候,这个时候突然改变需求:需要删除Feature分支。
这个就是这节需要掌握的内容:强行删除一个没有被合并过的分支。
软件开发中,总有无穷无尽的新的功能要不断添加进来。
添加一个新功能时,你肯定不希望因为一些实验性质的代码,把主分支搞乱了,所以,每添加一个新功能,最好新建一个feature分支,在上面开发,完成后,合并,最后,删除该feature分支。
现在,你终于接到了一个新任务:开发代号为Vulcan的新功能。
于是准备开发:
开发的文件是vulcan.txt:
然后我们git add和git commit提交:
切回dev分支,准备把feature-vulcan分支合并到dev分支上:
但是,还没合并的时候,现在不需要合并了,且需要销毁feature-vulcan分支:
但是我们看到,用我们之前学过的git branch -d 是销毁不掉的,提示是feature-vulcan这个分支还没有被完全合并,我觉得这样提醒是合理的,因为我们创建了这个feature-vulcan分支,如果就这样常规动作就销毁这个分支,我们很容易就在融合这个分支前就销魂这个分支而导致数据丢失,这个算是提醒,而且也说了,如果真的想删除,运行git branch -D,
现在我们强行删除:
小结
开发一个新feature,最好新建一个分支;
如果要丢弃一个没有被合并过的分支,可以通过git branch -D <name>强行删除。
六、多人协作
这一章讲述的是关于在项目中工作的有关情景,包括推送本地仓库到远程仓库,还包括当你和你的同事都在相同的分支上完成项目,然后推送到远程的时候,遇到了冲突
这一节所必须掌握的内容是:1、推送本地仓库到远程仓库;2、抓取分支
当从远程仓库克隆时,实际上就是把本地的master分支和远程仓库的master分支对应起来,且,远程仓库的默认名称是origin。
要查看远程库的信息,用git remote:
或者用git remote -v显示更详细的信息:
上面显示了可以抓取(fetch)和推送(push)的origin的地址(这个地址是我在前面学习的课程中建立的)。如果没有推送权限,就看不到push的地址。
推送分支
推送分支,就是把该分支上所有的本地提交推送到远程库。推送时,要指定本地分支,这样Git就会把你指定的本地分支推送到远程库中对应的远程分支上:
按我的理解,这条指令中,origin是远程仓库的名字,master是本地仓库的名字。所以在这条指令中,必须要有远程仓库和本地仓库,这样才可以对应起来,把本地仓库的内容推到远程仓库中去。
我的远程仓库在GitHub上,可以看到,更新已经推上去了:
但是,并不是一定要把本地分支往远程推送,那么,哪些分支需要推送,哪些不需要呢?
master分支是主分支,因此要时刻与远程同步;
dev分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步;
bug分支只用于在本地修复bug,就没必要推到远程了,除非老板要看看你每周到底修复了几个bug;
feature分支是否推到远程,取决于你是否和你的小伙伴合作在上面开发。
抓取分支
多人协作的时候,大家都会往远程仓库中的master和dev分支上推送各自的修改,
现在,模拟一个你的小伙伴,可以在另一台电脑(注意要把SSH Key添加到GitHub)或者同一台电脑的另一个目录下克隆,
现在我就在同一台电脑上,找下别的目录(C:\Users\Administrator\gitskills),来克隆一下来自远程端的内容到这个别的目录中:
去相关的目录下,可以看到learngit文件夹已经到了gitskills中(之前gitskills中只有README.md文件)。
中间出现了一个小插曲:
在上面我们用git remote -v来查看远程仓库的具体信息,我们看到的是github.com后面是/,但是,我使用了这个/,git竟然找不到远程仓库:
可以看到,上面两个截图的远程地址,差别只是在一个是冒号,另一个是/。/这个无法使用,所以我们今后只能用github.com后面是冒号。
当你的小伙伴从远程库clone时(也就是我在同一个电脑的另一个目录下模拟的),默认情况下,你的小伙伴只能看到本地的master分支。不信可以用git branch命令看看:
这段按我的理解是,master分支是本地目录默认的,所以也就只能看到master分支。
现在,你的小伙伴要在dev分支上开发,就必须创建远程origin分支到本地,于是他用这个命令创建本地dev分支:
这之中出现了一个小问题,廖老师的网站是这样写的:
所以一开始我也是这样写的,但是怎么创建都创建不了:
后来我想,其实我也想到我在GitHub上没有origin/dev分支,我想我有learngit仓库,我也就又试了下这个:
也是出现了相同的结果。后来我就想,我在远端只有一个origin,我就只写了这个,没有在后面带上斜杠以及任何东西,就创建成功了,我想廖老师所说的那样的情况,是因为廖老师origin上有dev分支。
然后,小伙伴就可以在dev上继续修改(在此添加了新的内容env.txt),保存,然后,把dev分支push到远程:
这样我的小伙伴已经推送完了他的修改。现在就该我了,我就在我之前所在的目录(learngit)中,做一个同样的修改(增加env.txt):
修改完成后,我也做同样的提交并且推送:
我试了好几次,都是推送成功,不知道怎么才能做出因冲突而推送失败的操作。
那就继续按着老师所说的内容继续下去:
推送失败,因为你的小伙伴的最新提交和你试图推送的提交有冲突,解决办法也很简单,Git已经提示我们,先用git pull把最新的提交从origin/dev抓下来,然后,在本地合并,解决冲突,再推送:
git pull
There is no tracking information for the current branch.
Please specify which branch you want to merge with.
See git-pull(1) for details.
git pull <remote> <branch>
If you wish to set tracking information for this branch you can do so with:
git branch --set-upstream-to=origin/<branch> dev
git pull也失败了,原因是没有指定本地dev分支与远程origin/dev分支的链接,根据提示,设置dev和origin/dev的链接:
git branch --set-upstream-to=origin/dev dev
Branch 'dev' set up to track remote branch 'dev' from 'origin'.
再pull:
git pull
Auto-merging env.txt
CONFLICT (add/add): Merge conflict in env.txt
Automatic merge failed; fix conflicts and then commit the result.
这回git pull
成功,但是合并有冲突,需要手动解决,解决的方法和分支管理中的解决冲突完全一样。解决后,提交,再push:
git commit -m "fix env conflict"
[dev 57c53ab] fix env conflict
git push origin dev
Counting objects: 6, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (6/6), 621 bytes | 621.00 KiB/s, done.
Total 6 (delta 0), reused 0 (delta 0)
To github.com:michaelliao/learngit.git
7a5e5dd..57c53ab dev -> dev
因此,多人协作的工作模式通常是这样
首先,可以试图用git push origin <branch-name>推送自己的修改;
如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并;
如果合并有冲突,则解决冲突,并在本地提交;
没有冲突或者解决掉冲突后,再用git push origin <branch-name>推送就能成功!
如果git pull提示no tracking information,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream-to <branch-name> origin/<branch-name>。
这就是多人协作的工作模式,一旦熟悉了,就非常简单。
小结
查看远程库信息,使用git remote -v;
本地新建的分支如果不推送到远程,对其他人就是不可见的;
从本地推送分支,使用git push origin branch-name,如果推送失败,先用git pull抓取远程的新提交;
在本地创建和远程分支对应的分支,使用git checkout -b branch-name origin/branch-name,本地和远程分支的名称最好一致;
建立本地分支和远程分支的关联,使用git branch --set-upstream branch-name origin/branch-name;
从远程抓取分支,使用git pull,如果有冲突,要先处理冲突。
以上是我看廖雪峰老师的网站,然后做的学习摘抄,无意侵犯老师作品,如有侵犯,我会删除。