多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
### 理解分支 一开始的时候,`master`分支是一条线,Git用`master`指向最新的提交,再用`HEAD`指向`master`,就能确定当前分支,以及当前分支的提交点: ![git-br-initial](http://www.liaoxuefeng.com/files/attachments/919022325462368/0) 每次提交,`master`分支都会向前移动一步,这样,随着你不断提交,`master`分支的线也越来越长。 当我们创建新的分支,例如`dev`时,Git新建了一个指针叫`dev`,指向`master`相同的提交,再把`HEAD`指向`dev`,就表示当前分支在`dev`上: ![git-br-create](http://www.liaoxuefeng.com/files/attachments/919022363210080/0) 你看,Git创建一个分支很快,因为除了增加一个`dev`指针,改改`HEAD`的指向,工作区的文件都没有任何变化! 不过,从现在开始,对工作区的修改和提交就是针对`dev`分支了,比如新提交一次后,`dev`指针往前移动一步,而`master`指针不变: ![git-br-dev-fd](http://www.liaoxuefeng.com/files/attachments/919022387118368/0) 假如我们在`dev`上的工作完成了,就可以把`dev`合并到`master`上。Git怎么合并呢?最简单的方法,就是直接把`master`指向`dev`的当前提交,就完成了合并: ![git-br-ff-merge](http://www.liaoxuefeng.com/files/attachments/919022412005504/0) 所以Git合并分支也很快!就改改指针,工作区内容也不变! 合并完分支后,甚至可以删除`dev`分支。删除`dev`分支就是把`dev`指针给删掉,删掉后,我们就剩下了一条`master`分支: ![git-br-rm](http://www.liaoxuefeng.com/files/attachments/919022479428512/0) 真是太神奇了,你看得出来有些提交是通过分支完成的吗? ### 分支命令 * 查看分支:`git branch` * 创建分支:`git branch <name>` * 切换分支:`git checkout <name>` * 创建+切换分支:`git checkout -b <name>` * 合并某分支到当前分支:`git merge <name>` * 删除分支:`git branch -d <name>` ### 冲突处理 准备新的`feature1`分支,继续我们的新分支开发: ~~~ $ git checkout -b feature1 Switched to a new branch 'feature1' ~~~ 修改`readme.txt`最后一行,改为: ~~~ Creating a new branch is quick AND simple. ~~~ 在`feature1`分支上提交: ~~~ $ git add readme.txt $ git commit -m "AND simple" [feature1 14096d0] AND simple 1 file changed, 1 insertion(+), 1 deletion(-) ~~~ 切换到`master`分支: ~~~ $ git checkout master Switched to branch 'master' Your branch is ahead of 'origin/master' by 1 commit. (use "git push" to publish your local commits) ~~~ Git还会自动提示我们当前`master`分支比远程的`master`分支要超前1个提交。 在`master`分支上把`readme.txt`文件的最后一行改为: ~~~ Creating a new branch is quick & simple. ~~~ 提交: ~~~ $ git add readme.txt $ git commit -m "& simple" [master 5dc6824] & simple 1 file changed, 1 insertion(+), 1 deletion(-) ~~~ 现在,`master`分支和`feature1`分支各自都分别有新的提交,变成了这样: ![git-br-feature1](http://www.liaoxuefeng.com/files/attachments/919023000423040/0) 这种情况下,Git无法执行“快速合并”,只能试图把各自的修改合并起来,但这种合并就可能会有冲突,我们试试看: ~~~ $ git merge feature1 Auto-merging readme.txt CONFLICT (content): Merge conflict in readme.txt Automatic merge failed; fix conflicts and then commit the result. ~~~ 果然冲突了!Git告诉我们,`readme.txt`文件存在冲突,必须手动解决冲突后再提交。`git status`也可以告诉我们冲突的文件: ~~~ $ git status On branch master Your branch is ahead of 'origin/master' by 2 commits. (use "git push" to publish your local commits) You have unmerged paths. (fix conflicts and run "git commit") (use "git merge --abort" to abort the merge) Unmerged paths: (use "git add <file>..." to mark resolution) both modified: readme.txt no changes added to commit (use "git add" and/or "git commit -a") ~~~ 我们可以直接查看readme.txt的内容: ~~~ Git is a distributed version control system. Git is free software distributed under the GPL. Git has a mutable index called stage. Git tracks changes of files. <<<<<<< HEAD Creating a new branch is quick & simple. ======= Creating a new branch is quick AND simple. >>>>>>> feature1 ~~~ Git用`<<<<<<<`,`=======`,`>>>>>>>`标记出不同分支的内容,我们修改如下后保存: ~~~ Creating a new branch is quick and simple. ~~~ 再提交: ~~~ $ git add readme.txt $ git commit -m "conflict fixed" [master cf810e4] conflict fixed ~~~ 现在,`master`分支和`feature1`分支变成了下图所示: ![git-br-conflict-merged](http://www.liaoxuefeng.com/files/attachments/919023031831104/0) ### 不使用fast forward 模式合并分支 通常,合并分支时,如果可能,Git会用`Fast forward`模式,但这种模式下,删除分支后,会丢掉分支信息。 如果要强制禁用`Fast forward`模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息。 下面我们实战一下`--no-ff`方式的`git merge`: 首先,仍然创建并切换`dev`分支: ~~~ $ git checkout -b dev Switched to a new branch 'dev' ~~~ 修改readme.txt文件,并提交一个新的commit: ~~~ $ git add readme.txt $ git commit -m "add merge" [dev f52c633] add merge 1 file changed, 1 insertion(+) ~~~ 现在,我们切换回`master`: ~~~ $ git checkout master Switched to branch 'master' ~~~ 准备合并`dev`分支,请注意`--no-ff`参数,表示禁用`Fast forward`: ~~~ $ git merge --no-ff -m "merge with no-ff" dev Merge made by the 'recursive' strategy. readme.txt | 1 + 1 file changed, 1 insertion(+) ~~~ 因为本次合并要创建一个新的commit,所以加上`-m`参数,把commit描述写进去。 合并后,我们用`git log`看看分支历史: ~~~ $ git log --graph --pretty=oneline --abbrev-commit * e1e9c68 (HEAD -> master) merge with no-ff |\ | * f52c633 (dev) add merge |/ * cf810e4 conflict fixed ... ~~~ 可以看到,不使用`Fast forward`模式,merge后就像这样: ![git-no-ff-mode](https://www.liaoxuefeng.com/files/attachments/919023225142304/0)