分支策略
在实际开发中,我们应该按照几个基本原则进行分支管理:
首先,master
分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;
那在哪里干活呢?
干活都在dev分支上,也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master
上,在master
分支发布1.0版本;
每个人都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了。
所以,团队合作的分支看起来就像这样:
bug分支
假如我们现在正在dev2分支上进行开发,开发到一半,突然发现master分支上面有bug,需要解决。
在Git中,每个bug都可以通过一个新的临时分支来修复,修复后,合并分支,然后将临时分支删除。
可现在dev2的代码在工作区中开发了一半,还无法提交,怎么办?例如:
$ git branch
* dev2
master
$ cat ReadMe
hello bit
hello git
hello world
hello version1
hello version2
hello version3
write bbb for new branch
a,b,c,d
i am coding
$ git status
On branch dev2
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: ReadMe
no changes added to commit (use "git add" and/or "git commit -a")
Git提供了git stash
命令,可以将当前的工作区信息进行储藏,被储藏的内容可以在将来某个时间恢复出来。
$ git stash
Saved working directory and index state WIP on dev2: 41b892f modify ReadMe
$ git status
On branch dev2
nothing to commit, working tree clean
用git status
查看工作区,就是干净的(除非有没有被Git管理的文件),因此可以放心地创建分支来修复bug。
储藏dev2工作区之后,由于我们要基于master分支修复bug,所以需要切回master分支,再新建临时分支来修复bug,示例如下:
$ git checkout master # 切回master
Switched to branch'master'
$ git checkout -b fix_bug # 新建并切换到fix_bug分支
Switched to a new branch 'fix_bug'
$ vim ReadMe
$ cat ReadMe
hello git
hello world
hello version1
hello version2
hello version3
write bbb for new branch
a,b,c,d,e # 修复bug---忘记写e
$ git add ReadMe # 重新add,commit
$ git commit -m"fix bug"
[fix_bug cb6c041] fix bug
1 file changed, 1 insertion(+), 1 deletion(-)
修复完成后,切换到master分支,并完成合并,最后删除fix_bug分支:
$ git checkout master
Switched to branch'master'
$ git merge --no-ff -m"merge fix_bug branch" fix_bug
Merge made by the'recursive' strategy.
ReadMe | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
$ cat ReadMe
hello git
hello world
hello version1
hello version2
hello version3
write bbb for new branch
a,b,c,d
$ git branch -d fix_bug
Deleted branch fix_bug (was 4bb6c04).
至此,bug的修复工作已经做完了,我们还要继续回到dev2分支进行开发。切换回dev2分支:
$ git checkout dev2
Switched to branch 'dev2'
$ git status
On branch dev2
nothing to commit, working tree clean
工作区是干净的,刚才的工作现场存到哪去了?用git stash list
命令看看:
$ git stash list
stash@{0}: WIP on dev2: 41b892f modify ReadMe
工作现场还在,Git把stash内容存在某个地方了,但是需要恢复一下,如何恢复现场呢?我们可以使用git stash pop
命令,恢复的同时会把stash也删了,示例如下:
$ git stash pop
On branch dev2
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: ReadMe
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (4f87325b9536837b5efd26196776ae3724c2)
再次查看的时候,我们已经发现已经没有现场可以恢复了
$ git stash list
$
另外,恢复现场也可以采用git stash apply
恢复,但是恢复后stash内容并不删除,你需要用git stash drop
来删除;
你可以多次stash,恢复的时候,先用git stash list
查看,然后恢复指定的stash,用命令git stash apply stash@{0},这部分请同学们自行使用。
恢复完代码之后我们便可以继续完成开发,开发完成后便可以进行提交,例如:
$ cat ReadMe
hello bit
hello world
hello git
hello world
hello version1
hello version2
hello version3
write bbb for new branch
a,b,c,d
$ git add ReadMe
$ git commit -m"modify ReadMe"
[dev2 6c0412d] modify ReadMe
1 file changed, 1 insertion(+)
但我们注意到了,修复bug的内容,并没有在dev2上显示。此时的状态图为:
Master分支目前最新提交,是领先于新建dev2时基于的master分支的提交的,所以我们在dev2中自然看不见修复bug的相关提交。
那么,正常情况下我们切回master分支直接合并即可,这样做是有一定风险的。
是因为在合并分支时可能会有冲突,而代码冲突需要我们手动解决(在master上解决)。我们无法保证冲突会一次性解决(尤其是大项目中成千上万的代码量),解决难免会出错,导致出错代码合并到master
分支上
解决这个问题的一个好的建议就是:最好在自己的分支上合并master,再让master去合并dev,这样做的目的是有冲突可以在本地分支解决并进行测试,而不影响master。此时的状态为:
对应的实操演示如下,要说明的是,以下演示为了方便理解,使用了 --no-ff
,但上述图示是采用fast-forward
模式后得出的,主要是为了方便解释问题。
$ git branch
* dev2
master
$ git merge master
Auto-merging ReadMe
CONFLICT (content): Merge conflict in ReadMe
Automatic merge failed; fix conflicts and then commit the result.
$ cat ReadMe
hello git
hello world
hello version1
hello version2
hello version3
write bbb for new branch
<<<<<<< HEAD
a,b,c,d
i am coding...
=======
a,b,c,d,e
>>>>>>> master
$ vim ReadMe
#解决冲突重新提交
$ git add ReadMe
$ git commit -m"fix conflict"
[dev2 5d0c4e8] fix conflict
1 file changed, 1 insertion(+)
$ git merge master
Updating 4d7f9d9..5d0c4e8
Fast-forward
ReadMe | 1 +
1 file changed, 1 insertion(+)
$ git status
On branch dev2
nothing to commit, working tree clean
# 切换回master
$ git checkout master
Switched to branch'master'
$ git merge dev2
Updating 4d7f9d9..5d0c4e8
Fast-forward
ReadMe | 1 +
1 file changed, 1 insertion(+)
$ git status
On branch master
nothing to commit, working tree clean
# 删除dev2分支
$ git branch -d dev2
Deleted branch dev2 (was 4d7d9f).
删除临时分支
添加一个新功能时,你肯定不希望因为一些实验性质的代码,把主分支搞乱了,所以,每添加一个新功能,最好新建一个feature分支,我们可以将其称之为feature分支,在上面开发,完成后,合并,最后,删除该feature
分支。
可是,虽然今天正在某个feature分支上开发了一半,被产品经理突然叫停,说是要使用新的开发架构。我们正在这个feature分支还没完成,突然被喊停,这时候使用传统的git branch -d命令删除分支的方法是不行的。演示如下:
$ git branch
* dev3
master
$ git branch -d dev3
error: The branch 'dev3' is not fully merged.
If you are sure you want to delete it, run 'git branch -D dev3'.
直接使用传统的删除分支的方法不行,按照提示,有如下方式:git branch -D dev3
$ git branch -D dev3
Deleted branch dev3 (was f78250b).