四、分支管理
分支的存在,极大的强化了不同开发者的协作管理,在一个功能的开发过程中,可以在一个单独的分支上完成,这样不影响主分支的开发,待功能完成后再将分支的内容合并到主分支。
每次提交到分支,Git都会把它们串成一条时间线,这条时间线就是一个分支,只不过默认只有master主分支。HEAD
严格来说不是指向提交,而是指向master
,master
才是指向提交的,所以,HEAD
指向的就是当前分支。
一开始的时候,只有master
分支,Git用master
指向最新的提交,再用HEAD
指向master
分支,就能确定当前分支,以及当前分支的提交点:
每次提交,master
分支都会向前移动一步,这样,随着你不断提交,master
分支的线也越来越长。
当我们创建新的分支,例如dev
时,Git新建了一个指针叫dev
,指向主分支master
相同的提交,当我们切换分支时,再把HEAD
指向dev
,就表示当前分支在dev
上:
Git创建一个分支很快,除了增加一个dev
指针,改变HEAD
的指向,工作区的文件都没有任何变化!
不过,从现在开始,对工作区的修改和提交就是针对dev
分支了,比如新提交一次后,dev
指针往前移动一步,而master
指针不变:
假如我们在dev
上的工作完成了,就可以把dev
合并到master
上。Git怎么合并呢?最简单的方法,就是直接把master
指向dev
的当前提交,就完成了合并:
所以Git合并分支也很快!就改改指针,工作区内容也不变!
合并完分支后,甚至可以删除dev
分支。删除dev
分支就是把dev
指针给删掉,删掉后,我们就剩下了一条master
分支:
4.1分支管理
(1)创建分支
git branch <分支名>
:创建新分支
(2)切换分支
git switch <分支名>
git checkout <分支名>
(3)创建并切换分支
git checkout -b <分支名>
:创建并切换分支(旧版本)
git switch -c <分支名>
:(推荐使用)
(4)删除分支
git branch -d <本地分支名>
(5)查看分支
git branch
:默认查看本地分支(当前所在分支前加*)
git branch -a
:查看本地、远程分支(远程分支为红色)
(6)合并分支到当前分支
git merge <分支名>
4.2 分支合并
我们用一首诗来进行举例:
累土以成九仞
跬步终至千里
振翅云顶之上
极目星辰大海
此时master分支上的README.md为上述状态。现在我们新建分支test1。那么新分支此时与master分支指向一致。接下来我们切换到test1分支上,修改第一句话为:为山九仞,功亏一篑,然后提交到分支。接下来切回master分支,此时master分支因为没有合并,依然为原始状态,修改第一句话为:千里之行始于足下。接下来我们合并test1分支
git merge test1
#Auto-merging test.txt
#CONFLICT (content): Merge conflict in test.txt
#Automatic merge failed; fix conflicts and then commit the result.
可以看到自动合并失败,原因是两个分支都对同一处文件进行了修改,虽然合并勉强完成,但在文件中已经显示了冲突。系统最后一句提示我们:“先手动解决冲突,再重新commit”。
下图中git已经为我们自动展示了冲突内容,Git用<<<<<<<
,=======
,>>>>>>>
标记出不同分支的内容,即使冲突地方很多,也是一一显示的。如果我们以 master分支的修改为主,就保留“千里之行始于足下”,其余内容删去(包括《 、》、=、)。同理,如果要保留test分支的修改,就保留“为山九仞,功亏一篑”,其余内容删去。
修改完毕后,在master
分支上git commit -am "message"
重新提交修改,然后git status
发现,冲突已经解决,不需要我们再次合并了。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iq3RBOba-1654005954050)(E:\李国瑞\云顶书院\博客\git-image\fix conflict.png)]
用带参数的git log
也可以看到分支的合并情况:
git log --graph --pretty=oneline --abbrev-commit
当Git无法自动合并分支时,就必须首先解决冲突。解决冲突后,再提交,合并完成。
解决冲突就是把Git合并失败的文件手动编辑为我们希望的内容,再提交。
用
git log --graph
命令可以看到分支合并图。
4.3 分支管理策略
4.3.1 Fast Forward,FF
作用在,只有一个分支A和主分支master,当分支A开始开发时,主分支保持分支A创建时的进度不变。
4.3.2 3 way
当分支A提交了commit A1时,主分支master也提交了commit m1,这样在主分支合并分支A时,会生成一个新的commit m2,commit m2的parents是分支A的commit A1和master的commit m1。
git merge --no-ff -m "merge with no-ff" dev
--no-ff
表示禁用Fast Forward
;因为合并要创建新的commit
,所以要加-m
。
4.3.3 Bug分支
在团队协作开发时,bug总是层出不穷的。在Git中,修复Bug可以通过新建一个临时分支来修复,修复后,合并分支,然后将临时分支删除。
情况一:此时你正在dev分支上开发,突然接到一个代号为326的bug急需修复,而且必须在2小时内修复完毕。于是你想到要建一个分支issue-326
来修复它,但是你目前在dev分支上的工作还没提交,且需要10h才能完成,而且工作没有完成无法提交。于是你必须把工作现场保存起来,等到修复bug后再恢复现场。
git stash
git stash
:备份当前工作区的内容,保存到Git 栈中,从最近的一次commit中读取相关内容
可以看到,虽然还没有提交,但通过git stash
保存后,工作目录是干净了(除非有没有被Git管理的文件)。而且,dev分支上你还没做完的文件自动退回到上次commit时的状态。
修复bug首先确定在哪个分支进行修复,如果bug在master分支,就从master分支创建临时分支issue-326
。待bug修复完毕后回到master分支,对issue-326
进行合并。
之后回到dev
分支,需要恢复我们之前stash
保存的内容。
查看stash列表:git stash list
恢复stash:
- 按指定的序号恢复:
git stash apply stash@{0}
git stash pop
:从git栈中获取到最近一次stash进去的内容,恢复工作区的内容。恢复之后,会删除栈中对应的stash。git stash apply
:从git栈中获取到最近一次stash进去的内容,恢复工作区的内容。
清空git栈:git stash clear
移动commit:
虽然在master分支上修复了bug,但dev分支也是基于master分支创建的,所以我们需要将master上针对bug的修改移动到dev分支上。master上的commit id为:4aa4ee2
git cherry-pick <commit>
不过这里我测试失败了,看来实际操作起来还是有一定难度。
4.3.4 Feature
开发一个新功能时,为了不把主分支搞乱,最好新建一个feature分支,在其上开发完后进行合并,最后删除。但合并前接到新功能取消的命令,只好删除feature分支。
当删除未经合并的分支时,会提示需要强行删除,使用大写的-D
参数
git branch -D <feature-name>
4.4 多人协作
当从远程仓库克隆时,Git自动把本地的master分支和远程的master分支关联起来,远程仓库的默认名称是origin。
查看远程仓库信息:
1:git remote
:返回远程仓库的名称
2:git remote -v
:显示详细信息,显示可以抓取和推送的origin
地址,如果没有推送权限,就看不到push地址。
删除关联的远程仓库:git remote rm origin
**推送分支:**将本地的分支上的所有commit推送到远程仓库的某个分支
git push <远程主机名> <本地分支名> <远程分支名>
git push origin master
若远程分支被省略,默认将本地分支推送到与之存在追踪关系的远程分支
git push origin
若省略本地分支名,相当于删除远程分支,因为上传了一个空的分支。更多用法请参照git push。
但是并不是所有本地分支都要往远程推送。
- master是主分支,时刻与远程同步
- dev分支是开发分支,团队的所有成员都需要在上面工作,所以也需要与远程同步。
- bug分支只用于在本地修复bug,没必要推送到远程
- feature分支是否推送到远程分支取决于团队是否在feature分支上工作。
本地仓库拉取远程分支(前提是该远程分支存在)
git checkout -b dev origin/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 remote add <name> <url>
:关联名为name
的远程仓库
git remote rm origin
:删除已关联的名为origin
的远程仓