Git自学与掉坑实录(五)
目录
Git自学与掉坑实录(一)
· 创建版本库
· 添加提交文件至版本库
Git自学与掉坑实录(二)
· 本地文件的修改与提交
· 多版本之间的切换
· 查看版本历史
· 忽略特殊文件
Git自学与掉坑实录(三)
· 工作区、暂存区、版本库的概念
· 进行到各个阶段管理(添加、删除、恢复、修改)文件的方法
Git自学与掉坑实录(四)
· 远程仓库
· Github的入门说明
· 参与开源项目
Git自学与掉坑实录(五)
· 管理(创建、合并、删除)分支
· 解决冲突
· Fast forward模式与禁用(是否显示合并信息)
· bug分支
· 功能分支
· 多人协作(查看信息、推送远程库、抓取)
Git自学与掉坑实录(六)
· 创建标签
· 删除标签(本地与远程)
Git自学与掉坑实录(七)
· 显示代码颜色
· 忽略文件与强制添加某些忽略文件
· 搭建Git服务器
<br />
十二、分支管理
Git里有一条默认分支"master分支"。"HEAD"指向"master分支","master分支"指向提交,因此"HEAD"指向的就是当前分支。
当提交时,Git用"master"指向最新的提交,"HEAD"指向"master"就能确定当前分支,以及当前分支的提交点。每次提交,"master分支"都会向前延伸,"HEAD"和"master"的指针随之向前移动,随着不断提交,"master分支"的线越来越长。
了解了这个概念,也就是了解分支管理的基础。分支管理十分便于协作开发,协作者可以创建多个分支,每个人在自己的分支上独立工作,不影响其他人,工作完成后再一次性合并到原来的分支上。
之前的章节我们也提到Git快速的版本切换,在分支的创建、切换、删除上也同样是分分钟搞定的,简而言之就是通过版本的指向,而不去改变工作区的内容。下面具体说说:
1.创建与合并分支
· 创建分支
输入命令$(创建并切换"dev分支")git checkout -b dev
;
我们创建一条新分支"dev分支",并改变"HEAD"的指向。此时工作区的文件没有任何变化,但是接下来版本库的提交和修改就是针对"dev分支"了。
最新一次提交后,"dev"的指针前进一步,"master"不变
git checkout -b
中的-b
表示创建并切换"dev分支"为当前分支,相当于两条命令:
输入命令$(创建"dev分支")git branch dev
;
输入命令$(切换"dev分支")git checkout dev
;
输入命令$(查看当前分支)git branch
;
"dev分支"为当前分支
git branch
会列出所有分支,并在当前分支前加"*"
于是我们对"wil.txt"文件随意修改点什么,并提交;
如图,修改提交到"dev分支"上
输入命令$(切换回"master分支")git checkout master
我们发现,"wil.txt"修改的内容不见了。
说明我们只是切换到了"master分支",而"master分支"此时的提交点没有变,因此我们还需要一步合并分支。
</br>
· 合并分支
输入命令$(将"dev分支"的最新修改合并到"master分支")git merge dev
合并成功
git merge
表示合并指定分支("dev分支")到当前分支。此时我们再查看"wil.txt"内容。
在合并过程中,我们看到了"Fast-forward",代表快进模式,所以速度很快。
</br>
· 删除分支
输入命令$(删除"dev分支")git branch -d dev
合并完成后,可以删除"dev分支",实际上就是把"dev"的指针删掉,此时我们只剩一条"master分支"。
通过分支推进项目的进程
输入命令$(查看当前分支)git branch
;
<br />
2.解决冲突
当新分支与"master分支"都有新的提交时,合并就会产生冲突。
比如我们再新建一个"feature1分支",并分别对同一文件进行修改。我们在"feature1分支"上对"wil.txt"文件进行修改并提交:
当指针从"feature1分支"切换回"master分支"时,Git自动提示我们,当前"master分支"比远程的"master分支"超前1个提交。
在"master分支"上也对"wil.txt"文件进行修改并提交:
这种情况下,Git就无法执行Fast-forward(快速合并)当新分支与"master分支"都有新的提交时,合并就会产生冲突。
我们试着把两个分支合并看看情况:
· 输入命令$(将"feature1分支"的最新修改合并到"master分支")git merge feature1
· 输入命令$git status
· 再来看看这时候的"wil.txt"长什么样:
输入命令$
cat wil.txt
Git用"<<<<<<<","=======",">>>>>>>"标记出不同分支的内容。我们在文档中修改后保存。
· 手动修改文件
可以直接打开"wil.txt",也可以输入命令$vi wil.txt
进行编辑,修改内容如下:
· 提交修改文件
· 输入命令$(分支的合并情况)
git log --graph --pretty=oneline --abbrev-commit
· 输入命令$(删除"feature1分支")
git branch -d feature1
· 完成。
<br />
3.分支管理策略
通常合并分支时,如果Git使用Fast forward模式,删除分支后,会丢掉分支合并信息。
如果要强制禁用Fast forward模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息。
输入命令$(禁用Fast forward):git merge --no-ff -m "merge with no-ff(描述)" dev(分支名)
--no-ff
表示强制禁用Fast forward,使用普通模式合并。因为会创建一个新的commit,所以加上-m参数,把commit描述写进去。
输入命令$(查看分支历史):git log --graph --pretty=oneline --abbrev-commit
当前文档内容即"dev分支"修改的内容,并且可以看到分支的合并历史
总结一下,"master分支"是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活。"dev分支"(或其他新建分支)是不稳定的,干活都在"dev分支"上。每个人都有自己的分支,时不时地往dev分支上合并。
当版本发布时,先把"dev分支"合并到"master分支"上,再在"master分支"发布版本。而加上--no-ff
参数就是为了查看历史时,可以看到每一个分支的合并记录。
<br />
4.Bug分支
软件开发中,bug就像家常便饭一样。有了bug就需要修复,在Git中,由于分支是如此的强大,所以,每个bug都可以通过一个新的临时分支来修复,修复后,合并分支,然后将临时分支删除。
但实际工作场景很可能会出现这种情况,你急需修复一个bug,但是该分支上进行的工作还没有结束无法提交。这时候我们需要把分支上正在进行的工作储藏起来。
· 储存当前工作分支内容("dev分支")
输入命令$(储藏当前工作现场)git stash
;
再用$git status
查看工作区,应该是干净的(除非有没有被Git管理的文件)。
· 修复出错分支("dev分支")
确定在哪个分支上修复,就在那个分支创建临时分支。假设需要在"master分支"修复:
输入命令$git checkout master
;
输入命令$(切换创建"issue-101临时分支")git checkout -b issue-101
。
修复bug,改写"wil.txt"内容并提交:
输入命令$git add wil.txt
;
输入命令$git commit -m "fix bug 101"
。
修复完成后,切换到"master分支",完成合并,最后删除"issue-101临时分支":
输入命令$git checkout master
;
输入命令$git merge --no-ff -m "merged bug fix 101" issue-101
;
输入命令$git branch -d issue-101
。
· 回到之前的工作分支("dev分支")
输入命令$git checkout dev
;
输入命令$git status
;
" On branch dev
nothing to commit (working directory clean) "
说明工作区是干净的。
输入命令$(查看stash)git stash list
;
" stash@{0}: WIP on dev: 6224937 add merge "
说明"stash@{0}"的工作内容还在,Git把stash内容存在某个地方,需要把它恢复一下。
· 恢复到工作分支的场景("dev分支")
a.输入命令$(恢复后,stash内容并不删除)git stash apply
;
输入命令$git stash drop
b.输入命令$(恢复的同时把stash内容也删了)git stash pop
再次输入命令$(查看stash)git stash list
;
就看不到任何stash内容了。
*当有多个stash时,我们可以选择恢复制定的stash。
输入命令$(恢复后,"stash@{0}"的内容并不删除)git stash apply stash@{0}
;
<br />
5.Feature分支
在每个项目中,一定会不断增加新功能,所以每添加一个新功能就新建一个"feature分支"。在上面进行开发、合并、删除等操作。
举例,
· 开发代号为"Vulcan"的新功能。
输入命令$(切换并创建"feature-vulcan分支")git checkout -b feature-vulcan
;
输入命令$(添加修改文件并提交)git add vulcan.py
&git commit -m "add feature vulcan"
;
输入命令$(切回"dev分支")git checkout dev
。
· 要求销毁新功能
输入命令$(删除"feature-vulcan分支")git branch -d feature-vulcan
;
"error: The branch 'feature-vulcan' is not fully merged.
If you are sure you want to delete it, run 'git branch -D feature-vulcan'."
由于"feature-vulcan分支"还未合并(merge),删除将丢失分支上的修改。如果需要强行删除,输入命令git branch -D feature-vulcan
。
· 删除成功
<br />
6.多人协作
当你从远程仓库克隆时,实际上Git自动把本地的"master分支"和远程的"master分支"对应起来了,并且,远程仓库的默认名称是"origin"。
· 查看远程库信息
输入命令$(查看远程库的信息)git remote
输入命令$(查看远程库的显示详细信息)git remote -v
· 推送分支
输入命令$(把"master分支"的所有本地提交推送到远程库)git push origin master
输入命令$(把"dev分支"的所有本地提交推送到远程库)git push origin dev
master分支是主分支,因此要时刻与远程同步;
dev分支是开发分支,团队成员都需要在上面工作,所以也需要与远程同步;
bug分支只用于在本地修复bug,就没必要推到远程了,除非老板要看看你每周到底修复了几个bug;
feature分支是否推到远程,取决于你是否和你的小伙伴合作在上面开发。
总之,就是在Git中,分支完全可以在本地自己藏着玩,是否推送,视你的心情而定!
· 抓取分支
多人协作时,大家都会往"master分支"和"dev分支"上推送各自的修改。
假装你是一个路人A,在另一台电脑(注意要把SSH Key添加到GitHub)或者同一台电脑的另一个目录下克隆。
输入命令$(克隆Github上的项目)git clone git@github.com:Github用户名/learngit.git
此时路人A从远程库克隆时,默认情况下只能看到本地的"master分支"。
输入命令$git branch
现在,路人A要在"dev分支"上开发,必须创建远程"origin"的"dev分支"到本地。
输入命令$(创建本地"dev分支")git checkout -b dev origin/dev
接下来,路人A可以在"dev分支"上继续修改,然后,时不时地把"dev分支"push到远程。
输入命令$(创建本地"dev分支")git commit -m "add /usr/bin/env"
当路人A和你一起修改了同样的文件并推送到"orgin",后提交的小伙伴会推送失败,因为两个提交会有冲突。
这时候,我们需要先从"origin/dev"将最新的提交git pull
下来,然后在本地合并,解决冲突再推送。
输入命令$git pull
;
"no tracking information"说明本地分支和远程分支的链接关系没有创建
git pull
也失败了,因为没有创建本地"dev分支"与远程"origin/dev分支"的链接,根据提示设置:
输入命令$git branch --set-upstream dev origin/dev
;
再次输入命令$git pull
。
合并git pull
下来的最新提交,需要手动解决合并冲突,上面有介绍过方法。解决后,再推送到远程库"origin/dev分支"。
<br /><br />
小结
$
git branch
#查看分支。
$git branch filename
#创建"filename分支"。
$git checkout filename
#切换"filename分支"。
$git checkout -b filename
#上面两条的结合,创建并切换"filename分支"。
$git merge filename
#合并"filename分支"到当前分支。
$git branch -d filename
#删除"filename分支"。
$git branch -D filename
#删除未合并过的"filename分支"。
$git log --graph --pretty=oneline --abbrev-commit
#查看分支合并图。
$git merge --no-ff -m "描述" 分支名
#表示用普通模式合并,合并后的历史有分支,能看出来曾经做过合并;而fast forward合并就看不出来曾经做过合并。
$ls
#查看当前目录内的文件。
$git remote
#查看远程库的信息。
$git remote -v
#查看远程库的显示详细信息。
$git push origin master
#把"master分支"的本地内容提交推送到远程库。
$git push origin "branch-name"
#把"xx分支"的本地内容提交推送到远程库。
$git pull
#把"xx分支"的本地内容提交推送到远程库。如果结果提示"no tracking information",说明本地分支和远程分支的链接关系没有创建,输入命令git branch --set-upstream "branch-name" origin/"branch-name"
。
<br /><br /><br /><br /><br /><br /><br />
主要参考:
<br /><br /><br /><br />