git
的人,只会用
add
,
commit
,
push
,
pull
这几个命令,包括恢复版本之类的,多半也会暴力的删除整个项目,再从新
clone
干净的代码。虽然说也能工做了,可是无疑没有领会到
git
的精华。 这篇文章主要说明如何使用分支使咱们的开发工做更加顺滑,如何让分支成为你平常工做流不可缺失的一部分。
git branch //列出全部的分支
git branch <branch> //建立名为<branch>的分支,可是不会切换过去
git branch -d <branch> //删除指定分支,这是一个“安全”操做,git会阻止你删除包含未合并更改的分支。
git branch -D <branch> //强制删除分支
git branch -m <branch> //从新命名当前分支
复制代码
在平常开发中,不管是修复一个bug或者添加一个功能,咱们都应该新建一个分支来封装咱们的修改。这样能够保证咱们不稳定的代码永远不会提交到主代码分支上。git
下面咱们具体来看在执行分支有关的操做,分支的变化:算法
分支只是指向提交的指针,理解这一点很重要,当你建立新分支,实际上只是建立了一个新的指针,仓库自己不会受到影响,一开始你的仓库只有一条分支:安全
git branch new-feature
复制代码
git chekcout new-feature
切换到
new-feature
分支,而后再使用
git add
,
git commit
。
假如你已经开发完了new-feature,而且已经commit代码了, 你就能够自由删除这个分支了。bash
git branch -d new-feature
复制代码
若是分支尚未合入master,会报下面的错误:ui
error: The branch 'new feature' is not fully merged.
If you are sure you want to delete it, run 'git branch -D crazy-experiment'.
复制代码
这时候你能够合并分支(下面会说如何合并分支),若是你真的肯定了要删除分支,能够用-D
执行强制删除:this
git branch -D new-feature
复制代码
git checkout
命令容许你切换到用git branch
建立的分支。切换分支会更新当前工做目录中的文件,还能够用git log
查看当前分支的历史。 用法spa
git checkout <existing-branch> //切换到一个已有分支上
git checkout -b <new-branch> // -b 标记 能够方便让你先建立一个新的new-branch,再直接切换过去
git checkout -b <new-branch> <existing-branch> //在已有的分支上建立分支,原来的分支使新分支的基
复制代码
git branch
和git chekout
是一对好基友,你可使用git checkout
在不一样的功能分支或者bug分支之间切换,而不产生相互影响。3d
关于分离的HEAD(detached HEAD) 通常咱们有时候须要恢复到之前commit的版本上查看原来的一些文件时,咱们会git checkout commit的hash码或者tag
, 这时候会提醒咱们进入了detached HEAD
。指针
git checkout 2
,咱们的代码回到2的状态了,一般git会显示下面的warning:
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:
git checkout -b new_branch_name
HEAD is now at 2
复制代码
若是在这种状态下开发,而后又add
,commit
,没有分支可让你回到以前的状态。当你不可避免的须要checkout
到另一个分支,想再回来就是不可能的了,由于像图中的那个X
状态,根本就不在分支上,你将不再能引用你以前添加的代码了。code
重点:永远记得在开发分支上开发,不要在分离的HEAD上开发,这能够确保你能够引用到你的新提交,若是只是checkout
到之前看看无所谓,若是真的须要在之前的版本上添加什么代码,记得上面warning 中的git checkout -b new_branch_name
,是本身处于一个确切的分支中。
远离detached HEAD
,咱们来看实际上git分支流程是什么样子的:
git branch new-feature
git checkout new-feature
复制代码
接下来咱们作一些代码改动,提交:
git add <some file>
git commit -m "A new feature"
##你接着改代码,接着提交不少次
复制代码
当你git log
会显示每一次的commit, 和master分支彻底独立,当你checkout
到master分支去,再git log
,会发现new-feature
分支的提交都不在,这就是不影响master分支。 这时候,你能够考虑合并new-feature或者在master分支上开始别的工做。
合并是git
将被fork
的历史放回到一块儿的方式。 git merge
命令容许你将 git branch
建立的多条分支合并成一个。 用法
git merge <branch> //将指定分支并入当前分支
git merge --no-ff <branch> //将指定分支并入当前分支,但 老是 生成一个合并提交(即便是快速向前合并)。这能够用来记录仓库中发生的全部合并。
复制代码
一旦在新分支上完成开发,咱们须要把新分支的提交合并到主分支,git会根据目前分支之间的结构信息,选择不一样的算法来完成合并:
快速向前合并 当new-feature的分支与原有的master分支呈现线性关系时,执行快速向前合并,git将当前的HEAD指针快速移到目标分支的顶端,master分支也就具备了new-feature分支的历史了,如图:
来看一个快速向前合并的实例:
# 开始新功能
git checkout -b new-feature master
# 编辑文件
git add <file>
git commit -m "开始新功能"
# 编辑文件
git add <file>
git commit -m "完成功能"
# 合并new-feature分支
git checkout master
git merge new-feature
git branch -d new-feature
复制代码
对于合做开发的人少的项目,这是一种主要的工做流,合做开发的人多的话,主master
分支常常都会有新提交,若是你的new-feature
耗时比较久,再提交时,master
分支可能已通过去几个版本了,这时候就须要下面的三路合并了。
三路合并 可是若是master分支在new-feature分离后,又有了新的提交,即开始分叉了,git只能执行三路合并,三路合并使用一个专门的提交来合并两个分支的历史。
解决冲突 若是两个分支对同一个文件的同一部分均有修改时,git将没法判断应该使用哪一个,这时候合并提交会中止,须要你手动解决这些冲突。你可使用git status
来查看哪里存在冲突,不少时候我都会在目录下执行grep -rn HEAD
来查看哪些文件里有这个标记,有这个标记的地方都是有冲突的。
当修改完全部的冲突后,git add
全部的冲突文件,运行git commit
生成一个合并提交,这和提交一个普通快照的流程相同。提交冲突只会存在在三路合并中,快速向前合并中不可能出现针对同一文件同一部分的不同修改。
下面实例来看看三路合并是怎么产生的:
# 开始新功能
git checkout -b new-feature master
# 编辑文件
git add <file>
git commit -m "开始新功能"
# 编辑文件
git add <file>
git commit -m "完成功能"
# 在master分支上开发
git checkout master
# 编辑文件
git add <file>
git commit -m "在master上添加了一些极其稳定的功能"
# 合并new-feature分支
git merge new-feature
git branch -d new-feature
复制代码
这时候,merge会中止,由于没法将 master 直接移动到 new-feature。因此须要你手动合并冲突后再提交。
git merge
会产生合并提交,有的人会选择使用git rebase
来合并以确保一个干净的提交历史。关于这两个的区别,我会另写一篇介绍。