4、分支管理
(1)创建自己的分支,别人看不到,还继续在原来的分支上正常工作,而你在自己的分支上干活,直到开发完毕后,再一次性合并到原来的分支上,既安全又不影响别人工作。
(2)每次commit ,Git会把它们串成一条时间线,这条时间线就是一个分支。目前在Git里只有1条时间线,称为主分支,即 master分支;HEAD严格来说不指向提交,而是指向master,而master才指向提交,所以HEAD指向的是当前分支。
(3)当我们创建新的分支,例如dev时,Git新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,就表示当前分支在dev上;
从现在开始,针对工作区的修改和提交就是针对 dev 分支了,比如提交一次之后,dev指针往前移动一步,而master指针不变;
等到我们在 dev 上完成工作后,就可以把 dev 合并到 master上,Git直接把 master 指向dev的当前提交,就完成了合并;
合并之后,还可以删除 dev 分支,也就是把 dev 指针删掉,这样就只剩下一条 master 分支。
(4)使用 git checkout -b dev 就可以创建 dev 分支并转向dev分支,相当于 git branch dev,然后 git checkout dev;可以使用 git branch 查看当前存在的分支,命令会列出所有分支,当前分支前加 * ;在修改文件内容之后,我们可以通过命令 git checkout master 切换分支,也就是转向 master 分支,可以发现改动内容并没有生效;最后,还可以通过 git merge dev 将master分支指向dev,实现合并(这种合并方式称为 Fast-forward,即快进模式)。
不再使用分支时,可以用 git branch -d dev 删除分支。
(5)当我们创建一个分支feature1,并在分支上做了修改①之后,切换回master分支,做了不一样的更改②,这时候我们使用 git merge feature1时会出现冲突,表明两次修改不一样,无法合并;Git 会用 <<<<<<<,=======,>>>>>>>标记处不同分支的内容;这时我们再次修改内容,再提交,master分支和feature1分支就会变成如下图所示的情况,也就解决了冲突,最后我们再删除分支feature1。
使用 git log --graph 可以查看分支合并情况,为了简化输出,常在后面加上 --pretty=oneline --abbrev--commit 参数。
(6)同样是创建分支 dev ,修改提交之后我们使用 git merge --no-ff -m "修改内容" dev ,也可以合并分支,而参数 --no-ff 表示禁用Fast forward,合并之后我们使用 git log 查看分支历史,可以看到分支合并的情况;而当前 master 和 dev 也并没有合并。
(7)实际开发中的策略:首先,master 分支应该非常稳定,仅用来发布新版本,平时不在上面干活;而平时的修改都在 dev 分支上进行,也就是说,dev 分支是不稳定的,到某个时候,比如版本要发布了,再把 dev分支合并到 master 上,在master上发布;小组里的成员每个人都在 dev 上干活,每个人都有自己的分支,时不时往 dev 分支上合并。
(8)修复bug时,我们会通过创建新的bug分支进行修复,然后合并,最后删除;当需要修复bug同时手头工作没有完成时,我们可以先通过 git stash 一下,也就是储藏工作现场,然后再去修复bug;修复完成后,在通过 git stash pop 回到工作现场;如果储藏了多个工作现场,可以先用 git stash list 查看储藏的内容,再通过 git stash apply stash@{对应的数字} 返回对应的现场,注意还要使用 git stash drop stash@{对应的数字} 将其从stash中删除。
【注:创建分支dev,如果想要stash,必须将修改的内容先 add,这时转到其他分支,无法看到修改的内容;但是可以在其他分支使用 git stash pop 将原工作现场还原,此时再转回到dev发现也已经还原了;在没有cmmit的前提下,也可以在其他分支将dev分支删除。】
(9)软件开发中会遇到很多新功能,为了不把主分支搞乱,每添加一个新功能,最好新建一个feature分支,在上面开发完成后,再合并,最后删除feature分支。如果在分支没有合并时想要强行删除分支,需要使用 git branch -D 分支名 命令,注意这里使用的是大写的-D参数。
(10)当从远程克隆时,实际上Git自动将本地master分支和远程master分支对应起来,远程仓库默认名称为 origin ;使用命令 git remote 查看远程仓库信息,在后面加上参数 -v 查看更详细信息;推送分支就是把所有本地提交推送到远程库,推送时要指定本地分支,通过使用 git push 远程库名称 本地分支名称 命令。
(11)多人协作时,另一个人clone命令将远程库clone到本地,但此时只能看到master分支,如果要创建远程分支到本地,需要使用命令 git checkout -b branch-name origin/branch-name,这样就可以把本地的修改推送到远端分支上;如果另一个人向 origin/dev 推送了他的提交,你做了同样的修改也想推送,推送会失败,这时使用 git pull 将最新提交从 origin/dev 上抓下来(如果失败,说明本地分支没有和远端分支建立连接,使用 git branch --set-upstream-to=origin/branch-name branch-name),pull成功之后手动解决冲突(选择要提交的最终内容),在commit之后再push即可。
(12)当我们使用多个分支之后,再查看历史会有点混乱,通过 git log 查看,Git会使用(HEAD -> master) 和(origin/master) 标识当前分支HEAD和远程origin的位置;当我们经过push和pull操作发现分支混乱时,使用 git rebase 命令可以将原本的分叉变成一条直线,更便于我们查看历史提交。
【注:只对尚未推送或分享给别人的本地修改执行 rebase 操作清理历史;从不对已推送至别处的提交执行rebase操作。】
5、标签管理
(1)通过在版本库中打一个标签(tag),唯一确定了一个打标签的版本,标签是不能移动的,它是版本库的一个快照,便于我们查找某些重要的版本。
(2)Git中打标签非常简单,只需要转到要打标签的分支,使用 git tag 标签名 在分支处打上标签,可以使用命令 git tag 查看所有标签名(按字母顺序列出);如果有的时候忘了打标签,可以通过 git log 找到历史提交的 commit id, 然后使用 git tag 标签名 commit-id 即可。
(3)使用 git show 标签名 查看标签信息,也可以创建带有说明的标签,使用 -a 参数指定标签名,-m 参数指定说明文字,如 git tag -a tagname -m 说明文字 commit-id 。
【注:标签总是和某个cmmit挂钩的,如果这个commit既出现在master分支,又出现在dev分支,那么两个分支都可以看到这个标签。】
(4)如果标签打错了,可以使用 git tag -d 标签名 命令删除,创建的标签只存储在本地,不会推送到远程;如果要推送某个标签到远程,使用命令 git push origin 标签名 ,或者一次性推送全部标签到远程 git push origin --tags ;如果标签已经推送到远程,要删除的话先从本地删除,使用命令 git tag -d 标签名 ,然后从远程删除 git push origin :refs/tags/标签名。